diff --git a/.cproject b/.cproject
index bcf690995..617aa3795 100644
--- a/.cproject
+++ b/.cproject
@@ -854,6 +854,14 @@
 				true
 				true
 			
+			
+				make
+				-j4
+				testSmartStereoProjectionPoseFactor.run
+				true
+				true
+				true
+			
 			
 				make
 				-j5
@@ -2953,6 +2961,14 @@
 				true
 				true
 			
+			
+				make
+				-j4
+				testRangeFactor.run
+				true
+				true
+				true
+			
 			
 				make
 				-j2
diff --git a/.gitignore b/.gitignore
index 60633adaf..f3f1efd5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@
 /examples/Data/dubrovnik-3-7-pre-rewritten.txt
 /examples/Data/pose2example-rewritten.txt
 /examples/Data/pose3example-rewritten.txt
+*.txt.user
+*.txt.user.6d59f0c
diff --git a/gtsam.h b/gtsam.h
index 96d51117a..67b3f2888 100644
--- a/gtsam.h
+++ b/gtsam.h
@@ -758,10 +758,6 @@ class CalibratedCamera {
   gtsam::CalibratedCamera retract(const Vector& d) const;
   Vector localCoordinates(const gtsam::CalibratedCamera& T2) const;
 
-  // Group
-  gtsam::CalibratedCamera compose(const gtsam::CalibratedCamera& c) const;
-  gtsam::CalibratedCamera inverse() const;
-
   // Action on Point3
   gtsam::Point2 project(const gtsam::Point3& point) const;
   static gtsam::Point2 project_to_camera(const gtsam::Point3& cameraPoint);
@@ -2198,10 +2194,14 @@ typedef gtsam::RangeFactor RangeFactorPosePoint2;
 typedef gtsam::RangeFactor RangeFactorPosePoint3;
 typedef gtsam::RangeFactor RangeFactorPose2;
 typedef gtsam::RangeFactor RangeFactorPose3;
-typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint;
-typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint;
-typedef gtsam::RangeFactor RangeFactorCalibratedCamera;
-typedef gtsam::RangeFactor RangeFactorSimpleCamera;
+
+// Commented out by Frank Dec 2014: not poses!
+// If needed, we need a RangeFactor that takes a camera, extracts the pose
+// Should be easy with Expressions
+//typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint;
+//typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint;
+//typedef gtsam::RangeFactor RangeFactorCalibratedCamera;
+//typedef gtsam::RangeFactor RangeFactorSimpleCamera;
 
 
 #include 
diff --git a/gtsam/base/Matrix.h b/gtsam/base/Matrix.h
index 9c273f78c..3ecfcf8fa 100644
--- a/gtsam/base/Matrix.h
+++ b/gtsam/base/Matrix.h
@@ -37,36 +37,36 @@ namespace gtsam {
 typedef Eigen::MatrixXd Matrix;
 typedef Eigen::Matrix MatrixRowMajor;
 
-typedef Eigen::Matrix2d Matrix2;
-typedef Eigen::Matrix3d Matrix3;
-typedef Eigen::Matrix4d Matrix4;
-typedef Eigen::Matrix Matrix5;
-typedef Eigen::Matrix Matrix6;
+// Create handy typedefs and constants for square-size matrices
+// MatrixMN, MatrixN = MatrixNN, I_NxN, and Z_NxN, for M,N=1..9
+#define GTSAM_MAKE_TYPEDEFS(SIZE, SUFFIX)   \
+typedef Eigen::Matrix Matrix##SUFFIX;  \
+typedef Eigen::Matrix Matrix1##SUFFIX;  \
+typedef Eigen::Matrix Matrix2##SUFFIX;  \
+typedef Eigen::Matrix Matrix3##SUFFIX;  \
+typedef Eigen::Matrix Matrix4##SUFFIX;  \
+typedef Eigen::Matrix Matrix5##SUFFIX;  \
+typedef Eigen::Matrix Matrix6##SUFFIX;  \
+typedef Eigen::Matrix Matrix7##SUFFIX;  \
+typedef Eigen::Matrix Matrix8##SUFFIX;  \
+typedef Eigen::Matrix Matrix9##SUFFIX;  \
+static const Eigen::MatrixBase::IdentityReturnType I_##SUFFIX##x##SUFFIX = Matrix##SUFFIX::Identity(); \
+static const Eigen::MatrixBase::ConstantReturnType Z_##SUFFIX##x##SUFFIX = Matrix##SUFFIX::Zero();
 
-typedef Eigen::Matrix Matrix23;
-typedef Eigen::Matrix Matrix24;
-typedef Eigen::Matrix Matrix25;
-typedef Eigen::Matrix Matrix26;
-typedef Eigen::Matrix Matrix27;
-typedef Eigen::Matrix Matrix28;
-typedef Eigen::Matrix Matrix29;
-
-typedef Eigen::Matrix Matrix32;
-typedef Eigen::Matrix Matrix34;
-typedef Eigen::Matrix Matrix35;
-typedef Eigen::Matrix Matrix36;
-typedef Eigen::Matrix Matrix37;
-typedef Eigen::Matrix Matrix38;
-typedef Eigen::Matrix Matrix39;
+GTSAM_MAKE_TYPEDEFS(1,1);
+GTSAM_MAKE_TYPEDEFS(2,2);
+GTSAM_MAKE_TYPEDEFS(3,3);
+GTSAM_MAKE_TYPEDEFS(4,4);
+GTSAM_MAKE_TYPEDEFS(5,5);
+GTSAM_MAKE_TYPEDEFS(6,6);
+GTSAM_MAKE_TYPEDEFS(7,7);
+GTSAM_MAKE_TYPEDEFS(8,8);
+GTSAM_MAKE_TYPEDEFS(9,9);
 
 // Matrix expressions for accessing parts of matrices
 typedef Eigen::Block SubMatrix;
 typedef Eigen::Block ConstSubMatrix;
 
-// Two very commonly used matrices:
-const Matrix3 Z_3x3 = Matrix3::Zero();
-const Matrix3 I_3x3 = Matrix3::Identity();
-
 // Matlab-like syntax
 
 /**
diff --git a/gtsam/base/OptionalJacobian.h b/gtsam/base/OptionalJacobian.h
new file mode 100644
index 000000000..5651816ba
--- /dev/null
+++ b/gtsam/base/OptionalJacobian.h
@@ -0,0 +1,115 @@
+/* ----------------------------------------------------------------------------
+
+ * GTSAM Copyright 2010, Georgia Tech Research Corporation, 
+ * Atlanta, Georgia 30332-0415
+ * All Rights Reserved
+ * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
+
+ * See LICENSE for the license information
+
+ * -------------------------------------------------------------------------- */
+
+/**
+ * @file    OptionalJacobian.h
+ * @brief   Special class for optional Matrix arguments
+ * @author  Frank Dellaert
+ * @author  Natesh Srinivasan
+ * @date    Nov 28, 2014
+ */
+
+#pragma once
+
+#include 
+
+#ifndef OPTIONALJACOBIAN_NOBOOST
+#include 
+#endif
+
+namespace gtsam {
+
+/**
+ * OptionalJacobian is an Eigen::Ref like class that can take be constructed using
+ * either a fixed size or dynamic Eigen matrix. In the latter case, the dynamic
+ * matrix will be resized. Finally, there is a constructor that takes
+ * boost::none, the default constructor acts like boost::none, and
+ * boost::optional is also supported for backwards compatibility.
+ */
+template
+class OptionalJacobian {
+
+public:
+
+  /// Fixed size type
+  typedef Eigen::Matrix Fixed;
+
+private:
+
+  Eigen::Map map_; /// View on constructor argument, if given
+
+  // Trick from http://eigen.tuxfamily.org/dox/group__TutorialMapClass.html
+  // uses "placement new" to make map_ usurp the memory of the fixed size matrix
+  void usurp(double* data) {
+    new (&map_) Eigen::Map(data);
+  }
+
+public:
+
+  /// Default constructor acts like boost::none
+  OptionalJacobian() :
+      map_(NULL) {
+  }
+
+  /// Constructor that will usurp data of a fixed-size matrix
+  OptionalJacobian(Fixed& fixed) :
+      map_(NULL) {
+    usurp(fixed.data());
+  }
+
+  /// Constructor that will usurp data of a fixed-size matrix, pointer version
+  OptionalJacobian(Fixed* fixedPtr) :
+      map_(NULL) {
+    if (fixedPtr)
+      usurp(fixedPtr->data());
+  }
+
+  /// Constructor that will resize a dynamic matrix (unless already correct)
+  OptionalJacobian(Eigen::MatrixXd& dynamic) :
+      map_(NULL) {
+    dynamic.resize(Rows, Cols); // no malloc if correct size
+    usurp(dynamic.data());
+  }
+
+#ifndef OPTIONALJACOBIAN_NOBOOST
+
+  /// Constructor with boost::none just makes empty
+  OptionalJacobian(boost::none_t none) :
+      map_(NULL) {
+  }
+
+  /// Constructor compatible with old-style derivatives
+  OptionalJacobian(const boost::optional optional) :
+      map_(NULL) {
+    if (optional) {
+      optional->resize(Rows, Cols);
+      usurp(optional->data());
+    }
+  }
+
+#endif
+
+  /// Return true is allocated, false if default constructor was used
+  operator bool() const {
+    return map_.data();
+  }
+
+  /// De-reference, like boost optional
+  Eigen::Map& operator*() {
+    return map_;
+  }
+
+  /// TODO: operator->()
+  Eigen::Map* operator->(){ return &map_; }
+};
+
+} // namespace gtsam
+
diff --git a/gtsam/base/tests/testOptionalJacobian.cpp b/gtsam/base/tests/testOptionalJacobian.cpp
new file mode 100644
index 000000000..6584c82d1
--- /dev/null
+++ b/gtsam/base/tests/testOptionalJacobian.cpp
@@ -0,0 +1,105 @@
+/* ----------------------------------------------------------------------------
+
+ * GTSAM Copyright 2010, Georgia Tech Research Corporation, 
+ * Atlanta, Georgia 30332-0415
+ * All Rights Reserved
+ * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
+
+ * See LICENSE for the license information
+
+ * -------------------------------------------------------------------------- */
+
+/**
+ * @file    testOptionalJacobian.cpp
+ * @brief   Unit test for OptionalJacobian
+ * @author  Frank Dellaert
+ * @date    Nov 28, 2014
+ **/
+
+#include 
+#include 
+#include 
+
+using namespace std;
+using namespace gtsam;
+
+//******************************************************************************
+TEST( OptionalJacobian, Constructors ) {
+  Matrix23 fixed;
+
+  OptionalJacobian<2, 3> H1;
+  EXPECT(!H1);
+
+  OptionalJacobian<2, 3> H2(fixed);
+  EXPECT(H2);
+
+  OptionalJacobian<2, 3> H3(&fixed);
+  EXPECT(H3);
+
+  Matrix dynamic;
+  OptionalJacobian<2, 3> H4(dynamic);
+  EXPECT(H4);
+
+  OptionalJacobian<2, 3> H5(boost::none);
+  EXPECT(!H5);
+
+  boost::optional optional(dynamic);
+  OptionalJacobian<2, 3> H6(optional);
+  EXPECT(H6);
+}
+
+//******************************************************************************
+void test(OptionalJacobian<2, 3> H = boost::none) {
+  if (H)
+    *H = Matrix23::Zero();
+}
+
+void testPtr(Matrix23* H = NULL) {
+  if (H)
+    *H = Matrix23::Zero();
+}
+
+TEST( OptionalJacobian, Ref2) {
+
+  Matrix expected;
+  expected = Matrix23::Zero();
+
+  // Default argument does nothing
+  test();
+
+  // Fixed size, no copy
+  Matrix23 fixed1;
+  fixed1.setOnes();
+  test(fixed1);
+  EXPECT(assert_equal(expected,fixed1));
+
+  // Fixed size, no copy, pointer style
+  Matrix23 fixed2;
+  fixed2.setOnes();
+  test(&fixed2);
+  EXPECT(assert_equal(expected,fixed2));
+
+  // Empty is no longer a sign we don't want a matrix, we want it resized
+  Matrix dynamic0;
+  test(dynamic0);
+  EXPECT(assert_equal(expected,dynamic0));
+
+  // Dynamic wrong size
+  Matrix dynamic1(3, 5);
+  dynamic1.setOnes();
+  test(dynamic1);
+  EXPECT(assert_equal(expected,dynamic0));
+
+  // Dynamic right size
+  Matrix dynamic2(2, 5);
+  dynamic2.setOnes();
+  test(dynamic2);
+  EXPECT(assert_equal(dynamic2,dynamic0));
+}
+
+//******************************************************************************
+int main() {
+  TestResult tr;
+  return TestRegistry::runAllTests(tr);
+}
+//******************************************************************************
diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp
index 8ff728d26..ccd061d7c 100644
--- a/gtsam/geometry/Cal3Bundler.cpp
+++ b/gtsam/geometry/Cal3Bundler.cpp
@@ -34,15 +34,17 @@ Cal3Bundler::Cal3Bundler(double f, double k1, double k2, double u0, double v0) :
 }
 
 /* ************************************************************************* */
-Matrix Cal3Bundler::K() const {
+Matrix3 Cal3Bundler::K() const {
   Matrix3 K;
   K << f_, 0, u0_, 0, f_, v0_, 0, 0, 1;
   return K;
 }
 
 /* ************************************************************************* */
-Vector Cal3Bundler::k() const {
-  return (Vector(4) << k1_, k2_, 0, 0).finished();
+Vector4 Cal3Bundler::k() const {
+  Vector4 rvalue_;
+  rvalue_ << k1_, k2_, 0, 0;
+  return rvalue_;
 }
 
 /* ************************************************************************* */
@@ -64,21 +66,9 @@ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const {
   return true;
 }
 
-/* ************************************************************************* */
-Point2 Cal3Bundler::uncalibrate(const Point2& p) const {
-  //  r = x^2 + y^2;
-  //  g = (1 + k(1)*r + k(2)*r^2);
-  //  pi(:,i) = g * pn(:,i)
-  const double x = p.x(), y = p.y();
-  const double r = x * x + y * y;
-  const double g = 1. + (k1_ + k2_ * r) * r;
-  const double u = g * x, v = g * y;
-  return Point2(u0_ + f_ * u, v0_ + f_ * v);
-}
-
 /* ************************************************************************* */
 Point2 Cal3Bundler::uncalibrate(const Point2& p, //
-    boost::optional Dcal, boost::optional Dp) const {
+    OptionalJacobian<2, 3> Dcal, OptionalJacobian<2, 2> Dp) const {
   //  r = x^2 + y^2;
   //  g = (1 + k(1)*r + k(2)*r^2);
   //  pi(:,i) = g * pn(:,i)
@@ -103,35 +93,6 @@ Point2 Cal3Bundler::uncalibrate(const Point2& p, //
   return Point2(u0_ + f_ * u, v0_ + f_ * v);
 }
 
-/* ************************************************************************* */
-Point2 Cal3Bundler::uncalibrate(const Point2& p, //
-    boost::optional Dcal, boost::optional Dp) const {
-  //  r = x^2 + y^2;
-  //  g = (1 + k(1)*r + k(2)*r^2);
-  //  pi(:,i) = g * pn(:,i)
-  const double x = p.x(), y = p.y();
-  const double r = x * x + y * y;
-  const double g = 1. + (k1_ + k2_ * r) * r;
-  const double u = g * x, v = g * y;
-
-  // Derivatives make use of intermediate variables above
-  if (Dcal) {
-    double rx = r * x, ry = r * y;
-    Dcal->resize(2, 3);
-    *Dcal << u, f_ * rx, f_ * r * rx, v, f_ * ry, f_ * r * ry;
-  }
-
-  if (Dp) {
-    const double a = 2. * (k1_ + 2. * k2_ * r);
-    const double axx = a * x * x, axy = a * x * y, ayy = a * y * y;
-    Dp->resize(2,2);
-    *Dp << g + axx, axy, axy, g + ayy;
-    *Dp *= f_;
-  }
-
-  return Point2(u0_ + f_ * u, v0_ + f_ * v);
-}
-
 /* ************************************************************************* */
 Point2 Cal3Bundler::calibrate(const Point2& pi, const double tol) const {
   // Copied from Cal3DS2 :-(
@@ -161,24 +122,25 @@ Point2 Cal3Bundler::calibrate(const Point2& pi, const double tol) const {
 }
 
 /* ************************************************************************* */
-Matrix Cal3Bundler::D2d_intrinsic(const Point2& p) const {
-  Matrix Dp;
+Matrix2 Cal3Bundler::D2d_intrinsic(const Point2& p) const {
+  Matrix2 Dp;
   uncalibrate(p, boost::none, Dp);
   return Dp;
 }
 
 /* ************************************************************************* */
-Matrix Cal3Bundler::D2d_calibration(const Point2& p) const {
-  Matrix Dcal;
+Matrix23 Cal3Bundler::D2d_calibration(const Point2& p) const {
+  Matrix23 Dcal;
   uncalibrate(p, Dcal, boost::none);
   return Dcal;
 }
 
 /* ************************************************************************* */
-Matrix Cal3Bundler::D2d_intrinsic_calibration(const Point2& p) const {
-  Matrix Dcal, Dp;
+Matrix25 Cal3Bundler::D2d_intrinsic_calibration(const Point2& p) const {
+  Matrix23 Dcal;
+  Matrix2 Dp;
   uncalibrate(p, Dcal, Dp);
-  Matrix H(2, 5);
+  Matrix25 H;
   H << Dp, Dcal;
   return H;
 }
diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h
index 4c77fdf23..fc1d63e10 100644
--- a/gtsam/geometry/Cal3Bundler.h
+++ b/gtsam/geometry/Cal3Bundler.h
@@ -69,8 +69,8 @@ public:
   /// @name Standard Interface
   /// @{
 
-  Matrix K() const; ///< Standard 3*3 calibration matrix
-  Vector k() const; ///< Radial distortion parameters (4 of them, 2 0)
+  Matrix3 K() const; ///< Standard 3*3 calibration matrix
+  Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0)
 
   Vector3 vector() const;
 
@@ -106,43 +106,27 @@ public:
 
 
   /**
-   * convert intrinsic coordinates xy to image coordinates uv
-   * @param p point in intrinsic coordinates
-   * @return point in image coordinates
-   */
-  Point2 uncalibrate(const Point2& p) const;
-
-  /**
-   * Version of uncalibrate with fixed derivatives
+   * @brief: convert intrinsic coordinates xy to image coordinates uv
+   * Version of uncalibrate with derivatives
    * @param p point in intrinsic coordinates
    * @param Dcal optional 2*3 Jacobian wrpt CalBundler parameters
    * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
    * @return point in image coordinates
    */
-  Point2 uncalibrate(const Point2& p, boost::optional Dcal,
-      boost::optional Dp) const;
-
-  /**
-   * Version of uncalibrate with dynamic derivatives
-   * @param p point in intrinsic coordinates
-   * @param Dcal optional 2*3 Jacobian wrpt CalBundler parameters
-   * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
-   * @return point in image coordinates
-   */
-  Point2 uncalibrate(const Point2& p, boost::optional Dcal,
-      boost::optional Dp) const;
+  Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 3> Dcal = boost::none,
+      OptionalJacobian<2, 2> Dp = boost::none) const;
 
   /// Conver a pixel coordinate to ideal coordinate
   Point2 calibrate(const Point2& pi, const double tol = 1e-5) const;
 
   /// @deprecated might be removed in next release, use uncalibrate
-  Matrix D2d_intrinsic(const Point2& p) const;
+  Matrix2 D2d_intrinsic(const Point2& p) const;
 
   /// @deprecated might be removed in next release, use uncalibrate
-  Matrix D2d_calibration(const Point2& p) const;
+  Matrix23 D2d_calibration(const Point2& p) const;
 
   /// @deprecated might be removed in next release, use uncalibrate
-  Matrix D2d_intrinsic_calibration(const Point2& p) const;
+  Matrix25 D2d_intrinsic_calibration(const Point2& p) const;
 
   /// @}
   /// @name Manifold
diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp
index 1105fecfb..cfbce2b28 100644
--- a/gtsam/geometry/Cal3DS2_Base.cpp
+++ b/gtsam/geometry/Cal3DS2_Base.cpp
@@ -28,8 +28,10 @@ Cal3DS2_Base::Cal3DS2_Base(const Vector &v):
     fx_(v[0]), fy_(v[1]), s_(v[2]), u0_(v[3]), v0_(v[4]), k1_(v[5]), k2_(v[6]), p1_(v[7]), p2_(v[8]){}
 
 /* ************************************************************************* */
-Matrix Cal3DS2_Base::K() const {
-  return (Matrix(3, 3) << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0).finished();
+Matrix3 Cal3DS2_Base::K() const {
+    Matrix3 K;
+    K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0;
+    return K;
 }
 
 /* ************************************************************************* */
@@ -39,7 +41,7 @@ Vector Cal3DS2_Base::vector() const {
 
 /* ************************************************************************* */
 void Cal3DS2_Base::print(const std::string& s_) const {
-  gtsam::print(K(), s_ + ".K");
+  gtsam::print((Matrix)K(), s_ + ".K");
   gtsam::print(Vector(k()), s_ + ".k");
 }
 
@@ -91,8 +93,7 @@ static Matrix2 D2dintrinsic(double x, double y, double rr,
 
 /* ************************************************************************* */
 Point2 Cal3DS2_Base::uncalibrate(const Point2& p,
-    boost::optional H1,
-    boost::optional H2) const {
+    OptionalJacobian<2,9> H1, OptionalJacobian<2,2> H2) const {
 
   //  rr = x^2 + y^2;
   //  g = (1 + k(1)*rr + k(2)*rr^2);
@@ -126,26 +127,6 @@ Point2 Cal3DS2_Base::uncalibrate(const Point2& p,
   return Point2(fx_ * pnx + s_ * pny + u0_, fy_ * pny + v0_);
 }
 
-/* ************************************************************************* */
-Point2 Cal3DS2_Base::uncalibrate(const Point2& p,
-    boost::optional H1,
-    boost::optional H2) const {
-
-  if (H1 || H2) {
-    Matrix29 D1;
-    Matrix2 D2;
-    Point2 pu = uncalibrate(p, D1, D2);
-    if (H1)
-      *H1 = D1;
-    if (H2)
-      *H2 = D2;
-    return pu;
-
-  } else {
-    return uncalibrate(p);
-  }
-}
-
 /* ************************************************************************* */
 Point2 Cal3DS2_Base::calibrate(const Point2& pi, const double tol) const {
   // Use the following fixed point iteration to invert the radial distortion.
@@ -177,7 +158,7 @@ Point2 Cal3DS2_Base::calibrate(const Point2& pi, const double tol) const {
 }
 
 /* ************************************************************************* */
-Matrix Cal3DS2_Base::D2d_intrinsic(const Point2& p) const {
+Matrix2 Cal3DS2_Base::D2d_intrinsic(const Point2& p) const {
   const double x = p.x(), y = p.y(), xx = x * x, yy = y * y;
   const double rr = xx + yy;
   const double r4 = rr * rr;
@@ -188,7 +169,7 @@ Matrix Cal3DS2_Base::D2d_intrinsic(const Point2& p) const {
 }
 
 /* ************************************************************************* */
-Matrix Cal3DS2_Base::D2d_calibration(const Point2& p) const {
+Matrix29 Cal3DS2_Base::D2d_calibration(const Point2& p) const {
   const double x = p.x(), y = p.y(), xx = x * x, yy = y * y, xy = x * y;
   const double rr = xx + yy;
   const double r4 = rr * rr;
diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h
index 61c01e349..f9292d4f6 100644
--- a/gtsam/geometry/Cal3DS2_Base.h
+++ b/gtsam/geometry/Cal3DS2_Base.h
@@ -45,7 +45,7 @@ protected:
   double p1_, p2_ ; // tangential distortion
 
 public:
-  Matrix K() const ;
+  Matrix3 K() const ;
   Eigen::Vector4d k() const { return Eigen::Vector4d(k1_, k2_, p1_, p2_); }
   Vector vector() const ;
 
@@ -113,23 +113,18 @@ public:
    * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
    * @return point in (distorted) image coordinates
    */
-
   Point2 uncalibrate(const Point2& p,
-       boost::optional Dcal = boost::none,
-       boost::optional Dp = boost::none) const ;
-
-  Point2 uncalibrate(const Point2& p,
-       boost::optional Dcal,
-       boost::optional Dp) const ;
+       OptionalJacobian<2,9> Dcal = boost::none,
+       OptionalJacobian<2,2> Dp = boost::none) const ;
 
   /// Convert (distorted) image coordinates uv to intrinsic coordinates xy
   Point2 calibrate(const Point2& p, const double tol=1e-5) const;
 
   /// Derivative of uncalibrate wrpt intrinsic coordinates
-  Matrix D2d_intrinsic(const Point2& p) const ;
+  Matrix2 D2d_intrinsic(const Point2& p) const ;
 
   /// Derivative of uncalibrate wrpt the calibration parameters
-  Matrix D2d_calibration(const Point2& p) const ;
+  Matrix29 D2d_calibration(const Point2& p) const ;
 
 private:
 
diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp
index 6bc4c4bb3..5bdf89856 100644
--- a/gtsam/geometry/Cal3Unified.cpp
+++ b/gtsam/geometry/Cal3Unified.cpp
@@ -52,8 +52,8 @@ bool Cal3Unified::equals(const Cal3Unified& K, double tol) const {
 /* ************************************************************************* */
 // todo: make a fixed sized jacobian version of this
 Point2 Cal3Unified::uncalibrate(const Point2& p,
-       boost::optional H1,
-       boost::optional H2) const {
+       OptionalJacobian<2,10> H1,
+       OptionalJacobian<2,2> H2) const {
 
   // this part of code is modified from Cal3DS2,
   // since the second part of this model (after project to normalized plane)
@@ -81,10 +81,7 @@ Point2 Cal3Unified::uncalibrate(const Point2& p,
     Vector2 DU;
     DU << -xs * sqrt_nx * xi_sqrt_nx2, //
         -ys * sqrt_nx * xi_sqrt_nx2;
-
-    H1->resize(2,10);
-    H1->block<2,9>(0,0) = H1base;
-    H1->block<2,1>(0,9) = H2base * DU;
+    *H1 << H1base, H2base * DU;
   }
 
   // Inlined derivative for points
@@ -96,7 +93,7 @@ Point2 Cal3Unified::uncalibrate(const Point2& p,
     DU << (sqrt_nx + xi*(ys*ys + 1)) * denom, mid, //
         mid, (sqrt_nx + xi*(xs*xs + 1)) * denom;
 
-    *H2 = H2base * DU;
+    *H2 << H2base * DU;
   }
 
   return puncalib;
diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h
index f65b27780..133e330ba 100644
--- a/gtsam/geometry/Cal3Unified.h
+++ b/gtsam/geometry/Cal3Unified.h
@@ -96,8 +96,8 @@ public:
    * @return point in image coordinates
    */
   Point2 uncalibrate(const Point2& p,
-      boost::optional Dcal = boost::none,
-      boost::optional Dp = boost::none) const ;
+      OptionalJacobian<2,10> Dcal = boost::none,
+      OptionalJacobian<2,2> Dp = boost::none) const ;
 
   /// Conver a pixel coordinate to ideal coordinate
   Point2 calibrate(const Point2& p, const double tol=1e-5) const;
diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp
index aece1ded1..3ec29bbd2 100644
--- a/gtsam/geometry/Cal3_S2.cpp
+++ b/gtsam/geometry/Cal3_S2.cpp
@@ -53,7 +53,7 @@ Cal3_S2::Cal3_S2(const std::string &path) :
 
 /* ************************************************************************* */
 void Cal3_S2::print(const std::string& s) const {
-  gtsam::print(matrix(), s);
+  gtsam::print((Matrix)matrix(), s);
 }
 
 /* ************************************************************************* */
@@ -72,32 +72,13 @@ bool Cal3_S2::equals(const Cal3_S2& K, double tol) const {
 }
 
 /* ************************************************************************* */
-Point2 Cal3_S2::uncalibrate(const Point2& p, boost::optional Dcal,
-    boost::optional Dp) const {
+Point2 Cal3_S2::uncalibrate(const Point2& p, OptionalJacobian<2, 5> Dcal,
+    OptionalJacobian<2, 2> Dp) const {
   const double x = p.x(), y = p.y();
-  if (Dcal) {
-    Dcal->resize(2,5);
+  if (Dcal)
     *Dcal << x, 0.0, y, 1.0, 0.0, 0.0, y, 0.0, 0.0, 1.0;
-  }
-  if (Dp) {
-    Dp->resize(2,2);
+  if (Dp)
     *Dp << fx_, s_, 0.0, fy_;
-  }
-  return Point2(fx_ * x + s_ * y + u0_, fy_ * y + v0_);
-}
-
-/* ************************************************************************* */
-Point2 Cal3_S2::uncalibrate(const Point2& p, boost::optional Dcal,
-    boost::optional Dp) const {
-  const double x = p.x(), y = p.y();
-  if (Dcal) *Dcal << x, 0.0, y, 1.0, 0.0, 0.0, y, 0.0, 0.0, 1.0;
-  if (Dp) *Dp << fx_, s_, 0.0, fy_;
-  return Point2(fx_ * x + s_ * y + u0_, fy_ * y + v0_);
-}
-
-/* ************************************************************************* */
-Point2 Cal3_S2::uncalibrate(const Point2& p) const {
-  const double x = p.x(), y = p.y();
   return Point2(fx_ * x + s_ * y + u0_, fy_ * y + v0_);
 }
 
diff --git a/gtsam/geometry/Cal3_S2.h b/gtsam/geometry/Cal3_S2.h
index 6317d251d..cf358d0b2 100644
--- a/gtsam/geometry/Cal3_S2.h
+++ b/gtsam/geometry/Cal3_S2.h
@@ -125,29 +125,26 @@ public:
   }
 
   /// return calibration matrix K
-  Matrix K() const {
-    return (Matrix(3, 3) <<  fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0).finished();
+  Matrix3 K() const {
+    Matrix3 K;
+    K <<  fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0;
+    return K;
   }
 
   /** @deprecated The following function has been deprecated, use K above */
-  Matrix matrix() const {
+  Matrix3 matrix() const {
     return K();
   }
 
   /// return inverted calibration matrix inv(K)
-  Matrix matrix_inverse() const {
+  Matrix3 matrix_inverse() const {
     const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_;
-    return (Matrix(3, 3) << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0,
-        1.0 / fy_, -v0_ / fy_, 0.0, 0.0, 1.0).finished();
+    Matrix3 K_inverse;
+    K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0,
+        1.0 / fy_, -v0_ / fy_, 0.0, 0.0, 1.0;
+    return K_inverse;
   }
 
-  /**
-   * convert intrinsic coordinates xy to image coordinates uv
-   * @param p point in intrinsic coordinates
-   * @return point in image coordinates
-   */
-  Point2 uncalibrate(const Point2& p) const;
-
   /**
    * convert intrinsic coordinates xy to image coordinates uv, fixed derivaitves
    * @param p point in intrinsic coordinates
@@ -155,18 +152,8 @@ public:
    * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
    * @return point in image coordinates
    */
-  Point2 uncalibrate(const Point2& p, boost::optional Dcal,
-      boost::optional Dp) const;
-
-  /**
-   * convert intrinsic coordinates xy to image coordinates uv, dynamic derivaitves
-   * @param p point in intrinsic coordinates
-   * @param Dcal optional 2*5 Jacobian wrpt Cal3_S2 parameters
-   * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
-   * @return point in image coordinates
-   */
-  Point2 uncalibrate(const Point2& p, boost::optional Dcal,
-      boost::optional Dp) const;
+  Point2 uncalibrate(const Point2& p, OptionalJacobian<2,5> Dcal = boost::none,
+      OptionalJacobian<2,2> Dp = boost::none) const;
 
   /**
    * convert image coordinates uv to intrinsic coordinates xy
@@ -184,10 +171,10 @@ public:
 
   /// "Between", subtracts calibrations. between(p,q) == compose(inverse(p),q)
   inline Cal3_S2 between(const Cal3_S2& q,
-      boost::optional H1=boost::none,
-      boost::optional H2=boost::none) const {
-    if(H1) *H1 = -eye(5);
-    if(H2) *H2 = eye(5);
+      OptionalJacobian<5,5> H1=boost::none,
+      OptionalJacobian<5,5> H2=boost::none) const {
+    if(H1) *H1 = -I_5x5;
+    if(H2) *H2 =  I_5x5;
     return Cal3_S2(q.fx_-fx_, q.fy_-fy_, q.s_-s_, q.u0_-u0_, q.v0_-v0_);
   }
 
diff --git a/gtsam/geometry/CalibratedCamera.cpp b/gtsam/geometry/CalibratedCamera.cpp
index 392a53858..1f5f1f8a5 100644
--- a/gtsam/geometry/CalibratedCamera.cpp
+++ b/gtsam/geometry/CalibratedCamera.cpp
@@ -33,10 +33,10 @@ CalibratedCamera::CalibratedCamera(const Vector &v) :
 
 /* ************************************************************************* */
 Point2 CalibratedCamera::project_to_camera(const Point3& P,
-    boost::optional H1) {
+    OptionalJacobian<2,3> H1) {
   if (H1) {
     double d = 1.0 / P.z(), d2 = d * d;
-    *H1 = (Matrix(2, 3) <<  d, 0.0, -P.x() * d2, 0.0, d, -P.y() * d2).finished();
+    *H1 <<  d, 0.0, -P.x() * d2, 0.0, d, -P.y() * d2;
   }
   return Point2(P.x() / P.z(), P.y() / P.z());
 }
@@ -59,10 +59,12 @@ CalibratedCamera CalibratedCamera::Level(const Pose2& pose2, double height) {
 
 /* ************************************************************************* */
 Point2 CalibratedCamera::project(const Point3& point,
-    boost::optional Dpose, boost::optional Dpoint) const {
+    OptionalJacobian<2,6> Dpose, OptionalJacobian<2,3> Dpoint) const {
 
 #ifdef CALIBRATEDCAMERA_CHAIN_RULE
-  Point3 q = pose_.transform_to(point, Dpose, Dpoint);
+  Matrix36 Dpose_;
+  Matrix3 Dpoint_;
+  Point3 q = pose_.transform_to(point, Dpose ? Dpose_ : 0, Dpoint ? Dpoint_ : 0);
 #else
   Point3 q = pose_.transform_to(point);
 #endif
@@ -75,23 +77,26 @@ Point2 CalibratedCamera::project(const Point3& point,
   if (Dpose || Dpoint) {
 #ifdef CALIBRATEDCAMERA_CHAIN_RULE
     // just implement chain rule
-    Matrix H;
-    project_to_camera(q,H);
-    if (Dpose) *Dpose = H * (*Dpose);
-    if (Dpoint) *Dpoint = H * (*Dpoint);
+    if(Dpose && Dpoint) {
+      Matrix23 H;
+      project_to_camera(q,H);
+      if (Dpose) *Dpose = H * (*Dpose_);
+      if (Dpoint) *Dpoint = H * (*Dpoint_);
+    }
 #else
     // optimized version, see CalibratedCamera.nb
     const double z = q.z(), d = 1.0 / z;
     const double u = intrinsic.x(), v = intrinsic.y(), uv = u * v;
     if (Dpose)
-      *Dpose = (Matrix(2, 6) <<  uv, -(1. + u * u), v, -d, 0., d * u, (1. + v * v),
-          -uv, -u, 0., -d, d * v).finished();
+      *Dpose <<  uv, -(1. + u * u), v, -d, 0., d * u, (1. + v * v),
+          -uv, -u, 0., -d, d * v;
     if (Dpoint) {
-      const Matrix R(pose_.rotation().matrix());
-      *Dpoint = d
-          * (Matrix(2, 3) <<  R(0, 0) - u * R(0, 2), R(1, 0) - u * R(1, 2),
+      const Matrix3 R(pose_.rotation().matrix());
+      Matrix23 Dpoint_;
+      Dpoint_ << R(0, 0) - u * R(0, 2), R(1, 0) - u * R(1, 2),
               R(2, 0) - u * R(2, 2), R(0, 1) - v * R(0, 2),
-              R(1, 1) - v * R(1, 2), R(2, 1) - v * R(2, 2)).finished();
+              R(1, 1) - v * R(1, 2), R(2, 1) - v * R(2, 2);
+      *Dpoint = d * Dpoint_;
     }
 #endif
   }
diff --git a/gtsam/geometry/CalibratedCamera.h b/gtsam/geometry/CalibratedCamera.h
index c66941091..f5a8b4469 100644
--- a/gtsam/geometry/CalibratedCamera.h
+++ b/gtsam/geometry/CalibratedCamera.h
@@ -18,9 +18,8 @@
 
 #pragma once
 
-#include 
-#include 
 #include 
+#include 
 
 namespace gtsam {
 
@@ -88,26 +87,6 @@ public:
     return pose_;
   }
 
-  /// compose the two camera poses: TODO Frank says this might not make sense
-  inline const CalibratedCamera compose(const CalibratedCamera &c,
-      boost::optional H1 = boost::none, boost::optional H2 =
-          boost::none) const {
-    return CalibratedCamera(pose_.compose(c.pose(), H1, H2));
-  }
-
-  /// between the two camera poses: TODO Frank says this might not make sense
-  inline const CalibratedCamera between(const CalibratedCamera& c,
-      boost::optional H1 = boost::none, boost::optional H2 =
-          boost::none) const {
-    return CalibratedCamera(pose_.between(c.pose(), H1, H2));
-  }
-
-  /// invert the camera pose: TODO Frank says this might not make sense
-  inline const CalibratedCamera inverse(boost::optional H1 =
-      boost::none) const {
-    return CalibratedCamera(pose_.inverse(H1));
-  }
-
   /**
    * Create a level camera at the given 2D pose and height
    * @param pose2 specifies the location and viewing direction
@@ -152,8 +131,8 @@ public:
    * @return the intrinsic coordinates of the projected point
    */
   Point2 project(const Point3& point,
-      boost::optional Dpose = boost::none,
-      boost::optional Dpoint = boost::none) const;
+      OptionalJacobian<2, 6> Dpose = boost::none,
+      OptionalJacobian<2, 3> Dpoint = boost::none) const;
 
   /**
    * projects a 3-dimensional point in camera coordinates into the
@@ -161,7 +140,7 @@ public:
    * With optional 2by3 derivative
    */
   static Point2 project_to_camera(const Point3& cameraPoint,
-      boost::optional H1 = boost::none);
+      OptionalJacobian<2, 3> H1 = boost::none);
 
   /**
    * backproject a 2-dimensional point to a 3-dimension point
@@ -175,8 +154,8 @@ public:
    * @param H2 optionally computed Jacobian with respect to the 3D point
    * @return range (double)
    */
-  double range(const Point3& point, boost::optional H1 = boost::none,
-      boost::optional H2 = boost::none) const {
+  double range(const Point3& point, OptionalJacobian<1, 6> H1 = boost::none,
+      OptionalJacobian<1, 3> H2 = boost::none) const {
     return pose_.range(point, H1, H2);
   }
 
@@ -187,8 +166,8 @@ public:
    * @param H2 optionally computed Jacobian with respect to the 3D point
    * @return range (double)
    */
-  double range(const Pose3& pose, boost::optional H1 = boost::none,
-      boost::optional H2 = boost::none) const {
+  double range(const Pose3& pose, OptionalJacobian<1, 6> H1 = boost::none,
+      OptionalJacobian<1, 6> H2 = boost::none) const {
     return pose_.range(pose, H1, H2);
   }
 
@@ -199,8 +178,8 @@ public:
    * @param H2 optionally computed Jacobian with respect to the 3D point
    * @return range (double)
    */
-  double range(const CalibratedCamera& camera, boost::optional H1 =
-      boost::none, boost::optional H2 = boost::none) const {
+  double range(const CalibratedCamera& camera, OptionalJacobian<1, 6> H1 =
+      boost::none, OptionalJacobian<1, 6> H2 = boost::none) const {
     return pose_.range(camera.pose_, H1, H2);
   }
 
@@ -224,15 +203,16 @@ private:
 namespace traits {
 
 template<>
-struct GTSAM_EXPORT is_group : public boost::true_type{
+struct GTSAM_EXPORT is_group : public boost::true_type {
 };
 
 template<>
-struct GTSAM_EXPORT is_manifold : public boost::true_type{
+struct GTSAM_EXPORT is_manifold : public boost::true_type {
 };
 
 template<>
-struct GTSAM_EXPORT dimension : public boost::integral_constant{
+struct GTSAM_EXPORT dimension : public boost::integral_constant<
+    int, 6> {
 };
 
 }
diff --git a/gtsam/geometry/EssentialMatrix.cpp b/gtsam/geometry/EssentialMatrix.cpp
index e65e5d097..c2b690496 100644
--- a/gtsam/geometry/EssentialMatrix.cpp
+++ b/gtsam/geometry/EssentialMatrix.cpp
@@ -14,7 +14,7 @@ namespace gtsam {
 
 /* ************************************************************************* */
 EssentialMatrix EssentialMatrix::FromPose3(const Pose3& _1P2_,
-    boost::optional H) {
+    OptionalJacobian<5, 6> H) {
   const Rot3& _1R2_ = _1P2_.rotation();
   const Point3& _1T2_ = _1P2_.translation();
   if (!H) {
@@ -25,13 +25,10 @@ EssentialMatrix EssentialMatrix::FromPose3(const Pose3& _1P2_,
     // Calculate the 5*6 Jacobian H = D_E_1P2
     // D_E_1P2 = [D_E_1R2 D_E_1T2], 5*3 wrpt rotation, 5*3 wrpt translation
     // First get 2*3 derivative from Unit3::FromPoint3
-    Matrix D_direction_1T2;
+    Matrix23 D_direction_1T2;
     Unit3 direction = Unit3::FromPoint3(_1T2_, D_direction_1T2);
-    H->resize(5, 6);
-    H->block<3, 3>(0, 0) << Matrix::Identity(3, 3); // upper left
-    H->block<2, 3>(3, 0) << Matrix::Zero(2, 3); // lower left
-    H->block<3, 3>(0, 3) << Matrix::Zero(3, 3); // upper right
-    H->block<2, 3>(3, 3) << D_direction_1T2 * _1R2_.matrix(); // lower right
+    *H << I_3x3, Z_3x3, //
+    Matrix23::Zero(), D_direction_1T2 * _1R2_.matrix();
     return EssentialMatrix(_1R2_, direction);
   }
 }
@@ -55,22 +52,23 @@ EssentialMatrix EssentialMatrix::retract(const Vector& xi) const {
 
 /* ************************************************************************* */
 Vector EssentialMatrix::localCoordinates(const EssentialMatrix& other) const {
-  return (Vector(5) <<
-      aRb_.localCoordinates(other.aRb_), aTb_.localCoordinates(other.aTb_)).finished();
+  return (Vector(5) << aRb_.localCoordinates(other.aRb_), aTb_.localCoordinates(
+      other.aTb_)).finished();
 }
 
 /* ************************************************************************* */
-Point3 EssentialMatrix::transform_to(const Point3& p,
-    boost::optional DE, boost::optional Dpoint) const {
+Point3 EssentialMatrix::transform_to(const Point3& p, OptionalJacobian<3, 5> DE,
+    OptionalJacobian<3, 3> Dpoint) const {
   Pose3 pose(aRb_, aTb_.point3());
-  Point3 q = pose.transform_to(p, DE, Dpoint);
+  Matrix36 DE_;
+  Point3 q = pose.transform_to(p, DE ? &DE_ : 0, Dpoint);
   if (DE) {
     // DE returned by pose.transform_to is 3*6, but we need it to be 3*5
     // The last 3 columns are derivative with respect to change in translation
     // The derivative of translation with respect to a 2D sphere delta is 3*2 aTb_.basis()
     // Duy made an educated guess that this needs to be rotated to the local frame
-    Matrix H(3, 5);
-    H << DE->block<3, 3>(0, 0), -aRb_.transpose() * aTb_.basis();
+    Matrix35 H;
+    H << DE_.block < 3, 3 > (0, 0), -aRb_.transpose() * aTb_.basis();
     *DE = H;
   }
   return q;
@@ -78,7 +76,7 @@ Point3 EssentialMatrix::transform_to(const Point3& p,
 
 /* ************************************************************************* */
 EssentialMatrix EssentialMatrix::rotate(const Rot3& cRb,
-    boost::optional HE, boost::optional HR) const {
+    OptionalJacobian<5, 5> HE, OptionalJacobian<5, 3> HR) const {
 
   // The rotation must be conjugated to act in the camera frame
   Rot3 c1Rc2 = aRb_.conjugate(cRb);
@@ -89,18 +87,16 @@ EssentialMatrix EssentialMatrix::rotate(const Rot3& cRb,
     return EssentialMatrix(c1Rc2, c1Tc2);
   } else {
     // Calculate derivatives
-    Matrix D_c1Tc2_cRb, D_c1Tc2_aTb; // 2*3 and 2*2
+    Matrix23 D_c1Tc2_cRb; // 2*3
+    Matrix2 D_c1Tc2_aTb; // 2*2
     Unit3 c1Tc2 = cRb.rotate(aTb_, D_c1Tc2_cRb, D_c1Tc2_aTb);
-    if (HE) {
-      *HE = zeros(5, 5);
-      HE->block<3, 3>(0, 0) << cRb.matrix(); // a change in aRb_ will yield a rotated change in c1Rc2
-      HE->block<2, 2>(3, 3) << D_c1Tc2_aTb; // (2*2)
-    }
+    if (HE)
+      *HE << cRb.matrix(), Matrix32::Zero(), //
+      Matrix23::Zero(), D_c1Tc2_aTb;
     if (HR) {
       throw runtime_error(
           "EssentialMatrix::rotate: derivative HR not implemented yet");
       /*
-       HR->resize(5, 3);
        HR->block<3, 3>(0, 0) << zeros(3, 3); // a change in the rotation yields ?
        HR->block<2, 3>(3, 0) << zeros(2, 3); // (2*3) * (3*3) ?
        */
@@ -110,13 +106,12 @@ EssentialMatrix EssentialMatrix::rotate(const Rot3& cRb,
 }
 
 /* ************************************************************************* */
-double EssentialMatrix::error(const Vector& vA, const Vector& vB, //
-    boost::optional H) const {
+double EssentialMatrix::error(const Vector3& vA, const Vector3& vB, //
+    OptionalJacobian<1, 5> H) const {
   if (H) {
-    H->resize(1, 5);
     // See math.lyx
-    Matrix HR = vA.transpose() * E_ * skewSymmetric(-vB);
-    Matrix HD = vA.transpose() * skewSymmetric(-aRb_.matrix() * vB)
+    Matrix13 HR = vA.transpose() * E_ * skewSymmetric(-vB);
+    Matrix12 HD = vA.transpose() * skewSymmetric(-aRb_.matrix() * vB)
         * aTb_.basis();
     *H << HR, HD;
   }
diff --git a/gtsam/geometry/EssentialMatrix.h b/gtsam/geometry/EssentialMatrix.h
index fd5f45160..b25286412 100644
--- a/gtsam/geometry/EssentialMatrix.h
+++ b/gtsam/geometry/EssentialMatrix.h
@@ -50,7 +50,7 @@ public:
 
   /// Named constructor converting a Pose3 with scale to EssentialMatrix (no scale)
   static EssentialMatrix FromPose3(const Pose3& _1P2_,
-      boost::optional H = boost::none);
+      OptionalJacobian<5, 6> H = boost::none);
 
   /// Random, using Rot3::Random and Unit3::Random
   template
@@ -132,16 +132,16 @@ public:
    * @return point in pose coordinates
    */
   Point3 transform_to(const Point3& p,
-      boost::optional DE = boost::none,
-      boost::optional Dpoint = boost::none) const;
+      OptionalJacobian<3,5> DE = boost::none,
+      OptionalJacobian<3,3> Dpoint = boost::none) const;
 
   /**
    * Given essential matrix E in camera frame B, convert to body frame C
    * @param cRb rotation from body frame to camera frame
    * @param E essential matrix E in camera frame C
    */
-  EssentialMatrix rotate(const Rot3& cRb, boost::optional HE =
-      boost::none, boost::optional HR = boost::none) const;
+  EssentialMatrix rotate(const Rot3& cRb, OptionalJacobian<5, 5> HE =
+      boost::none, OptionalJacobian<5, 3> HR = boost::none) const;
 
   /**
    * Given essential matrix E in camera frame B, convert to body frame C
@@ -153,8 +153,8 @@ public:
   }
 
   /// epipolar error, algebraic
-  double error(const Vector& vA, const Vector& vB, //
-      boost::optional H = boost::none) const;
+  double error(const Vector3& vA, const Vector3& vB, //
+      OptionalJacobian<1,5> H = boost::none) const;
 
   /// @}
 
diff --git a/gtsam/geometry/PinholeCamera.h b/gtsam/geometry/PinholeCamera.h
index c5174ae65..9b881dc78 100644
--- a/gtsam/geometry/PinholeCamera.h
+++ b/gtsam/geometry/PinholeCamera.h
@@ -18,16 +18,9 @@
 
 #pragma once
 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
 #include 
+#include 
+#include 
 
 namespace gtsam {
 
@@ -42,7 +35,9 @@ private:
   Pose3 pose_;
   Calibration K_;
 
-  static const int DimK = traits::dimension::value;
+  // Get dimensions of calibration type and This at compile time
+  static const int DimK = traits::dimension::value, //
+      DimC = 6 + DimK;
 
 public:
 
@@ -114,9 +109,9 @@ public:
   /// @{
 
   explicit PinholeCamera(const Vector &v) {
-    pose_ = Pose3::Expmap(v.head(Pose3::Dim()));
-    if (v.size() > Pose3::Dim()) {
-      K_ = Calibration(v.tail(Calibration::Dim()));
+    pose_ = Pose3::Expmap(v.head(6));
+    if (v.size() > 6) {
+      K_ = Calibration(v.tail(DimK));
     }
   }
 
@@ -167,82 +162,30 @@ public:
     return K_;
   }
 
-  /// @}
-  /// @name Group ?? Frank says this might not make sense
-  /// @{
-
-  /// compose two cameras: TODO Frank says this might not make sense
-  inline const PinholeCamera compose(const PinholeCamera &c,
-      boost::optional H1 = boost::none, boost::optional H2 =
-          boost::none) const {
-    PinholeCamera result(pose_.compose(c.pose(), H1, H2), K_);
-    if (H1) {
-      H1->conservativeResize(Dim(), Dim());
-      H1->topRightCorner(Pose3::Dim(), Calibration::Dim()) = zeros(Pose3::Dim(),
-          Calibration::Dim());
-      H1->bottomRows(Calibration::Dim()) = zeros(Calibration::Dim(), Dim());
-    }
-    if (H2) {
-      H2->conservativeResize(Dim(), Dim());
-      H2->topRightCorner(Pose3::Dim(), Calibration::Dim()) = zeros(Pose3::Dim(),
-          Calibration::Dim());
-      H2->bottomRows(Calibration::Dim()) = zeros(Calibration::Dim(), Dim());
-    }
-    return result;
-  }
-
-  /// between two cameras: TODO Frank says this might not make sense
-  inline const PinholeCamera between(const PinholeCamera& c,
-      boost::optional H1 = boost::none, boost::optional H2 =
-          boost::none) const {
-    PinholeCamera result(pose_.between(c.pose(), H1, H2), K_);
-    if (H1) {
-      H1->conservativeResize(Dim(), Dim());
-      H1->topRightCorner(Pose3::Dim(), Calibration::Dim()) = zeros(Pose3::Dim(),
-          Calibration::Dim());
-      H1->bottomRows(Calibration::Dim()) = zeros(Calibration::Dim(), Dim());
-    }
-    if (H2) {
-      H2->conservativeResize(Dim(), Dim());
-      H2->topRightCorner(Pose3::Dim(), Calibration::Dim()) = zeros(Pose3::Dim(),
-          Calibration::Dim());
-      H2->bottomRows(Calibration::Dim()) = zeros(Calibration::Dim(), Dim());
-    }
-    return result;
-  }
-
-  /// inverse camera: TODO Frank says this might not make sense
-  inline const PinholeCamera inverse(
-      boost::optional H1 = boost::none) const {
-    PinholeCamera result(pose_.inverse(H1), K_);
-    if (H1) {
-      H1->conservativeResize(Dim(), Dim());
-      H1->topRightCorner(Pose3::Dim(), Calibration::Dim()) = zeros(Pose3::Dim(),
-          Calibration::Dim());
-      H1->bottomRows(Calibration::Dim()) = zeros(Calibration::Dim(), Dim());
-    }
-    return result;
-  }
-
-  /// compose two cameras: TODO Frank says this might not make sense
-  inline const PinholeCamera compose(const Pose3 &c) const {
-    return PinholeCamera(pose_.compose(c), K_);
-  }
-
   /// @}
   /// @name Manifold
   /// @{
 
-  /// move a cameras according to d
-  PinholeCamera retract(const Vector& d) const {
-    if ((size_t) d.size() == pose_.dim())
-      return PinholeCamera(pose().retract(d), calibration());
-    else
-      return PinholeCamera(pose().retract(d.head(pose().dim())),
-          calibration().retract(d.tail(calibration().dim())));
+  /// Manifold dimension
+  inline size_t dim() const {
+    return DimC;
   }
 
-  typedef Eigen::Matrix VectorK6;
+  /// Manifold dimension
+  inline static size_t Dim() {
+    return DimC;
+  }
+
+  typedef Eigen::Matrix VectorK6;
+
+  /// move a cameras according to d
+  PinholeCamera retract(const Vector& d) const {
+    if ((size_t) d.size() == 6)
+      return PinholeCamera(pose().retract(d), calibration());
+    else
+      return PinholeCamera(pose().retract(d.head(6)),
+          calibration().retract(d.tail(calibration().dim())));
+  }
 
   /// return canonical coordinate
   VectorK6 localCoordinates(const PinholeCamera& T2) const {
@@ -252,16 +195,6 @@ public:
     return d;
   }
 
-  /// Manifold dimension
-  inline size_t dim() const {
-    return pose_.dim() + K_.dim();
-  }
-
-  /// Manifold dimension
-  inline static size_t Dim() {
-    return Pose3::Dim() + Calibration::Dim();
-  }
-
   /// @}
   /// @name Transformations and measurement functions
   /// @{
@@ -272,8 +205,8 @@ public:
    * @param P A point in camera coordinates
    * @param Dpoint is the 2*3 Jacobian w.r.t. P
    */
-  inline static Point2 project_to_camera(const Point3& P,
-      boost::optional Dpoint = boost::none) {
+  static Point2 project_to_camera(const Point3& P, //
+      OptionalJacobian<2, 3> Dpoint = boost::none) {
 #ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION
     if (P.z() <= 0)
       throw CheiralityException();
@@ -292,21 +225,7 @@ public:
     return std::make_pair(K_.uncalibrate(pn), pc.z() > 0);
   }
 
-  /** project a point from world coordinate to the image
-   *  @param pw is a point in world coordinates
-   */
-  inline Point2 project(const Point3& pw) const {
-
-    // Transform to camera coordinates and check cheirality
-    const Point3 pc = pose_.transform_to(pw);
-
-    // Project to normalized image coordinates
-    const Point2 pn = project_to_camera(pc);
-
-    return K_.uncalibrate(pn);
-  }
-
-  typedef Eigen::Matrix Matrix2K;
+  typedef Eigen::Matrix Matrix2K;
 
   /** project a point from world coordinate to the image
    *  @param pw is a point in world coordinates
@@ -314,11 +233,9 @@ public:
    *  @param Dpoint is the Jacobian w.r.t. point3
    *  @param Dcal is the Jacobian w.r.t. calibration
    */
-  inline Point2 project(
-      const Point3& pw, //
-      boost::optional Dpose,
-      boost::optional Dpoint,
-      boost::optional Dcal) const {
+  inline Point2 project(const Point3& pw, OptionalJacobian<2, 6> Dpose =
+      boost::none, OptionalJacobian<2, 3> Dpoint = boost::none,
+      OptionalJacobian<2, DimK> Dcal = boost::none) const {
 
     // Transform to camera coordinates and check cheirality
     const Point3 pc = pose_.transform_to(pw);
@@ -340,46 +257,7 @@ public:
         calculateDpoint(pn, d, pose_.rotation().matrix(), Dpi_pn, *Dpoint);
       return pi;
     } else
-      return K_.uncalibrate(pn, Dcal, boost::none);
-  }
-
-  /** project a point from world coordinate to the image
-   *  @param pw is a point in world coordinates
-   *  @param Dpose is the Jacobian w.r.t. pose3
-   *  @param Dpoint is the Jacobian w.r.t. point3
-   *  @param Dcal is the Jacobian w.r.t. calibration
-   */
-  inline Point2 project(
-      const Point3& pw, //
-      boost::optional Dpose,
-      boost::optional Dpoint,
-      boost::optional Dcal) const {
-
-    // Transform to camera coordinates and check cheirality
-    const Point3 pc = pose_.transform_to(pw);
-
-    // Project to normalized image coordinates
-    const Point2 pn = project_to_camera(pc);
-
-    if (Dpose || Dpoint) {
-      const double z = pc.z(), d = 1.0 / z;
-
-      // uncalibration
-      Matrix Dpi_pn(2, 2);
-      const Point2 pi = K_.uncalibrate(pn, Dcal, Dpi_pn);
-
-      // chain the Jacobian matrices
-      if (Dpose) {
-        Dpose->resize(2, 6);
-        calculateDpose(pn, d, Dpi_pn, *Dpose);
-      }
-      if (Dpoint) {
-        Dpoint->resize(2, 3);
-        calculateDpoint(pn, d, pose_.rotation().matrix(), Dpi_pn, *Dpoint);
-      }
-      return pi;
-    } else
-      return K_.uncalibrate(pn, Dcal, boost::none);
+      return K_.uncalibrate(pn, Dcal);
   }
 
   /** project a point at infinity from world coordinate to the image
@@ -388,11 +266,10 @@ public:
    *  @param Dpoint is the Jacobian w.r.t. point3
    *  @param Dcal is the Jacobian w.r.t. calibration
    */
-  inline Point2 projectPointAtInfinity(
-      const Point3& pw, //
-      boost::optional Dpose = boost::none,
-      boost::optional Dpoint = boost::none,
-      boost::optional Dcal = boost::none) const {
+  inline Point2 projectPointAtInfinity(const Point3& pw,
+      OptionalJacobian<2, 6> Dpose = boost::none,
+      OptionalJacobian<2, 2> Dpoint = boost::none,
+      OptionalJacobian<2, DimK> Dcal = boost::none) const {
 
     if (!Dpose && !Dpoint && !Dcal) {
       const Point3 pc = pose_.rotation().unrotate(pw); // get direction in camera frame (translation does not matter)
@@ -401,40 +278,30 @@ public:
     }
 
     // world to camera coordinate
-    Matrix Dpc_rot /* 3*3 */, Dpc_point /* 3*3 */;
+    Matrix3 Dpc_rot, Dpc_point;
     const Point3 pc = pose_.rotation().unrotate(pw, Dpc_rot, Dpc_point);
 
-    Matrix Dpc_pose = Matrix::Zero(3, 6);
-    Dpc_pose.block(0, 0, 3, 3) = Dpc_rot;
+    Matrix36 Dpc_pose;
+    Dpc_pose.setZero();
+    Dpc_pose.leftCols<3>() = Dpc_rot;
 
     // camera to normalized image coordinate
     Matrix23 Dpn_pc; // 2*3
     const Point2 pn = project_to_camera(pc, Dpn_pc);
 
     // uncalibration
-    Matrix Dpi_pn; // 2*2
+    Matrix2 Dpi_pn; // 2*2
     const Point2 pi = K_.uncalibrate(pn, Dcal, Dpi_pn);
 
     // chain the Jacobian matrices
-    const Matrix Dpi_pc = Dpi_pn * Dpn_pc;
+    const Matrix23 Dpi_pc = Dpi_pn * Dpn_pc;
     if (Dpose)
       *Dpose = Dpi_pc * Dpc_pose;
     if (Dpoint)
-      *Dpoint = (Dpi_pc * Dpc_point).block(0, 0, 2, 2); // only 2dof are important for the point (direction-only)
+      *Dpoint = (Dpi_pc * Dpc_point).leftCols<2>(); // only 2dof are important for the point (direction-only)
     return pi;
   }
 
-  typedef Eigen::Matrix Matrix2K6;
-
-  /** project a point from world coordinate to the image
-   *  @param pw is a point in the world coordinate
-   */
-  Point2 project2(const Point3& pw) const {
-    const Point3 pc = pose_.transform_to(pw);
-    const Point2 pn = project_to_camera(pc);
-    return K_.uncalibrate(pn);
-  }
-
   /** project a point from world coordinate to the image, fixed Jacobians
    *  @param pw is a point in the world coordinate
    *  @param Dcamera is the Jacobian w.r.t. [pose3 calibration]
@@ -442,8 +309,8 @@ public:
    */
   Point2 project2(
       const Point3& pw, //
-      boost::optional Dcamera,
-      boost::optional Dpoint) const {
+      OptionalJacobian<2, DimC> Dcamera = boost::none,
+      OptionalJacobian<2, 3> Dpoint = boost::none) const {
 
     const Point3 pc = pose_.transform_to(pw);
     const Point2 pn = project_to_camera(pc);
@@ -459,8 +326,8 @@ public:
       const Point2 pi = K_.uncalibrate(pn, Dcal, Dpi_pn);
 
       if (Dcamera) { // TODO why does leftCols<6>() not compile ??
-        calculateDpose(pn, d, Dpi_pn, Dcamera->leftCols(6));
-        Dcamera->rightCols(K_.dim()) = Dcal; // Jacobian wrt calib
+        calculateDpose(pn, d, Dpi_pn, (*Dcamera).leftCols(6));
+        (*Dcamera).rightCols(DimK) = Dcal; // Jacobian wrt calib
       }
       if (Dpoint) {
         calculateDpoint(pn, d, pose_.rotation().matrix(), Dpi_pn, *Dpoint);
@@ -469,40 +336,6 @@ public:
     }
   }
 
-  /** project a point from world coordinate to the image
-   *  @param pw is a point in the world coordinate
-   *  @param Dcamera is the Jacobian w.r.t. [pose3 calibration]
-   *  @param Dpoint is the Jacobian w.r.t. point3
-   */
-  Point2 project2(const Point3& pw, //
-      boost::optional Dcamera, boost::optional Dpoint) const {
-
-    const Point3 pc = pose_.transform_to(pw);
-    const Point2 pn = project_to_camera(pc);
-
-    if (!Dcamera && !Dpoint) {
-      return K_.uncalibrate(pn);
-    } else {
-      const double z = pc.z(), d = 1.0 / z;
-
-      // uncalibration
-      Matrix2K Dcal;
-      Matrix2 Dpi_pn;
-      const Point2 pi = K_.uncalibrate(pn, Dcal, Dpi_pn);
-
-      if (Dcamera) {
-        Dcamera->resize(2, this->dim());
-        calculateDpose(pn, d, Dpi_pn, Dcamera->leftCols<6>());
-        Dcamera->rightCols(K_.dim()) = Dcal; // Jacobian wrt calib
-      }
-      if (Dpoint) {
-        Dpoint->resize(2, 3);
-        calculateDpoint(pn, d, pose_.rotation().matrix(), Dpi_pn, *Dpoint);
-      }
-      return pi;
-    }
-  }
-
   /// backproject a 2-dimensional point to a 3-dimensional point at given depth
   inline Point3 backproject(const Point2& p, double depth) const {
     const Point2 pn = K_.calibrate(p);
@@ -520,71 +353,64 @@ public:
   /**
    * Calculate range to a landmark
    * @param point 3D location of landmark
-   * @param Dpose the optionally computed Jacobian with respect to pose
+   * @param Dcamera the optionally computed Jacobian with respect to pose
    * @param Dpoint the optionally computed Jacobian with respect to the landmark
    * @return range (double)
    */
   double range(
       const Point3& point, //
-      boost::optional Dpose = boost::none,
-      boost::optional Dpoint = boost::none) const {
-    double result = pose_.range(point, Dpose, Dpoint);
-    if (Dpose) {
-      // Add columns of zeros to Jacobian for calibration
-      Matrix& H1r(*Dpose);
-      H1r.conservativeResize(Eigen::NoChange, pose_.dim() + K_.dim());
-      H1r.block(0, pose_.dim(), 1, K_.dim()) = Matrix::Zero(1, K_.dim());
-    }
+      OptionalJacobian<1, DimC> Dcamera = boost::none,
+      OptionalJacobian<1, 3> Dpoint = boost::none) const {
+    Matrix16 Dpose_;
+    double result = pose_.range(point, Dcamera ? &Dpose_ : 0, Dpoint);
+    if (Dcamera)
+      *Dcamera << Dpose_, Eigen::Matrix::Zero();
     return result;
   }
 
   /**
    * Calculate range to another pose
    * @param pose Other SO(3) pose
-   * @param Dpose the optionally computed Jacobian with respect to pose
+   * @param Dcamera the optionally computed Jacobian with respect to pose
    * @param Dpose2 the optionally computed Jacobian with respect to the other pose
    * @return range (double)
    */
   double range(
       const Pose3& pose, //
-      boost::optional Dpose = boost::none,
-      boost::optional Dpose2 = boost::none) const {
-    double result = pose_.range(pose, Dpose, Dpose2);
-    if (Dpose) {
-      // Add columns of zeros to Jacobian for calibration
-      Matrix& H1r(*Dpose);
-      H1r.conservativeResize(Eigen::NoChange, pose_.dim() + K_.dim());
-      H1r.block(0, pose_.dim(), 1, K_.dim()) = Matrix::Zero(1, K_.dim());
-    }
+      OptionalJacobian<1, DimC> Dcamera = boost::none,
+      OptionalJacobian<1, 6> Dpose = boost::none) const {
+    Matrix16 Dpose_;
+    double result = pose_.range(pose, Dcamera ? &Dpose_ : 0, Dpose);
+    if (Dcamera)
+      *Dcamera << Dpose_, Eigen::Matrix::Zero();
     return result;
   }
 
   /**
    * Calculate range to another camera
    * @param camera Other camera
-   * @param Dpose the optionally computed Jacobian with respect to pose
+   * @param Dcamera the optionally computed Jacobian with respect to pose
    * @param Dother the optionally computed Jacobian with respect to the other camera
    * @return range (double)
    */
   template
   double range(
       const PinholeCamera& camera, //
-      boost::optional Dpose = boost::none,
-      boost::optional Dother = boost::none) const {
-    double result = pose_.range(camera.pose_, Dpose, Dother);
-    if (Dpose) {
-      // Add columns of zeros to Jacobian for calibration
-      Matrix& H1r(*Dpose);
-      H1r.conservativeResize(Eigen::NoChange, pose_.dim() + K_.dim());
-      H1r.block(0, pose_.dim(), 1, K_.dim()) = Matrix::Zero(1, K_.dim());
+      OptionalJacobian<1, DimC> Dcamera = boost::none,
+//      OptionalJacobian<1, 6 + traits::dimension::value> Dother =
+       boost::optional Dother =
+          boost::none) const {
+    Matrix16 Dcamera_, Dother_;
+    double result = pose_.range(camera.pose(), Dcamera ? &Dcamera_ : 0,
+        Dother ? &Dother_ : 0);
+    if (Dcamera) {
+       Dcamera->resize(1, 6 + DimK);
+      *Dcamera << Dcamera_, Eigen::Matrix::Zero();
     }
     if (Dother) {
-      // Add columns of zeros to Jacobian for calibration
-      Matrix& H2r(*Dother);
-      H2r.conservativeResize(Eigen::NoChange,
-          camera.pose().dim() + camera.calibration().dim());
-      H2r.block(0, camera.pose().dim(), 1, camera.calibration().dim()) =
-          Matrix::Zero(1, camera.calibration().dim());
+      Dother->resize(1, 6+traits::dimension::value);
+      Dother->setZero();
+      Dother->block(0, 0, 1, 6) = Dother_;
     }
     return result;
   }
@@ -592,15 +418,15 @@ public:
   /**
    * Calculate range to another camera
    * @param camera Other camera
-   * @param Dpose the optionally computed Jacobian with respect to pose
+   * @param Dcamera the optionally computed Jacobian with respect to pose
    * @param Dother the optionally computed Jacobian with respect to the other camera
    * @return range (double)
    */
   double range(
       const CalibratedCamera& camera, //
-      boost::optional Dpose = boost::none,
-      boost::optional Dother = boost::none) const {
-    return pose_.range(camera.pose_, Dpose, Dother);
+      OptionalJacobian<1, DimC> Dcamera = boost::none,
+      OptionalJacobian<1, 6> Dother = boost::none) const {
+    return range(camera.pose(), Dcamera, Dother);
   }
 
 private:
@@ -663,7 +489,7 @@ private:
 namespace traits {
 
 template
-struct GTSAM_EXPORT is_manifold > : public boost::true_type{
+struct GTSAM_EXPORT is_manifold > : public boost::true_type {
 };
 
 template
diff --git a/gtsam/geometry/Point2.cpp b/gtsam/geometry/Point2.cpp
index 8b90aed63..17e3ef370 100644
--- a/gtsam/geometry/Point2.cpp
+++ b/gtsam/geometry/Point2.cpp
@@ -38,15 +38,9 @@ bool Point2::equals(const Point2& q, double tol) const {
 }
 
 /* ************************************************************************* */
-double Point2::norm() const {
-  return sqrt(x_ * x_ + y_ * y_);
-}
-
-/* ************************************************************************* */
-double Point2::norm(boost::optional H) const {
-  double r = norm();
+double Point2::norm(OptionalJacobian<1,2> H) const {
+  double r = sqrt(x_ * x_ + y_ * y_);
   if (H) {
-    H->resize(1,2);
     if (fabs(r) > 1e-10)
       *H << x_ / r, y_ / r;
     else
@@ -56,12 +50,11 @@ double Point2::norm(boost::optional H) const {
 }
 
 /* ************************************************************************* */
-static const Matrix I2 = eye(2);
-double Point2::distance(const Point2& point, boost::optional H1,
-    boost::optional H2) const {
+double Point2::distance(const Point2& point, OptionalJacobian<1,2> H1,
+    OptionalJacobian<1,2> H2) const {
   Point2 d = point - *this;
   if (H1 || H2) {
-    Matrix H;
+    Matrix12 H;
     double r = d.norm(H);
     if (H1) *H1 = -H;
     if (H2) *H2 =  H;
diff --git a/gtsam/geometry/Point2.h b/gtsam/geometry/Point2.h
index a4e0cc296..8c8e03db4 100644
--- a/gtsam/geometry/Point2.h
+++ b/gtsam/geometry/Point2.h
@@ -20,7 +20,7 @@
 #include 
 
 #include 
-#include 
+#include 
 #include 
 
 namespace gtsam {
@@ -125,10 +125,10 @@ public:
 
   /// "Compose", just adds the coordinates of two points. With optional derivatives
   inline Point2 compose(const Point2& q,
-      boost::optional H1=boost::none,
-      boost::optional H2=boost::none) const {
-    if(H1) *H1 = eye(2);
-    if(H2) *H2 = eye(2);
+      OptionalJacobian<2,2> H1=boost::none,
+      OptionalJacobian<2,2> H2=boost::none) const {
+    if(H1) *H1 = I_2x2;
+    if(H2) *H2 = I_2x2;
     return *this + q;
   }
 
@@ -137,10 +137,10 @@ public:
 
   /// "Between", subtracts point coordinates. between(p,q) == compose(inverse(p),q)
   inline Point2 between(const Point2& q,
-      boost::optional H1=boost::none,
-      boost::optional H2=boost::none) const {
-    if(H1) *H1 = -eye(2);
-    if(H2) *H2 = eye(2);
+      OptionalJacobian<2,2> H1=boost::none,
+      OptionalJacobian<2,2> H2=boost::none) const {
+    if(H1) *H1 = -I_2x2;
+    if(H2) *H2 = I_2x2;
     return q - (*this);
   }
 
@@ -180,15 +180,12 @@ public:
   /** creates a unit vector */
   Point2 unit() const { return *this/norm(); }
 
-  /** norm of point */
-  double norm() const;
-
   /** norm of point, with derivative */
-  double norm(boost::optional H) const;
+  double norm(OptionalJacobian<1,2> H = boost::none) const;
 
   /** distance between two points */
-  double distance(const Point2& p2, boost::optional H1 = boost::none,
-      boost::optional H2 = boost::none) const;
+  double distance(const Point2& p2, OptionalJacobian<1,2> H1 = boost::none,
+      OptionalJacobian<1,2> H2 = boost::none) const;
 
   /** @deprecated The following function has been deprecated, use distance above */
   inline double dist(const Point2& p2) const {
diff --git a/gtsam/geometry/Point3.cpp b/gtsam/geometry/Point3.cpp
index ce56c78c1..330fafb97 100644
--- a/gtsam/geometry/Point3.cpp
+++ b/gtsam/geometry/Point3.cpp
@@ -63,22 +63,18 @@ Point3 Point3::operator/(double s) const {
 }
 
 /* ************************************************************************* */
-Point3 Point3::add(const Point3 &q, boost::optional H1,
-    boost::optional H2) const {
-  if (H1)
-    *H1 = eye(3, 3);
-  if (H2)
-    *H2 = eye(3, 3);
+Point3 Point3::add(const Point3 &q, OptionalJacobian<3,3> H1,
+    OptionalJacobian<3,3> H2) const {
+  if (H1) *H1 = I_3x3;
+  if (H2) *H2 = I_3x3;
   return *this + q;
 }
 
 /* ************************************************************************* */
-Point3 Point3::sub(const Point3 &q, boost::optional H1,
-    boost::optional H2) const {
-  if (H1)
-    *H1 = eye(3, 3);
-  if (H2)
-    *H2 = -eye(3, 3);
+Point3 Point3::sub(const Point3 &q, OptionalJacobian<3,3> H1,
+    OptionalJacobian<3,3> H2) const {
+  if (H1) *H1 = I_3x3;
+  if (H2) *H2 = I_3x3;
   return *this - q;
 }
 
@@ -94,26 +90,8 @@ double Point3::dot(const Point3 &q) const {
 }
 
 /* ************************************************************************* */
-double Point3::norm() const {
-  return sqrt(x_ * x_ + y_ * y_ + z_ * z_);
-}
-
-/* ************************************************************************* */
-double Point3::norm(boost::optional H) const {
-  double r = norm();
-  if (H) {
-    H->resize(1,3);
-    if (fabs(r) > 1e-10)
-      *H << x_ / r, y_ / r, z_ / r;
-    else
-      *H << 1, 1, 1; // really infinity, why 1 ?
-  }
-  return r;
-}
-
-/* ************************************************************************* */
-double Point3::norm(boost::optional&> H) const {
-  double r = norm();
+double Point3::norm(OptionalJacobian<1,3> H) const {
+  double r = sqrt(x_ * x_ + y_ * y_ + z_ * z_);
   if (H) {
     if (fabs(r) > 1e-10)
       *H << x_ / r, y_ / r, z_ / r;
@@ -124,13 +102,12 @@ double Point3::norm(boost::optional&> H) const {
 }
 
 /* ************************************************************************* */
-Point3 Point3::normalize(boost::optional H) const {
+Point3 Point3::normalize(OptionalJacobian<3,3> H) const {
   Point3 normalized = *this / norm();
   if (H) {
     // 3*3 Derivative
     double x2 = x_ * x_, y2 = y_ * y_, z2 = z_ * z_;
     double xy = x_ * y_, xz = x_ * z_, yz = y_ * z_;
-    H->resize(3, 3);
     *H << y2 + z2, -xy, -xz, /**/-xy, x2 + z2, -yz, /**/-xz, -yz, x2 + y2;
     *H /= pow(x2 + y2 + z2, 1.5);
   }
diff --git a/gtsam/geometry/Point3.h b/gtsam/geometry/Point3.h
index b7f7f8ffa..56d9b8bef 100644
--- a/gtsam/geometry/Point3.h
+++ b/gtsam/geometry/Point3.h
@@ -21,9 +21,9 @@
 
 #pragma once
 
-#include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -93,10 +93,10 @@ namespace gtsam {
 
     /// "Compose" - just adds coordinates of two points
     inline Point3 compose(const Point3& p2,
-        boost::optional H1=boost::none,
-        boost::optional H2=boost::none) const {
-      if (H1) *H1 = eye(3);
-      if (H2) *H2 = eye(3);
+        OptionalJacobian<3,3> H1=boost::none,
+        OptionalJacobian<3,3> H2=boost::none) const {
+      if (H1) *H1 << I_3x3;
+      if (H2) *H2 << I_3x3;
       return *this + p2;
     }
 
@@ -105,10 +105,10 @@ namespace gtsam {
 
     /** Between using the default implementation */
     inline Point3 between(const Point3& p2,
-        boost::optional H1=boost::none,
-        boost::optional H2=boost::none) const {
-      if(H1) *H1 = -eye(3);
-      if(H2) *H2 = eye(3);
+        OptionalJacobian<3,3> H1=boost::none,
+        OptionalJacobian<3,3> H2=boost::none) const {
+      if(H1) *H1 = -I_3x3;
+      if(H2) *H2 = I_3x3;
       return p2 - *this;
     }
 
@@ -142,13 +142,13 @@ namespace gtsam {
     static inline Vector3 Logmap(const Point3& dp) { return Vector3(dp.x(), dp.y(), dp.z()); }
 
     /// Left-trivialized derivative of the exponential map
-    static Matrix dexpL(const Vector& v) {
-      return eye(3);
+    static Matrix3 dexpL(const Vector& v) {
+      return I_3x3;
     }
 
     /// Left-trivialized derivative inverse of the exponential map
-    static Matrix dexpInvL(const Vector& v) {
-      return eye(3);
+    static Matrix3 dexpInvL(const Vector& v) {
+      return I_3x3;
     }
 
     /// @}
@@ -163,14 +163,16 @@ namespace gtsam {
 
     /** distance between two points */
     inline double distance(const Point3& p2,
-        boost::optional H1 = boost::none, boost::optional H2 = boost::none) const {
+        OptionalJacobian<1,3> H1 = boost::none, OptionalJacobian<1,3> H2 = boost::none) const {
       double d = (p2 - *this).norm();
       if (H1) {
-        *H1 = (Matrix(1, 3) << x_-p2.x(), y_-p2.y(), z_-p2.z()).finished()*(1./d);
+        *H1 << x_-p2.x(), y_-p2.y(), z_-p2.z();
+        *H1 = *H1 *(1./d);
       }
 
       if (H2) {
-        *H2 = (Matrix(1, 3) << -x_+p2.x(), -y_+p2.y(), -z_+p2.z()).finished()*(1./d);
+        *H2 << -x_+p2.x(), -y_+p2.y(), -z_+p2.z();
+        *H2 << *H2 *(1./d);
       }
       return d;
     }
@@ -180,17 +182,11 @@ namespace gtsam {
       return (p2 - *this).norm();
     }
 
-    /** Distance of the point from the origin */
-    double norm() const;
-
     /** Distance of the point from the origin, with Jacobian */
-    double norm(boost::optional H) const;
-
-    /** Distance of the point from the origin, with Jacobian */
-    double norm(boost::optional&> H) const;
+    double norm(OptionalJacobian<1,3> H = boost::none) const;
 
     /** normalize, with optional Jacobian */
-    Point3 normalize(boost::optional H = boost::none) const;
+    Point3 normalize(OptionalJacobian<3, 3> H = boost::none) const;
 
     /** cross product @return this x q */
     Point3 cross(const Point3 &q) const;
@@ -219,11 +215,11 @@ namespace gtsam {
 
     /** add two points, add(this,q) is same as this + q */
     Point3 add (const Point3 &q,
-          boost::optional H1=boost::none, boost::optional H2=boost::none) const;
+          OptionalJacobian<3, 3> H1=boost::none, OptionalJacobian<3, 3> H2=boost::none) const;
 
     /** subtract two points, sub(this,q) is same as this - q */
     Point3 sub (const Point3 &q,
-          boost::optional H1=boost::none, boost::optional H2=boost::none) const;
+          OptionalJacobian<3,3> H1=boost::none, OptionalJacobian<3,3> H2=boost::none) const;
 
     /// @}
 
diff --git a/gtsam/geometry/Pose2.cpp b/gtsam/geometry/Pose2.cpp
index 7a693ed3d..c9aab4185 100644
--- a/gtsam/geometry/Pose2.cpp
+++ b/gtsam/geometry/Pose2.cpp
@@ -33,15 +33,20 @@ INSTANTIATE_LIE(Pose2);
 /** instantiate concept checks */
 GTSAM_CONCEPT_POSE_INST(Pose2);
 
-static const Matrix I3 = eye(3), Z12 = zeros(1,2);
 static const Rot2 R_PI_2(Rot2::fromCosSin(0., 1.));
 
 /* ************************************************************************* */
-Matrix Pose2::matrix() const {
-  Matrix R = r_.matrix();
-  R = stack(2, &R, &Z12);
-  Matrix T = (Matrix(3, 1) <<  t_.x(), t_.y(), 1.0).finished();
-  return collect(2, &R, &T);
+Matrix3 Pose2::matrix() const {
+  Matrix2 R = r_.matrix();
+  Matrix32 R0;
+  R0.block<2,2>(0,0) = R;
+  R0.block<1,2>(2,0).setZero();
+  Matrix31 T;
+  T <<  t_.x(), t_.y(), 1.0;
+  Matrix3 RT_;
+  RT_.block<3,2>(0,0) = R0;
+  RT_.block<3,1>(0,2) = T;
+  return RT_;
 }
 
 /* ************************************************************************* */
@@ -108,105 +113,64 @@ Vector Pose2::localCoordinates(const Pose2& p2) const {
 /* ************************************************************************* */
 // Calculate Adjoint map
 // Ad_pose is 3*3 matrix that when applied to twist xi, returns Ad_pose(xi)
-Matrix Pose2::AdjointMap() const {
+Matrix3 Pose2::AdjointMap() const {
   double c = r_.c(), s = r_.s(), x = t_.x(), y = t_.y();
-  return (Matrix(3, 3) <<
+  Matrix3 rvalue;
+  rvalue <<
       c,  -s,   y,
       s,   c,  -x,
-      0.0, 0.0, 1.0
-  ).finished();
+      0.0, 0.0, 1.0;
+  return rvalue;
 }
 
 /* ************************************************************************* */
-Pose2 Pose2::inverse(boost::optional H1) const {
+Pose2 Pose2::inverse(OptionalJacobian<3,3> H1) const {
   if (H1) *H1 = -AdjointMap();
   return Pose2(r_.inverse(), r_.unrotate(Point2(-t_.x(), -t_.y())));
 }
 
-/* ************************************************************************* */
-// see doc/math.lyx, SE(2) section
-Point2 Pose2::transform_to(const Point2& point) const {
-  Point2 d = point - t_;
-  return r_.unrotate(d);
-}
-
 /* ************************************************************************* */
 // see doc/math.lyx, SE(2) section
 Point2 Pose2::transform_to(const Point2& point,
-    boost::optional H1, boost::optional H2) const {
+    OptionalJacobian<2, 3> H1, OptionalJacobian<2, 2> H2) const {
   Point2 d = point - t_;
   Point2 q = r_.unrotate(d);
   if (!H1 && !H2) return q;
   if (H1) *H1 <<
       -1.0, 0.0,  q.y(),
       0.0, -1.0, -q.x();
-  if (H2) *H2 = r_.transpose();
+  if (H2) *H2 << r_.transpose();
   return q;
 }
 
 /* ************************************************************************* */
 // see doc/math.lyx, SE(2) section
-Point2 Pose2::transform_to(const Point2& point,
-    boost::optional H1, boost::optional H2) const {
-  Point2 d = point - t_;
-  Point2 q = r_.unrotate(d);
-  if (!H1 && !H2) return q;
-  if (H1) *H1 = (Matrix(2, 3) <<
-      -1.0, 0.0,  q.y(),
-      0.0, -1.0, -q.x()).finished();
-  if (H2) *H2 = r_.transpose();
-  return q;
-}
-
-/* ************************************************************************* */
-// see doc/math.lyx, SE(2) section
-Pose2 Pose2::compose(const Pose2& p2, boost::optional H1,
-    boost::optional H2) const {
+Pose2 Pose2::compose(const Pose2& p2, OptionalJacobian<3,3> H1,
+    OptionalJacobian<3,3> H2) const {
   // TODO: inline and reuse?
   if(H1) *H1 = p2.inverse().AdjointMap();
-  if(H2) *H2 = I3;
+  if(H2) *H2 = I_3x3;
   return (*this)*p2;
 }
 
 /* ************************************************************************* */
 // see doc/math.lyx, SE(2) section
 Point2 Pose2::transform_from(const Point2& p,
-    boost::optional H1, boost::optional H2) const {
+    OptionalJacobian<2, 3> H1, OptionalJacobian<2, 2> H2) const {
   const Point2 q = r_ * p;
   if (H1 || H2) {
-    const Matrix R = r_.matrix();
-    const Matrix Drotate1 = (Matrix(2, 1) <<  -q.y(), q.x()).finished();
-    if (H1) *H1 = collect(2, &R, &Drotate1); // [R R_{pi/2}q]
-    if (H2) *H2 = R;                         // R
+    const Matrix2 R = r_.matrix();
+    Matrix21 Drotate1;
+    Drotate1 <<  -q.y(), q.x();
+    if (H1) *H1 << R, Drotate1;
+    if (H2) *H2 = R; // R
   }
   return q + t_;
 }
 
 /* ************************************************************************* */
-Pose2 Pose2::between(const Pose2& p2) const {
-  // get cosines and sines from rotation matrices
-  const Rot2& R1 = r_, R2 = p2.r();
-  double c1=R1.c(), s1=R1.s(), c2=R2.c(), s2=R2.s();
-
-  // Assert that R1 and R2 are normalized
-  assert(std::abs(c1*c1 + s1*s1 - 1.0) < 1e-5 && std::abs(c2*c2 + s2*s2 - 1.0) < 1e-5);
-
-  // Calculate delta rotation = between(R1,R2)
-  double c = c1 * c2 + s1 * s2, s = -s1 * c2 + c1 * s2;
-  Rot2 R(Rot2::atan2(s,c)); // normalizes
-
-  // Calculate delta translation = unrotate(R1, dt);
-  Point2 dt = p2.t() - t_;
-  double x = dt.x(), y = dt.y();
-  // t = R1' * (t2-t1)
-  Point2 t(c1 * x + s1 * y, -s1 * x + c1 * y);
-
-  return Pose2(R,t);
-}
-
-/* ************************************************************************* */
-Pose2 Pose2::between(const Pose2& p2, boost::optional H1,
-    boost::optional H2) const {
+Pose2 Pose2::between(const Pose2& p2, OptionalJacobian<3,3> H1,
+    OptionalJacobian<3,3> H2) const {
   // get cosines and sines from rotation matrices
   const Rot2& R1 = r_, R2 = p2.r();
   double c1=R1.c(), s1=R1.s(), c2=R2.c(), s2=R2.s();
@@ -233,97 +197,75 @@ Pose2 Pose2::between(const Pose2& p2, boost::optional H1,
         s,  -c,  dt2,
         0.0, 0.0,-1.0;
   }
-  if (H2) *H2 = I3;
-
-  return Pose2(R,t);
-}
-
-/* ************************************************************************* */
-Pose2 Pose2::between(const Pose2& p2, boost::optional H1,
-    boost::optional H2) const {
-  // get cosines and sines from rotation matrices
-  const Rot2& R1 = r_, R2 = p2.r();
-  double c1=R1.c(), s1=R1.s(), c2=R2.c(), s2=R2.s();
-
-  // Assert that R1 and R2 are normalized
-  assert(std::abs(c1*c1 + s1*s1 - 1.0) < 1e-5 && std::abs(c2*c2 + s2*s2 - 1.0) < 1e-5);
-
-  // Calculate delta rotation = between(R1,R2)
-  double c = c1 * c2 + s1 * s2, s = -s1 * c2 + c1 * s2;
-  Rot2 R(Rot2::atan2(s,c)); // normalizes
-
-  // Calculate delta translation = unrotate(R1, dt);
-  Point2 dt = p2.t() - t_;
-  double x = dt.x(), y = dt.y();
-  // t = R1' * (t2-t1)
-  Point2 t(c1 * x + s1 * y, -s1 * x + c1 * y);
-
-  // FD: This is just -AdjointMap(between(p2,p1)) inlined and re-using above
-  if (H1) {
-    double dt1 = -s2 * x + c2 * y;
-    double dt2 = -c2 * x - s2 * y;
-    *H1 = (Matrix(3, 3) <<
-        -c,  -s,  dt1,
-        s,  -c,  dt2,
-        0.0, 0.0,-1.0).finished();
-  }
-  if (H2) *H2 = I3;
+  if (H2) *H2 = I_3x3;
 
   return Pose2(R,t);
 }
 
 /* ************************************************************************* */
 Rot2 Pose2::bearing(const Point2& point,
-    boost::optional H1, boost::optional H2) const {
-  Point2 d = transform_to(point, H1, H2);
+    OptionalJacobian<1, 3> H1, OptionalJacobian<1, 2> H2) const {
+  // make temporary matrices
+  Matrix23 D1; Matrix2 D2;
+  Point2 d = transform_to(point, H1 ? &D1 : 0, H2 ? &D2 : 0); // uses pointer version
   if (!H1 && !H2) return Rot2::relativeBearing(d);
-  Matrix D_result_d;
+  Matrix12 D_result_d;
   Rot2 result = Rot2::relativeBearing(d, D_result_d);
-  if (H1) *H1 = D_result_d * (*H1);
-  if (H2) *H2 = D_result_d * (*H2);
+  if (H1) *H1 = D_result_d * (D1);
+  if (H2) *H2 = D_result_d * (D2);
   return result;
 }
 
 /* ************************************************************************* */
-Rot2 Pose2::bearing(const Pose2& point,
-    boost::optional H1, boost::optional H2) const {
-  Rot2 result = bearing(point.t(), H1, H2);
+Rot2 Pose2::bearing(const Pose2& pose,
+    OptionalJacobian<1, 3> H1, OptionalJacobian<1, 3> H2) const {
+  Matrix12 D2;
+  Rot2 result = bearing(pose.t(), H1, H2 ? &D2 : 0);
   if (H2) {
-    Matrix H2_ = *H2 * point.r().matrix();
-    *H2 = zeros(1, 3);
-    insertSub(*H2, H2_, 0, 0);
+    Matrix12 H2_ = D2 * pose.r().matrix();
+    *H2 << H2_, Z_1x1;
   }
   return result;
 }
-
 /* ************************************************************************* */
 double Pose2::range(const Point2& point,
-    boost::optional H1, boost::optional H2) const {
+    OptionalJacobian<1,3> H1, OptionalJacobian<1,2> H2) const {
   Point2 d = point - t_;
   if (!H1 && !H2) return d.norm();
-  Matrix H;
+  Matrix12 H;
   double r = d.norm(H);
-  if (H1) *H1 = H * (Matrix(2, 3) <<
-      -r_.c(),  r_.s(),  0.0,
-      -r_.s(), -r_.c(),  0.0).finished();
+  if (H1) {
+      Matrix23 H1_;
+      H1_ << -r_.c(),  r_.s(),  0.0,
+              -r_.s(), -r_.c(),  0.0;
+      *H1 = H * H1_;
+  }
   if (H2) *H2 = H;
   return r;
 }
 
 /* ************************************************************************* */
-double Pose2::range(const Pose2& pose2,
-    boost::optional H1,
-    boost::optional H2) const {
-  Point2 d = pose2.t() - t_;
+double Pose2::range(const Pose2& pose,
+    OptionalJacobian<1,3> H1,
+    OptionalJacobian<1,3> H2) const {
+  Point2 d = pose.t() - t_;
   if (!H1 && !H2) return d.norm();
-  Matrix H;
+  Matrix12 H;
   double r = d.norm(H);
-  if (H1) *H1 = H * (Matrix(2, 3) <<
+  if (H1) {
+      Matrix23 H1_;
+      H1_ <<
       -r_.c(),  r_.s(),  0.0,
-      -r_.s(), -r_.c(),  0.0).finished();
-  if (H2) *H2 = H * (Matrix(2, 3) <<
-      pose2.r_.c(), -pose2.r_.s(),  0.0,
-      pose2.r_.s(),  pose2.r_.c(),  0.0).finished();
+      -r_.s(), -r_.c(),  0.0;
+      *H1 = H * H1_;
+  }
+  if (H2) {
+      Matrix23 H2_;
+      H2_ <<
+      pose.r_.c(), -pose.r_.s(),  0.0,
+      pose.r_.s(),  pose.r_.c(),  0.0;
+      *H2 = H * H2_;
+  }
   return r;
 }
 
diff --git a/gtsam/geometry/Pose2.h b/gtsam/geometry/Pose2.h
index d43be6afb..49eb444b2 100644
--- a/gtsam/geometry/Pose2.h
+++ b/gtsam/geometry/Pose2.h
@@ -107,12 +107,12 @@ public:
   inline static Pose2 identity() { return Pose2(); }
 
   /// inverse transformation with derivatives
-  Pose2 inverse(boost::optional H1=boost::none) const;
+  Pose2 inverse(OptionalJacobian<3, 3> H1=boost::none) const;
 
   /// compose this transformation onto another (first *this and then p2)
   Pose2 compose(const Pose2& p2,
-      boost::optional H1 = boost::none,
-      boost::optional