diff --git a/.cproject b/.cproject
index af6b32cd2..d5a6ca4d4 100644
--- a/.cproject
+++ b/.cproject
@@ -568,6 +568,7 @@
 			
 			
 				make
+				
 				tests/testBayesTree.run
 				true
 				false
@@ -575,6 +576,7 @@
 			
 			
 				make
+				
 				testBinaryBayesNet.run
 				true
 				false
@@ -622,6 +624,7 @@
 			
 			
 				make
+				
 				testSymbolicBayesNet.run
 				true
 				false
@@ -629,6 +632,7 @@
 			
 			
 				make
+				
 				tests/testSymbolicFactor.run
 				true
 				false
@@ -636,6 +640,7 @@
 			
 			
 				make
+				
 				testSymbolicFactorGraph.run
 				true
 				false
@@ -651,6 +656,7 @@
 			
 			
 				make
+				
 				tests/testBayesTree
 				true
 				false
@@ -728,46 +734,6 @@
 				true
 				true
 			
-			
-				make
-				-j5
-				testValues.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testOrdering.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testKey.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testLinearContainerFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j6 -j8
-				testWhiteNoiseFactor.run
-				true
-				true
-				true
-			
 			
 				make
 				-j2
@@ -1114,6 +1080,7 @@
 			
 			
 				make
+				
 				testErrors.run
 				true
 				false
@@ -1159,6 +1126,14 @@
 				true
 				true
 			
+			
+				make
+				-j5
+				testParticleFactor.run
+				true
+				true
+				true
+			
 			
 				make
 				-j2
@@ -1239,14 +1214,6 @@
 				true
 				true
 			
-			
-				make
-				-j5
-				testParticleFactor.run
-				true
-				true
-				true
-			
 			
 				make
 				-j2
@@ -1351,6 +1318,22 @@
 				true
 				true
 			
+			
+				make
+				-j5
+				testImuFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testCombinedImuFactor.run
+				true
+				true
+				true
+			
 			
 				make
 				-j2
@@ -1433,7 +1416,6 @@
 			
 			
 				make
-				
 				testSimulated2DOriented.run
 				true
 				false
@@ -1473,7 +1455,6 @@
 			
 			
 				make
-				
 				testSimulated2D.run
 				true
 				false
@@ -1481,7 +1462,6 @@
 			
 			
 				make
-				
 				testSimulated3D.run
 				true
 				false
@@ -1495,22 +1475,6 @@
 				true
 				true
 			
-			
-				make
-				-j5
-				testImuFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testCombinedImuFactor.run
-				true
-				true
-				true
-			
 			
 				make
 				-j5
@@ -1768,6 +1732,7 @@
 			
 			
 				cpack
+				
 				-G DEB
 				true
 				false
@@ -1775,6 +1740,7 @@
 			
 			
 				cpack
+				
 				-G RPM
 				true
 				false
@@ -1782,6 +1748,7 @@
 			
 			
 				cpack
+				
 				-G TGZ
 				true
 				false
@@ -1789,6 +1756,7 @@
 			
 			
 				cpack
+				
 				--config CPackSourceConfig.cmake
 				true
 				false
@@ -2217,70 +2185,6 @@
 				true
 				true
 			
-			
-				make
-				-j5
-				testGeneralSFMFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testProjectionFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testGeneralSFMFactor_Cal3Bundler.run
-				true
-				true
-				true
-			
-			
-				make
-				-j6 -j8
-				testAntiFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j6 -j8
-				testBetweenFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testDataset.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testEssentialMatrixFactor.run
-				true
-				true
-				true
-			
-			
-				make
-				-j5
-				testRotateFactor.run
-				true
-				true
-				true
-			
 			
 				make
 				-j2
@@ -2547,6 +2451,7 @@
 			
 			
 				make
+				
 				testGraph.run
 				true
 				false
@@ -2554,6 +2459,7 @@
 			
 			
 				make
+				
 				testJunctionTree.run
 				true
 				false
@@ -2561,6 +2467,7 @@
 			
 			
 				make
+				
 				testSymbolicBayesNetB.run
 				true
 				false
@@ -2678,6 +2585,70 @@
 				true
 				true
 			
+			
+				make
+				-j5
+				testAntiFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testBetweenFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testDataset.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testEssentialMatrixFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testGeneralSFMFactor_Cal3Bundler.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testGeneralSFMFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testProjectionFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testRotateFactor.run
+				true
+				true
+				true
+			
 			
 				make
 				-j2
@@ -2830,6 +2801,70 @@
 				true
 				true
 			
+			
+				make
+				-j5
+				Pose2SLAMExample_lago.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				Pose2SLAMExample_g2o.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testLago.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testLinearContainerFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testOrdering.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testValues.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				testWhiteNoiseFactor.run
+				true
+				true
+				true
+			
+			
+				make
+				-j5
+				timeLago.run
+				true
+				true
+				true
+			
 			
 				make
 				-j4
@@ -2848,7 +2883,6 @@
 			
 			
 				make
-				
 				tests/testGaussianISAM2
 				true
 				false
diff --git a/.gitignore b/.gitignore
index 6d274af09..cf23a5147 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 /build*
 /doc*
 *.pyc
-*.DS_Store
\ No newline at end of file
+*.DS_Store
+/examples/Data/dubrovnik-3-7-pre-rewritten.txt
+/examples/Data/pose2example-rewritten.txt
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 196b7e4df..933f2083e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.6)
 
 # Set the version number for the library
 set (GTSAM_VERSION_MAJOR 3)
-set (GTSAM_VERSION_MINOR 0)
+set (GTSAM_VERSION_MINOR 1)
 set (GTSAM_VERSION_PATCH 0)
 math (EXPR GTSAM_VERSION_NUMERIC "10000 * ${GTSAM_VERSION_MAJOR} + 100 * ${GTSAM_VERSION_MINOR} + ${GTSAM_VERSION_PATCH}")
 set (GTSAM_VERSION_STRING "${GTSAM_VERSION_MAJOR}.${GTSAM_VERSION_MINOR}.${GTSAM_VERSION_PATCH}")
@@ -273,6 +273,13 @@ if(MSVC)
 	add_definitions(/wd4251 /wd4275 /wd4251 /wd4661 /wd4344) # Disable non-DLL-exported base class and other warnings
 endif()
 
+# GCC 4.8+ complains about local typedefs which we use for shared_ptr etc.
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+    add_definitions(-Wno-unused-local-typedefs)
+  endif()
+endif()
+
 if(GTSAM_ENABLE_CONSISTENCY_CHECKS)
   add_definitions(-DGTSAM_EXTRA_CONSISTENCY_CHECKS)
 endif()
diff --git a/examples/Data/dubrovnik-3-7-pre-rewritten.txt b/examples/Data/dubrovnik-3-7-pre-rewritten.txt
deleted file mode 100644
index 7dea43c9e..000000000
--- a/examples/Data/dubrovnik-3-7-pre-rewritten.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-3 7 19
-
-0 0 -385.989990234375 387.1199951171875
-1 0 -38.439998626708984375 492.1199951171875
-2 0 -667.91998291015625 123.1100006103515625
-0 1 383.8800048828125 -15.299989700317382812
-1 1 559.75 -106.15000152587890625
-0 2 591.54998779296875 136.44000244140625
-1 2 863.8599853515625 -23.469970703125
-2 2 494.720001220703125 112.51999664306640625
-0 3 592.5 125.75
-1 3 861.08001708984375 -35.219970703125
-2 3 498.540008544921875 101.55999755859375
-0 4 348.720001220703125 558.3800048828125
-1 4 776.030029296875 483.529998779296875
-2 4 7.7800288200378417969 326.350006103515625
-0 5 14.010009765625 96.420013427734375
-1 5 207.1300048828125 118.3600006103515625
-0 6 202.7599945068359375 340.989990234375
-1 6 543.18011474609375 294.80999755859375
-2 6 -58.419979095458984375 110.8300018310546875
-
-  0.29656188120312942935
--0.035318354384285870207
-  0.31252101755032046793
-0.47230274932665988752
--0.3572340863744113415
--2.0517704282499575896
-1430.031982421875
--7.5572756941255647689e-08
-3.2377570134516087119e-14
-
- 0.28532097381985194184
--0.27699838370789808817
-0.048601169984112867206
-  -1.2598695987143850861
--0.049063798188844320869
-  -1.9586867140445654023
-1432.137451171875
--7.3171918302250560373e-08
-3.1759419042137054801e-14
-
-0.057491325683772541433
- 0.34853090049579965592
- 0.47985129303736057116
- 8.1963904289063389541
- 6.5146840788718787252
--3.8392804395897406344
-1572.047119140625
--1.5962623223231275915e-08
--1.6507904730136101212e-14
-
--11.317351620610928364
-3.3594874875767186673
--42.755222607849105998
-
-4.2648515634753199066
--8.4629358700849355301
--22.252086323427270997
-
-10.996977688149536689
--9.2123370180278048025
--29.206739014051372294
-
-10.935342607054865383
--9.4338917557810741954
--29.112263909175499776
-
-15.714024935401759819
-1.3745079651566265433
--59.286834979937104606
-
--1.3624227800805182031
--4.1979357415396094666
--21.034430148188398846
-
-6.7690173115899296974
--4.7352452433700786827
--53.605307875695892506
-
diff --git a/examples/Data/pose2example-rewritten.txt b/examples/Data/pose2example-rewritten.txt
deleted file mode 100644
index 6c8fe38a2..000000000
--- a/examples/Data/pose2example-rewritten.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-VERTEX_SE2 0 0 0 0
-VERTEX_SE2 1 1.03039 0.01135 -0.081596
-VERTEX_SE2 2 2.03614 -0.129733 -0.301887
-VERTEX_SE2 3 3.0151 -0.442395 -0.345514
-VERTEX_SE2 4 3.34395 0.506678 1.21471
-VERTEX_SE2 5 3.68449 1.46405 1.18379
-VERTEX_SE2 6 4.06463 2.41478 1.17633
-VERTEX_SE2 7 4.42978 3.30018 1.25917
-VERTEX_SE2 8 4.12888 2.32148 -1.82539
-VERTEX_SE2 9 3.88465 1.32751 -1.95302
-VERTEX_SE2 10 3.53107 0.388263 -2.14893
-EDGE_SE2 0 1 1.03039 0.01135 -0.081596 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 1 2 1.0139 -0.058639 -0.220291 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 2 3 1.02765 -0.007456 -0.043627 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 3 4 -0.012016 1.00436 1.56023 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 4 5 1.01603 0.014565 -0.03093 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 5 6 1.02389 0.006808 -0.007452 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 6 7 0.957734 0.003159 0.082836 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 7 8 -1.02382 -0.013668 -3.08456 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 8 9 1.02344 0.013984 -0.127624 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 9 10 1.00335 0.02225 -0.195918 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 5 9 0.033943 0.032439 3.07364 44.7214 0 0 44.7214 0 30.9017
-EDGE_SE2 3 10 0.04402 0.988477 -1.55351 44.7214 0 0 44.7214 0 30.9017
diff --git a/examples/Pose2SLAMExample_g2o.cpp b/examples/Pose2SLAMExample_g2o.cpp
index 393bba86d..3a4ee9cff 100644
--- a/examples/Pose2SLAMExample_g2o.cpp
+++ b/examples/Pose2SLAMExample_g2o.cpp
@@ -18,46 +18,45 @@
  * @author Luca Carlone
  */
 
-#include 
-#include 
-#include 
 #include 
-#include 
-#include 
+#include 
 #include 
-#include 
-#include 
 #include 
-#include 
 
 using namespace std;
 using namespace gtsam;
 
+int main(const int argc, const char *argv[]) {
 
-int main(const int argc, const char *argv[]){
-
+  // Read graph from file
+  string g2oFile;
   if (argc < 2)
-    std::cout << "Please specify: 1st argument: input file (in g2o format) and 2nd argument: output file" << std::endl;
-  const string g2oFile = argv[1];
+    g2oFile = "../../examples/Data/noisyToyGraph.txt";
+  else
+    g2oFile = argv[1];
 
-  NonlinearFactorGraph graph;
-  Values initial;
-  readG2o(g2oFile, graph, initial);
+  NonlinearFactorGraph::shared_ptr graph;
+  Values::shared_ptr initial;
+  boost::tie(graph, initial) = readG2o(g2oFile);
 
   // Add prior on the pose having index (key) = 0
-  NonlinearFactorGraph graphWithPrior = graph;
-  noiseModel::Diagonal::shared_ptr priorModel = noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
+  NonlinearFactorGraph graphWithPrior = *graph;
+  noiseModel::Diagonal::shared_ptr priorModel = //
+      noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
   graphWithPrior.add(PriorFactor(0, Pose2(), priorModel));
 
   std::cout << "Optimizing the factor graph" << std::endl;
-  GaussNewtonOptimizer optimizer(graphWithPrior, initial); // , parameters);
+  GaussNewtonOptimizer optimizer(graphWithPrior, *initial);
   Values result = optimizer.optimize();
   std::cout << "Optimization complete" << std::endl;
 
-  const string outputFile = argv[2];
-  std::cout << "Writing results to file: " << outputFile << std::endl;
-  writeG2o(outputFile, graph, result);
-  std::cout << "done! " << std::endl;
-
+  if (argc < 3) {
+    result.print("result");
+  } else {
+    const string outputFile = argv[2];
+    std::cout << "Writing results to file: " << outputFile << std::endl;
+    writeG2o(*graph, result, outputFile);
+    std::cout << "done! " << std::endl;
+  }
   return 0;
 }
diff --git a/examples/Pose2SLAMExample_lago.cpp b/examples/Pose2SLAMExample_lago.cpp
index d61f1b533..1f5d80d7b 100644
--- a/examples/Pose2SLAMExample_lago.cpp
+++ b/examples/Pose2SLAMExample_lago.cpp
@@ -12,51 +12,53 @@
 /**
  * @file Pose2SLAMExample_lago.cpp
  * @brief A 2D Pose SLAM example that reads input from g2o, and solve the Pose2 problem
- * using LAGO (Linear Approximation for Graph Optimization). See class LagoInitializer.h
+ * using LAGO (Linear Approximation for Graph Optimization). See class lago.h
  * Output is written on a file, in g2o format
  * Syntax for the script is ./Pose2SLAMExample_lago input.g2o output.g2o
  * @date May 15, 2014
  * @author Luca Carlone
  */
 
-#include 
-#include 
-#include 
+#include 
 #include 
-#include 
-#include 
-#include 
-#include 
+#include 
 #include 
-#include 
 
 using namespace std;
 using namespace gtsam;
 
+int main(const int argc, const char *argv[]) {
 
-int main(const int argc, const char *argv[]){
-
+  // Read graph from file
+  string g2oFile;
   if (argc < 2)
-    std::cout << "Please specify: 1st argument: input file (in g2o format) and 2nd argument: output file" << std::endl;
-  const string g2oFile = argv[1];
+    g2oFile = "../../examples/Data/noisyToyGraph.txt";
+  else
+    g2oFile = argv[1];
 
-  NonlinearFactorGraph graph;
-  Values initial;
-  readG2o(g2oFile, graph, initial);
+  NonlinearFactorGraph::shared_ptr graph;
+  Values::shared_ptr initial;
+  boost::tie(graph, initial) = readG2o(g2oFile);
 
   // Add prior on the pose having index (key) = 0
-  NonlinearFactorGraph graphWithPrior = graph;
-  noiseModel::Diagonal::shared_ptr priorModel = noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
+  NonlinearFactorGraph graphWithPrior = *graph;
+  noiseModel::Diagonal::shared_ptr priorModel = //
+      noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
   graphWithPrior.add(PriorFactor(0, Pose2(), priorModel));
+  graphWithPrior.print();
 
   std::cout << "Computing LAGO estimate" << std::endl;
-  Values estimateLago = initializeLago(graphWithPrior);
+  Values estimateLago = lago::initialize(graphWithPrior);
   std::cout << "done!" << std::endl;
 
-  const string outputFile = argv[2];
-  std::cout << "Writing results to file: " << outputFile << std::endl;
-  writeG2o(outputFile, graph, estimateLago);
-  std::cout << "done! " << std::endl;
+  if (argc < 3) {
+    estimateLago.print("estimateLago");
+  } else {
+    const string outputFile = argv[2];
+    std::cout << "Writing results to file: " << outputFile << std::endl;
+    writeG2o(*graph, estimateLago, outputFile);
+    std::cout << "done! " << std::endl;
+  }
 
   return 0;
 }
diff --git a/examples/SFMExample_SmartFactor.cpp b/examples/SFMExample_SmartFactor.cpp
new file mode 100644
index 000000000..904919d42
--- /dev/null
+++ b/examples/SFMExample_SmartFactor.cpp
@@ -0,0 +1,168 @@
+/* ----------------------------------------------------------------------------
+
+ * 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    SFMExample_SmartFactor.cpp
+ * @brief   A structure-from-motion problem on a simulated dataset, using smart projection factor
+ * @author  Duy-Nguyen Ta
+ * @author  Jing Dong
+ */
+
+/**
+ * A structure-from-motion example with landmarks
+ *  - The landmarks form a 10 meter cube
+ *  - The robot rotates around the landmarks, always facing towards the cube
+ */
+
+// For loading the data
+#include "SFMdata.h"
+
+// Camera observations of landmarks (i.e. pixel coordinates) will be stored as Point2 (x, y).
+#include 
+
+// Each variable in the system (poses and landmarks) must be identified with a unique key.
+// We can either use simple integer keys (1, 2, 3, ...) or symbols (X1, X2, L1).
+// Here we will use Symbols
+#include 
+
+// In GTSAM, measurement functions are represented as 'factors'.
+// The factor we used here is SmartProjectionPoseFactor. Every smart factor represent a single landmark,
+// The SmartProjectionPoseFactor only optimize the pose of camera, not the calibration,
+// The calibration should be known.
+#include 
+
+// Also, we will initialize the robot at some location using a Prior factor.
+#include 
+
+// When the factors are created, we will add them to a Factor Graph. As the factors we are using
+// are nonlinear factors, we will need a Nonlinear Factor Graph.
+#include 
+
+// Finally, once all of the factors have been added to our factor graph, we will want to
+// solve/optimize to graph to find the best (Maximum A Posteriori) set of variable values.
+// GTSAM includes several nonlinear optimizers to perform this step. Here we will use a
+// trust-region method known as Powell's Degleg
+#include 
+
+// The nonlinear solvers within GTSAM are iterative solvers, meaning they linearize the
+// nonlinear functions around an initial linearization point, then solve the linear system
+// to update the linearization point. This happens repeatedly until the solver converges
+// to a consistent set of variable values. This requires us to specify an initial guess
+// for each variable, held in a Values container.
+#include 
+
+#include 
+
+using namespace std;
+using namespace gtsam;
+
+// Make the typename short so it looks much cleaner
+typedef gtsam::SmartProjectionPoseFactor
+  SmartFactor;
+
+/* ************************************************************************* */
+int main(int argc, char* argv[]) {
+
+  // Define the camera calibration parameters
+  Cal3_S2::shared_ptr K(new Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0));
+
+  // Define the camera observation noise model
+  noiseModel::Isotropic::shared_ptr measurementNoise = noiseModel::Isotropic::Sigma(2, 1.0); // one pixel in u and v
+
+  // Create the set of ground-truth landmarks
+  vector points = createPoints();
+
+  // Create the set of ground-truth poses
+  vector poses = createPoses();
+
+  // Create a factor graph
+  NonlinearFactorGraph graph;
+
+  // A vector saved all Smart factors (for get landmark position after optimization)
+  vector smartfactors_ptr;
+
+  // Simulated measurements from each camera pose, adding them to the factor graph
+  for (size_t i = 0; i < points.size(); ++i) {
+
+    // every landmark represent a single landmark, we use shared pointer to init the factor, and then insert measurements.
+    SmartFactor::shared_ptr smartfactor(new SmartFactor());
+
+    for (size_t j = 0; j < poses.size(); ++j) {
+
+      // generate the 2D measurement
+      SimpleCamera camera(poses[j], *K);
+      Point2 measurement = camera.project(points[i]);
+
+      // call add() function to add measurment into a single factor, here we need to add:
+      //    1. the 2D measurement
+      //    2. the corresponding camera's key
+      //    3. camera noise model
+      //    4. camera calibration
+      smartfactor->add(measurement, Symbol('x', j), measurementNoise, K);
+    }
+
+    // save smartfactors to get landmark position
+    smartfactors_ptr.push_back(smartfactor);
+
+    // insert the smart factor in the graph
+    graph.push_back(smartfactor);
+  }
+
+  // Add a prior on pose x0. This indirectly specifies where the origin is.
+  noiseModel::Diagonal::shared_ptr poseNoise = noiseModel::Diagonal::Sigmas((Vector(6) << Vector3::Constant(0.3), Vector3::Constant(0.1))); // 30cm std on x,y,z 0.1 rad on roll,pitch,yaw
+  graph.push_back(PriorFactor(Symbol('x', 0), poses[0], poseNoise)); // add directly to graph
+
+  // Because the structure-from-motion problem has a scale ambiguity, the problem is still under-constrained
+  // Here we add a prior on the second pose x1, so this will fix the scale by indicating the distance between x0 and x1.
+  // Because these two are fixed, the rest poses will be alse fixed.
+  graph.push_back(PriorFactor(Symbol('x', 1), poses[1], poseNoise)); // add directly to graph
+
+  graph.print("Factor Graph:\n");
+
+  // Create the data structure to hold the initial estimate to the solution
+  // Intentionally initialize the variables off from the ground truth
+  Values initialEstimate;
+  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))));
+  initialEstimate.print("Initial Estimates:\n");
+
+  // Optimize the graph and print results
+  Values result = DoglegOptimizer(graph, initialEstimate).optimize();
+  result.print("Final results:\n");
+
+
+  // Notice: Smart factor represent the 3D point as a factor, not a variable.
+  // The 3D position of the landmark is not explicitly calculated by the optimizer.
+  // If you do want to output the landmark's 3D position, you should use the internal function point()
+  // of the smart factor to get the 3D point.
+  Values landmark_result;
+  for (size_t i = 0; i < points.size(); ++i) {
+
+    // The output of point() is in boost::optional, since sometimes
+    // the triangulation opterations inside smart factor will encounter degeneracy.
+    // Check the manual of boost::optional for more details for the usages.
+    boost::optional point;
+
+    // here we use the saved smart factors to call, pass in all optimized pose to calculate landmark positions
+    point = smartfactors_ptr.at(i)->point(result);
+
+    // ignore if boost::optional return NULL
+    if (point)
+      landmark_result.insert(Symbol('l', i), *point);
+  }
+
+  landmark_result.print("Landmark results:\n");
+
+
+  return 0;
+}
+/* ************************************************************************* */
+
diff --git a/examples/StereoVOExample_large.cpp b/examples/StereoVOExample_large.cpp
index c661967c0..b9ab663d9 100644
--- a/examples/StereoVOExample_large.cpp
+++ b/examples/StereoVOExample_large.cpp
@@ -25,47 +25,43 @@
  */
 
 #include 
-#include 
+#include 
+#include 
+#include 
 #include 
 #include 
-#include 
-#include 
-#include 
-
-#include 
-#include 
 #include 
+#include 
+#include 
 
+#include 
 #include 
 #include 
-#include 
-#include 
 
 using namespace std;
 using namespace gtsam;
 
 int main(int argc, char** argv){
 
+  Values initial_estimate;
   NonlinearFactorGraph graph;
   const noiseModel::Isotropic::shared_ptr model = noiseModel::Isotropic::Sigma(3,1);
-  Values initial_estimate = Values();
-  vector read_vector;
-  string read_string, parse_string;
 
-  string data_folder = "C:/Users/Stephen/Documents/Borg/gtsam/Examples/Data/";
-  string calibration_loc = data_folder + "VO_calibration.txt";
-  string pose_loc = data_folder + "VO_camera_poses_large.txt";
-  string factor_loc = data_folder + "VO_stereo_factors_large.txt";
+  string calibration_loc = findExampleDataFile("VO_calibration.txt");
+  string pose_loc = findExampleDataFile("VO_camera_poses_large.txt");
+  string factor_loc = findExampleDataFile("VO_stereo_factors_large.txt");
   
   //read camera calibration info from file
-  double fx,fy,s,u,v,b;
-  ifstream calibration_file(calibration_loc);
+  // focal lengths fx, fy, skew s, principal point u0, v0, baseline b
+  double fx, fy, s, u0, v0, b;
+  ifstream calibration_file(calibration_loc.c_str());
   cout << "Reading calibration info" << endl;
-  calibration_file >> fx >> fy >> s >> u >> v >> b;
+  calibration_file >> fx >> fy >> s >> u0 >> v0 >> b;
+
   //create stereo camera calibration object
-  const Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx,fy,s,u,v,b));
+  const Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx,fy,s,u0,v0,b));
   
-  ifstream pose_file(pose_loc);
+  ifstream pose_file(pose_loc.c_str());
   cout << "Reading camera poses" << endl;
   int pose_id;
   MatrixRowMajor m(4,4);
@@ -77,30 +73,36 @@ int main(int argc, char** argv){
     initial_estimate.insert(Symbol('x', pose_id), Pose3(m));
   }
   
-  double x, l, uL, uR, v, X, Y, Z;
-  ifstream factor_file(factor_loc);
+  // camera and landmark keys
+  size_t x, l;
+
+  // pixel coordinates uL, uR, v (same for left/right images due to rectification)
+  // landmark coordinates X, Y, Z in camera frame, resulting from triangulation
+  double uL, uR, v, X, Y, Z;
+  ifstream factor_file(factor_loc.c_str());
   cout << "Reading stereo factors" << endl;
   //read stereo measurement details from file and use to create and add GenericStereoFactor objects to the graph representation
   while (factor_file >> x >> l >> uL >> uR >> v >> X >> Y >> Z) {
-      graph.push_back(
-          GenericStereoFactor(StereoPoint2(uL, uR, v), model,
-                  Symbol('x', x), Symbol('l', l), K));
-      //if the landmark variable included in this factor has not yet been added to the initial variable value estimate, add it
-      if(!initial_estimate.exists(Symbol('l',l))){
-        Pose3 camPose = initial_estimate.at(Symbol('x', x));
-        //transform_from() transforms the input Point3 from the camera pose space, camPose, to the global space
-        Point3 worldPoint = camPose.transform_from(Point3(X,Y,Z));
-        initial_estimate.insert(Symbol('l',l),worldPoint);
-      }
+    graph.push_back(
+        GenericStereoFactor(StereoPoint2(uL, uR, v), model,
+            Symbol('x', x), Symbol('l', l), K));
+    //if the landmark variable included in this factor has not yet been added to the initial variable value estimate, add it
+    if (!initial_estimate.exists(Symbol('l', l))) {
+      Pose3 camPose = initial_estimate.at(Symbol('x', x));
+      //transform_from() transforms the input Point3 from the camera pose space, camPose, to the global space
+      Point3 worldPoint = camPose.transform_from(Point3(X, Y, Z));
+      initial_estimate.insert(Symbol('l', l), worldPoint);
+    }
   }
 
   Pose3 first_pose = initial_estimate.at(Symbol('x',1));
-  first_pose.print("Check estimate poses:\n");
   //constrain the first pose such that it cannot change from its original value during optimization
+  // NOTE: NonlinearEquality forces the optimizer to use QR rather than Cholesky
+  // QR is much slower than Cholesky, but numerically more stable
   graph.push_back(NonlinearEquality(Symbol('x',1),first_pose));
 
   cout << "Optimizing" << endl;
-  //create Levenberg-Marquardt optimizer to solve the initial factor graph estimate
+  //create Levenberg-Marquardt optimizer to optimize the factor graph
   LevenbergMarquardtOptimizer optimizer = LevenbergMarquardtOptimizer(graph, initial_estimate);
   Values result = optimizer.optimize();
 
@@ -109,4 +111,4 @@ int main(int argc, char** argv){
   pose_values.print("Final camera poses:\n");
 
   return 0;
-}
\ No newline at end of file
+}
diff --git a/gtsam.h b/gtsam.h
index 96a778acf..b7178d534 100644
--- a/gtsam.h
+++ b/gtsam.h
@@ -2249,6 +2249,13 @@ pair load2D(string filename,
 pair load2D(string filename);
 pair load2D_robust(string filename,
     gtsam::noiseModel::Base* model);
+void save2D(const gtsam::NonlinearFactorGraph& graph,
+    const gtsam::Values& config, gtsam::noiseModel::Diagonal* model,
+    string filename);
+
+pair readG2o(string filename);
+void writeG2o(const gtsam::NonlinearFactorGraph& graph,
+    const gtsam::Values& estimate, string filename);
 
 //*************************************************************************
 // Navigation
diff --git a/gtsam/3rdparty/CCOLAMD/Source/ccolamd.c b/gtsam/3rdparty/CCOLAMD/Source/ccolamd.c
index 36ffa1ada..1c35ffa41 100644
--- a/gtsam/3rdparty/CCOLAMD/Source/ccolamd.c
+++ b/gtsam/3rdparty/CCOLAMD/Source/ccolamd.c
@@ -617,11 +617,12 @@
 
 #include "ccolamd.h"
 
-#include 
 #include 
 #include 
 
 #ifdef MATLAB_MEX_FILE
+#include 
+typedef uint16_t char16_t;
 #include "mex.h"
 #include "matrix.h"
 #endif
diff --git a/gtsam/3rdparty/CCOLAMD/Source/ccolamd_global.c b/gtsam/3rdparty/CCOLAMD/Source/ccolamd_global.c
index d43985126..e470804a6 100644
--- a/gtsam/3rdparty/CCOLAMD/Source/ccolamd_global.c
+++ b/gtsam/3rdparty/CCOLAMD/Source/ccolamd_global.c
@@ -13,6 +13,9 @@
 
 #ifndef NPRINT
 #ifdef MATLAB_MEX_FILE
+#include 
+#include 
+typedef uint16_t char16_t;
 #include "mex.h"
 int (*ccolamd_printf) (const char *, ...) = mexPrintf ;
 #else
diff --git a/gtsam_unstable/geometry/TriangulationFactor.h b/gtsam/geometry/TriangulationFactor.h
similarity index 100%
rename from gtsam_unstable/geometry/TriangulationFactor.h
rename to gtsam/geometry/TriangulationFactor.h
diff --git a/gtsam_unstable/geometry/tests/testTriangulation.cpp b/gtsam/geometry/tests/testTriangulation.cpp
similarity index 99%
rename from gtsam_unstable/geometry/tests/testTriangulation.cpp
rename to gtsam/geometry/tests/testTriangulation.cpp
index 8d45311f1..fb05bcf9f 100644
--- a/gtsam_unstable/geometry/tests/testTriangulation.cpp
+++ b/gtsam/geometry/tests/testTriangulation.cpp
@@ -16,7 +16,7 @@
  *      Author: cbeall3
  */
 
-#include 
+#include 
 #include 
 #include 
 
diff --git a/gtsam/geometry/tests/testSphere2.cpp b/gtsam/geometry/tests/testUnit3.cpp
similarity index 100%
rename from gtsam/geometry/tests/testSphere2.cpp
rename to gtsam/geometry/tests/testUnit3.cpp
diff --git a/gtsam_unstable/geometry/triangulation.cpp b/gtsam/geometry/triangulation.cpp
similarity index 98%
rename from gtsam_unstable/geometry/triangulation.cpp
rename to gtsam/geometry/triangulation.cpp
index 3017fdf7a..9e1575801 100644
--- a/gtsam_unstable/geometry/triangulation.cpp
+++ b/gtsam/geometry/triangulation.cpp
@@ -16,7 +16,7 @@
  * @author Chris Beall
  */
 
-#include 
+#include 
 
 #include 
 #include 
diff --git a/gtsam_unstable/geometry/triangulation.h b/gtsam/geometry/triangulation.h
similarity index 97%
rename from gtsam_unstable/geometry/triangulation.h
rename to gtsam/geometry/triangulation.h
index f767514c1..6899c616a 100644
--- a/gtsam_unstable/geometry/triangulation.h
+++ b/gtsam/geometry/triangulation.h
@@ -18,8 +18,8 @@
 
 #pragma once
 
-#include 
-#include 
+
+#include 
 #include 
 #include 
 #include 
@@ -52,7 +52,7 @@ public:
  * @param rank_tol SVD rank tolerance
  * @return Triangulated Point3
  */
-GTSAM_UNSTABLE_EXPORT Point3 triangulateDLT(
+GTSAM_EXPORT Point3 triangulateDLT(
     const std::vector& projection_matrices,
     const std::vector& measurements, double rank_tol);
 
@@ -120,7 +120,7 @@ std::pair triangulationGraph(
  * @param landmarkKey to refer to landmark
  * @return refined Point3
  */
-GTSAM_UNSTABLE_EXPORT Point3 optimize(const NonlinearFactorGraph& graph,
+GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph& graph,
     const Values& values, Key landmarkKey);
 
 /**
diff --git a/gtsam/inference/VariableIndex-inl.h b/gtsam/inference/VariableIndex-inl.h
index a88ea5d57..82eb85c76 100644
--- a/gtsam/inference/VariableIndex-inl.h
+++ b/gtsam/inference/VariableIndex-inl.h
@@ -23,43 +23,35 @@ namespace gtsam {
 
 /* ************************************************************************* */
 template
-void VariableIndex::augment(const FG& factors, boost::optional&> newFactorIndices)
-{
+void VariableIndex::augment(const FG& factors,
+    boost::optional&> newFactorIndices) {
   gttic(VariableIndex_augment);
 
   // Augment index for each factor
-  for(size_t i = 0; i < factors.size(); ++i)
-  {
-    if(factors[i])
-    {
+  for (size_t i = 0; i < factors.size(); ++i) {
+    if (factors[i]) {
       const size_t globalI =
-        newFactorIndices ?
-        (*newFactorIndices)[i] :
-        nFactors_;
-      BOOST_FOREACH(const Key key, *factors[i])
-      {
+          newFactorIndices ? (*newFactorIndices)[i] : nFactors_;
+      BOOST_FOREACH(const Key key, *factors[i]) {
         index_[key].push_back(globalI);
-        ++ nEntries_;
+        ++nEntries_;
       }
     }
 
     // Increment factor count even if factors are null, to keep indices consistent
-    if(newFactorIndices)
-    {
-      if((*newFactorIndices)[i] >= nFactors_)
+    if (newFactorIndices) {
+      if ((*newFactorIndices)[i] >= nFactors_)
         nFactors_ = (*newFactorIndices)[i] + 1;
-    }
-    else
-    {
-      ++ nFactors_;
+    } else {
+      ++nFactors_;
     }
   }
 }
 
 /* ************************************************************************* */
 template
-void VariableIndex::remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG& factors)
-{
+void VariableIndex::remove(ITERATOR firstFactor, ITERATOR lastFactor,
+    const FG& factors) {
   gttic(VariableIndex_remove);
 
   // NOTE: We intentionally do not decrement nFactors_ because the factor
@@ -68,17 +60,20 @@ void VariableIndex::remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG&
   // one greater than the highest-numbered factor referenced in a VariableIndex.
   ITERATOR factorIndex = firstFactor;
   size_t i = 0;
-  for( ; factorIndex != lastFactor; ++factorIndex, ++i) {
-    if(i >= factors.size())
-      throw std::invalid_argument("Internal error, requested inconsistent number of factor indices and factors in VariableIndex::remove");
-    if(factors[i]) {
+  for (; factorIndex != lastFactor; ++factorIndex, ++i) {
+    if (i >= factors.size())
+      throw std::invalid_argument(
+          "Internal error, requested inconsistent number of factor indices and factors in VariableIndex::remove");
+    if (factors[i]) {
       BOOST_FOREACH(Key j, *factors[i]) {
         Factors& factorEntries = internalAt(j);
-        Factors::iterator entry = std::find(factorEntries.begin(), factorEntries.end(), *factorIndex);
-        if(entry == factorEntries.end())
-          throw std::invalid_argument("Internal error, indices and factors passed into VariableIndex::remove are not consistent with the existing variable index");
+        Factors::iterator entry = std::find(factorEntries.begin(),
+            factorEntries.end(), *factorIndex);
+        if (entry == factorEntries.end())
+          throw std::invalid_argument(
+              "Internal error, indices and factors passed into VariableIndex::remove are not consistent with the existing variable index");
         factorEntries.erase(entry);
-        -- nEntries_;
+        --nEntries_;
       }
     }
   }
@@ -87,10 +82,11 @@ void VariableIndex::remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG&
 /* ************************************************************************* */
 template
 void VariableIndex::removeUnusedVariables(ITERATOR firstKey, ITERATOR lastKey) {
-  for(ITERATOR key = firstKey; key != lastKey; ++key) {
+  for (ITERATOR key = firstKey; key != lastKey; ++key) {
     KeyMap::iterator entry = index_.find(*key);
-    if(!entry->second.empty())
-      throw std::invalid_argument("Asking to remove variables from the variable index that are not unused");
+    if (!entry->second.empty())
+      throw std::invalid_argument(
+          "Asking to remove variables from the variable index that are not unused");
     index_.erase(entry);
   }
 }
diff --git a/gtsam/linear/GaussianFactorGraph.cpp b/gtsam/linear/GaussianFactorGraph.cpp
index d6e4663e3..d6836783b 100644
--- a/gtsam/linear/GaussianFactorGraph.cpp
+++ b/gtsam/linear/GaussianFactorGraph.cpp
@@ -70,7 +70,7 @@ namespace gtsam {
       vector dims_accumulated;
       dims_accumulated.resize(dims.size()+1,0);
       dims_accumulated[0]=0;
-      for (int i=1; i checkIfDiagonal(const Matrix M) {
+boost::optional checkIfDiagonal(const Matrix M) {
   size_t m = M.rows(), n = M.cols();
   // check all non-diagonal entries
   bool full = false;
@@ -74,23 +74,46 @@ static boost::optional checkIfDiagonal(const Matrix M) {
 /* ************************************************************************* */
 Gaussian::shared_ptr Gaussian::SqrtInformation(const Matrix& R, bool smart) {
   size_t m = R.rows(), n = R.cols();
-  if (m != n) throw invalid_argument("Gaussian::SqrtInformation: R not square");
+  if (m != n)
+    throw invalid_argument("Gaussian::SqrtInformation: R not square");
   boost::optional diagonal = boost::none;
   if (smart)
     diagonal = checkIfDiagonal(R);
-  if (diagonal) return Diagonal::Sigmas(reciprocal(*diagonal),true);
-  else return shared_ptr(new Gaussian(R.rows(),R));
+  if (diagonal)
+    return Diagonal::Sigmas(reciprocal(*diagonal), true);
+  else
+    return shared_ptr(new Gaussian(R.rows(), R));
 }
 
 /* ************************************************************************* */
-Gaussian::shared_ptr Gaussian::Covariance(const Matrix& covariance, bool smart) {
+Gaussian::shared_ptr Gaussian::Information(const Matrix& M, bool smart) {
+  size_t m = M.rows(), n = M.cols();
+  if (m != n)
+    throw invalid_argument("Gaussian::Information: R not square");
+  boost::optional diagonal = boost::none;
+  if (smart)
+    diagonal = checkIfDiagonal(M);
+  if (diagonal)
+    return Diagonal::Precisions(*diagonal, true);
+  else {
+    Matrix R = RtR(M);
+    return shared_ptr(new Gaussian(R.rows(), R));
+  }
+}
+
+/* ************************************************************************* */
+Gaussian::shared_ptr Gaussian::Covariance(const Matrix& covariance,
+    bool smart) {
   size_t m = covariance.rows(), n = covariance.cols();
-  if (m != n) throw invalid_argument("Gaussian::Covariance: covariance not square");
+  if (m != n)
+    throw invalid_argument("Gaussian::Covariance: covariance not square");
   boost::optional variances = boost::none;
   if (smart)
     variances = checkIfDiagonal(covariance);
-  if (variances) return Diagonal::Variances(*variances,true);
-  else return shared_ptr(new Gaussian(n, inverse_square_root(covariance)));
+  if (variances)
+    return Diagonal::Variances(*variances, true);
+  else
+    return shared_ptr(new Gaussian(n, inverse_square_root(covariance)));
 }
 
 /* ************************************************************************* */
diff --git a/gtsam/linear/NoiseModel.h b/gtsam/linear/NoiseModel.h
index e709ea543..0351cfabd 100644
--- a/gtsam/linear/NoiseModel.h
+++ b/gtsam/linear/NoiseModel.h
@@ -164,6 +164,13 @@ namespace gtsam {
        */
       static shared_ptr SqrtInformation(const Matrix& R, bool smart = true);
 
+      /**
+       * A Gaussian noise model created by specifying an information matrix.
+       * @param M The information matrix
+       * @param smart check if can be simplified to derived class
+       */
+      static shared_ptr Information(const Matrix& M, bool smart = true);
+
       /**
        * A Gaussian noise model created by specifying a covariance matrix.
        * @param covariance The square covariance Matrix
@@ -864,6 +871,9 @@ namespace gtsam {
         ar & boost::serialization::make_nvp("noise_", const_cast(noise_));
       }
     };
+    
+    // Helper function
+    GTSAM_EXPORT boost::optional checkIfDiagonal(const Matrix M);
 
   } // namespace noiseModel
 
diff --git a/gtsam/linear/tests/testNoiseModel.cpp b/gtsam/linear/tests/testNoiseModel.cpp
index d68caeabe..df0f8a774 100644
--- a/gtsam/linear/tests/testNoiseModel.cpp
+++ b/gtsam/linear/tests/testNoiseModel.cpp
@@ -285,6 +285,17 @@ TEST(NoiseModel, SmartSqrtInformation2 )
   EXPECT(assert_equal(*expected,*actual));
 }
 
+/* ************************************************************************* */
+TEST(NoiseModel, SmartInformation )
+{
+  bool smart = true;
+  gtsam::SharedGaussian expected = Unit::Isotropic::Variance(3,2);
+  Matrix M = 0.5*eye(3);
+  EXPECT(checkIfDiagonal(M));
+  gtsam::SharedGaussian actual = Gaussian::Information(M, smart);
+  EXPECT(assert_equal(*expected,*actual));
+}
+
 /* ************************************************************************* */
 TEST(NoiseModel, SmartCovariance )
 {
diff --git a/gtsam/navigation/MagFactor.h b/gtsam/navigation/MagFactor.h
index 79677c0c6..44f543bc9 100644
--- a/gtsam/navigation/MagFactor.h
+++ b/gtsam/navigation/MagFactor.h
@@ -54,8 +54,11 @@ public:
   static Point3 unrotate(const Rot2& R, const Point3& p,
       boost::optional HR = boost::none) {
     Point3 q = Rot3::yaw(R.theta()).unrotate(p, HR);
-    if (HR)
-      *HR = HR->col(2);
+    if (HR) {
+      // assign to temporary first to avoid error in Win-Debug mode
+      Matrix H = HR->col(2);
+      *HR = H;
+    }
     return q;
   }
 
diff --git a/gtsam/nonlinear/LagoInitializer.h b/gtsam/nonlinear/LagoInitializer.h
deleted file mode 100644
index b351365c1..000000000
--- a/gtsam/nonlinear/LagoInitializer.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ----------------------------------------------------------------------------
-
- * 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  LagoInitializer.h
- *  @brief Initialize Pose2 in a factor graph using LAGO
- *  (Linear Approximation for Graph Optimization). see papers:
- *
- *  L. Carlone, R. Aragues, J. Castellanos, and B. Bona, A fast and accurate
- *  approximation for planar pose graph optimization, IJRR, 2014.
- *
- *  L. Carlone, R. Aragues, J.A. Castellanos, and B. Bona, A linear approximation
- *  for graph-based simultaneous localization and mapping, RSS, 2011.
- *
- *  @param graph: nonlinear factor graph (can include arbitrary factors but we assume
- *  that there is a subgraph involving Pose2 and betweenFactors). Also in the current
- *  version we assume that there is an odometric spanning path (x0->x1, x1->x2, etc)
- *  and a prior on x0. This assumption can be relaxed by using the extra argument
- *  useOdometricPath = false, although this part of code is not stable yet.
- *  @return Values: initial guess from LAGO (only pose2 are initialized)
- *
- *  @author Luca Carlone
- *  @author Frank Dellaert
- *  @date   May 14, 2014
- */
-
-#pragma once
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-namespace gtsam {
-
-typedef std::map key2doubleMap;
-const Key keyAnchor = symbol('Z',9999999);
-noiseModel::Diagonal::shared_ptr priorOrientationNoise = noiseModel::Diagonal::Variances((Vector(1) << 1e-8));
-noiseModel::Diagonal::shared_ptr priorPose2Noise = noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
-
-/*  This function computes the cumulative orientation (without wrapping) wrt the root of a spanning tree (tree)
- *  for a node (nodeKey). The function starts at the nodes and moves towards the root
- *  summing up the (directed) rotation measurements. Relative measurements are encoded in "deltaThetaMap"
- *  The root is assumed to have orientation zero.
- */
-GTSAM_EXPORT double computeThetaToRoot(const Key nodeKey, const PredecessorMap& tree,
-    const key2doubleMap& deltaThetaMap, const key2doubleMap& thetaFromRootMap);
-
-/*  This function computes the cumulative orientations (without wrapping)
- *  for all node wrt the root (root has zero orientation)
- */
-GTSAM_EXPORT key2doubleMap computeThetasToRoot(const key2doubleMap& deltaThetaMap,
-    const PredecessorMap& tree);
-
-/*  Given a factor graph "g", and a spanning tree "tree", the function selects the nodes belonging to the tree and to g,
- *  and stores the factor slots corresponding to edges in the tree and to chordsIds wrt this tree
- *  Also it computes deltaThetaMap which is a fast way to encode relative orientations along the tree:
- *  for a node key2, s.t. tree[key2]=key1, the values deltaThetaMap[key2] is the relative orientation theta[key2]-theta[key1]
- */
-GTSAM_EXPORT void getSymbolicGraph(
-    /*OUTPUTS*/ std::vector& spanningTreeIds, std::vector& chordsIds, key2doubleMap& deltaThetaMap,
-    /*INPUTS*/ const PredecessorMap& tree, const NonlinearFactorGraph& g);
-
-/*  Retrieves the deltaTheta and the corresponding noise model from a BetweenFactor */
-GTSAM_EXPORT void getDeltaThetaAndNoise(NonlinearFactor::shared_ptr factor,
-    Vector& deltaTheta, noiseModel::Diagonal::shared_ptr& model_deltaTheta);
-
-/*  Linear factor graph with regularized orientation measurements */
-GTSAM_EXPORT GaussianFactorGraph buildLinearOrientationGraph(const std::vector& spanningTreeIds, const std::vector& chordsIds,
-    const NonlinearFactorGraph& g, const key2doubleMap& orientationsToRoot, const PredecessorMap& tree);
-
-/* Selects the subgraph of betweenFactors and transforms priors into between wrt a fictitious node */
-GTSAM_EXPORT NonlinearFactorGraph buildPose2graph(const NonlinearFactorGraph& graph);
-
-/* Returns the orientations of a graph including only BetweenFactors */
-GTSAM_EXPORT VectorValues computeLagoOrientations(const NonlinearFactorGraph& pose2Graph, bool useOdometricPath = true);
-
-/*  LAGO: Returns the orientations of the Pose2 in a generic factor graph */
-GTSAM_EXPORT VectorValues initializeOrientationsLago(const NonlinearFactorGraph& graph, bool useOdometricPath = true);
-
-/*  Returns the values for the Pose2 in a generic factor graph */
-GTSAM_EXPORT Values initializeLago(const NonlinearFactorGraph& graph, bool useOdometricPath = true);
-
-/*  Only corrects the orientation part in initialGuess */
-GTSAM_EXPORT Values initializeLago(const NonlinearFactorGraph& graph, const Values& initialGuess);
-
-} // end of namespace gtsam
diff --git a/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp b/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp
index 2cde6768f..08961db86 100644
--- a/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp
+++ b/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp
@@ -244,7 +244,7 @@ void LevenbergMarquardtOptimizer::iterate() {
     try {
       delta = solve(dampedSystem, state_.values, params_);
       systemSolvedSuccessfully = true;
-    } catch (IndeterminantLinearSystemException& e) {
+    } catch (IndeterminantLinearSystemException) {
       systemSolvedSuccessfully = false;
     }
 
diff --git a/gtsam_unstable/slam/ImplicitSchurFactor.h b/gtsam/slam/ImplicitSchurFactor.h
similarity index 100%
rename from gtsam_unstable/slam/ImplicitSchurFactor.h
rename to gtsam/slam/ImplicitSchurFactor.h
diff --git a/gtsam_unstable/slam/JacobianFactorQ.h b/gtsam/slam/JacobianFactorQ.h
similarity index 100%
rename from gtsam_unstable/slam/JacobianFactorQ.h
rename to gtsam/slam/JacobianFactorQ.h
diff --git a/gtsam_unstable/slam/JacobianFactorQR.h b/gtsam/slam/JacobianFactorQR.h
similarity index 96%
rename from gtsam_unstable/slam/JacobianFactorQR.h
rename to gtsam/slam/JacobianFactorQR.h
index 2d2d5b7a4..a928106a8 100644
--- a/gtsam_unstable/slam/JacobianFactorQR.h
+++ b/gtsam/slam/JacobianFactorQR.h
@@ -6,7 +6,7 @@
  */
 
 #pragma once
-#include 
+#include 
 
 namespace gtsam {
 /**
diff --git a/gtsam_unstable/slam/JacobianFactorSVD.h b/gtsam/slam/JacobianFactorSVD.h
similarity index 97%
rename from gtsam_unstable/slam/JacobianFactorSVD.h
rename to gtsam/slam/JacobianFactorSVD.h
index e8ade3b1b..e28185038 100644
--- a/gtsam_unstable/slam/JacobianFactorSVD.h
+++ b/gtsam/slam/JacobianFactorSVD.h
@@ -5,7 +5,7 @@
  */
 
 #pragma once
-#include "gtsam_unstable/slam/JacobianSchurFactor.h"
+#include "gtsam/slam/JacobianSchurFactor.h"
 
 namespace gtsam {
 /**
diff --git a/gtsam_unstable/slam/JacobianSchurFactor.h b/gtsam/slam/JacobianSchurFactor.h
similarity index 100%
rename from gtsam_unstable/slam/JacobianSchurFactor.h
rename to gtsam/slam/JacobianSchurFactor.h
diff --git a/gtsam_unstable/slam/RegularHessianFactor.h b/gtsam/slam/RegularHessianFactor.h
similarity index 100%
rename from gtsam_unstable/slam/RegularHessianFactor.h
rename to gtsam/slam/RegularHessianFactor.h
diff --git a/gtsam_unstable/slam/SmartFactorBase.h b/gtsam/slam/SmartFactorBase.h
similarity index 99%
rename from gtsam_unstable/slam/SmartFactorBase.h
rename to gtsam/slam/SmartFactorBase.h
index 93931549f..1235fc6fb 100644
--- a/gtsam_unstable/slam/SmartFactorBase.h
+++ b/gtsam/slam/SmartFactorBase.h
@@ -325,7 +325,7 @@ public:
       const Cameras& cameras, const Point3& point,
       const double lambda = 0.0) const {
 
-    int numKeys = this->keys_.size();
+    size_t numKeys = this->keys_.size();
     std::vector Fblocks;
     double f = computeJacobians(Fblocks, E, PointCov, b, cameras, point,
         lambda);
@@ -352,7 +352,7 @@ public:
     Eigen::JacobiSVD svd(E, Eigen::ComputeFullU);
     Vector s = svd.singularValues();
     // Enull = zeros(2 * numKeys, 2 * numKeys - 3);
-    int numKeys = this->keys_.size();
+    size_t numKeys = this->keys_.size();
     Enull = svd.matrixU().block(0, 3, 2 * numKeys, 2 * numKeys - 3); // last 2m-3 columns
 
     return f;
diff --git a/gtsam_unstable/slam/SmartProjectionFactor.h b/gtsam/slam/SmartProjectionFactor.h
similarity index 99%
rename from gtsam_unstable/slam/SmartProjectionFactor.h
rename to gtsam/slam/SmartProjectionFactor.h
index 2124dd6f6..043528fea 100644
--- a/gtsam_unstable/slam/SmartProjectionFactor.h
+++ b/gtsam/slam/SmartProjectionFactor.h
@@ -21,11 +21,10 @@
 
 #include "SmartFactorBase.h"
 
-#include 
+#include 
 #include 
 #include 
 #include 
-#include 
 
 #include 
 #include 
@@ -54,7 +53,7 @@ public:
   double f;
 };
 
-enum linearizationType {
+enum LinearizationMode {
   HESSIAN, JACOBIAN_SVD, JACOBIAN_Q
 };
 
@@ -263,7 +262,7 @@ public:
           try {
             Point2 reprojectionError(camera.project(point_) - zi);
             totalReprojError += reprojectionError.vector().norm();
-          } catch (CheiralityException& e) {
+          } catch (CheiralityException) {
             cheiralityException_ = true;
           }
           i += 1;
diff --git a/gtsam_unstable/slam/SmartProjectionPoseFactor.h b/gtsam/slam/SmartProjectionPoseFactor.h
similarity index 81%
rename from gtsam_unstable/slam/SmartProjectionPoseFactor.h
rename to gtsam/slam/SmartProjectionPoseFactor.h
index 66497d28d..273102bda 100644
--- a/gtsam_unstable/slam/SmartProjectionPoseFactor.h
+++ b/gtsam/slam/SmartProjectionPoseFactor.h
@@ -41,9 +41,8 @@ template
 class SmartProjectionPoseFactor: public SmartProjectionFactor {
 protected:
 
-  linearizationType linearizeTo_;
+  LinearizationMode linearizeTo_;  ///< How to linearize the factor (HESSIAN, JACOBIAN_SVD, JACOBIAN_Q)
 
-  // Known calibration
   std::vector > K_all_; ///< shared pointer to calibration object (one for each camera)
 
 public:
@@ -69,7 +68,7 @@ public:
   SmartProjectionPoseFactor(const double rankTol = 1,
       const double linThreshold = -1, const bool manageDegeneracy = false,
       const bool enableEPI = false, boost::optional body_P_sensor = boost::none,
-      linearizationType linearizeTo = HESSIAN, double landmarkDistanceThreshold = 1e10,
+      LinearizationMode linearizeTo = HESSIAN, double landmarkDistanceThreshold = 1e10,
       double dynamicOutlierRejectionThreshold = -1) :
         Base(rankTol, linThreshold, manageDegeneracy, enableEPI, body_P_sensor,
         landmarkDistanceThreshold, dynamicOutlierRejectionThreshold), linearizeTo_(linearizeTo) {}
@@ -80,7 +79,7 @@ public:
   /**
    * add a new measurement and pose key
    * @param measured is the 2m dimensional location of the projection of a single landmark in the m view (the measurement)
-   * @param poseKey is the index corresponding to the camera observing the same landmark
+   * @param poseKey is key corresponding to the camera observing the same landmark
    * @param noise_i is the measurement noise
    * @param K_i is the (known) camera calibration
    */
@@ -92,8 +91,11 @@ public:
   }
 
   /**
-   * add a new measurements and pose keys
-   * Variant of the previous one in which we include a set of measurements
+   *  Variant of the previous one in which we include a set of measurements
+   * @param measurements vector of the 2m dimensional location of the projection of a single landmark in the m view (the measurement)
+   * @param poseKeys vector of keys corresponding to the camera observing the same landmark
+   * @param noises vector of measurement noises
+   * @param Ks vector of calibration objects
    */
   void add(std::vector measurements, std::vector poseKeys,
       std::vector noises,
@@ -105,8 +107,11 @@ public:
   }
 
   /**
-   * add a new measurements and pose keys
    * Variant of the previous one in which we include a set of measurements with the same noise and calibration
+   * @param mmeasurements vector of the 2m dimensional location of the projection of a single landmark in the m view (the measurement)
+   * @param poseKeys vector of keys corresponding to the camera observing the same landmark
+   * @param noise measurement noise (same for all measurements)
+   * @param K the (known) camera calibration (same for all measurements)
    */
   void add(std::vector measurements, std::vector poseKeys,
       const SharedNoiseModel noise, const boost::shared_ptr K) {
@@ -141,7 +146,12 @@ public:
     return 6 * this->keys_.size();
   }
 
-  // Collect all cameras
+  /**
+   * Collect all cameras involved in this factor
+   * @param values Values structure which must contain camera poses corresponding
+   * to keys involved in this factor
+   * @return vector of Values
+   */
   typename Base::Cameras cameras(const Values& values) const {
     typename Base::Cameras cameras;
     size_t i=0;
@@ -154,7 +164,9 @@ public:
   }
 
   /**
-   * linear factor on the poses
+   * Linearize to Gaussian Factor
+   * @param values Values structure which must contain camera poses for this factor
+   * @return
    */
   virtual boost::shared_ptr linearize(
       const Values& values) const {
@@ -184,7 +196,7 @@ public:
   }
 
   /** return the calibration object */
-  inline const boost::shared_ptr calibration() const {
+  inline const std::vector > calibration() const {
     return K_all_;
   }
 
diff --git a/gtsam/slam/dataset.cpp b/gtsam/slam/dataset.cpp
index f381a0786..b3c9b9557 100644
--- a/gtsam/slam/dataset.cpp
+++ b/gtsam/slam/dataset.cpp
@@ -16,18 +16,18 @@
  * @brief utility functions for loading datasets
  */
 
-#include 
-#include 
-#include 
-
-#include 
-
-#include 
-#include 
-#include 
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
 
 using namespace std;
 namespace fs = boost::filesystem;
@@ -43,7 +43,7 @@ string findExampleDataFile(const string& name) {
   // Search source tree and installed location
   vector rootsToSearch;
   rootsToSearch.push_back(GTSAM_SOURCE_TREE_DATASET_DIR); // Defined by CMake, see gtsam/gtsam/CMakeLists.txt
-  rootsToSearch.push_back(GTSAM_INSTALLED_DATASET_DIR);   // Defined by CMake, see gtsam/gtsam/CMakeLists.txt
+  rootsToSearch.push_back(GTSAM_INSTALLED_DATASET_DIR); // Defined by CMake, see gtsam/gtsam/CMakeLists.txt
 
   // Search for filename as given, and with .graph and .txt extensions
   vector namesToSearch;
@@ -55,35 +55,122 @@ string findExampleDataFile(const string& name) {
   // Find first name that exists
   BOOST_FOREACH(const fs::path& root, rootsToSearch) {
     BOOST_FOREACH(const fs::path& name, namesToSearch) {
-      if(fs::is_regular_file(root / name))
+      if (fs::is_regular_file(root / name))
         return (root / name).string();
     }
   }
 
   // If we did not return already, then we did not find the file
-  throw std::invalid_argument(
-      "gtsam::findExampleDataFile could not find a matching file in\n"
-      SOURCE_TREE_DATASET_DIR " or\n"
-      INSTALLED_DATASET_DIR " named\n" +
-      name + ", " + name + ".graph, or " + name + ".txt");
+  throw
+invalid_argument(
+    "gtsam::findExampleDataFile could not find a matching file in\n"
+    SOURCE_TREE_DATASET_DIR " or\n"
+    INSTALLED_DATASET_DIR " named\n" +
+    name + ", " + name + ".graph, or " + name + ".txt");
 }
+
+/* ************************************************************************* */
+string createRewrittenFileName(const string& name) {
+  // Search source tree and installed location
+  if (!exists(fs::path(name))) {
+    throw invalid_argument(
+        "gtsam::createRewrittenFileName could not find a matching file in\n"
+            + name);
+  }
+
+  fs::path p(name);
+  fs::path newpath = fs::path(p.parent_path().string())
+      / fs::path(p.stem().string() + "-rewritten.txt");
+
+  return newpath.string();
+}
+/* ************************************************************************* */
+
 #endif
 
 /* ************************************************************************* */
-pair load2D(
-    pair > dataset,
-    int maxID, bool addNoise, bool smart) {
-  return load2D(dataset.first, dataset.second, maxID, addNoise, smart);
+GraphAndValues load2D(pair dataset, int maxID,
+    bool addNoise, bool smart, NoiseFormat noiseFormat,
+    KernelFunctionType kernelFunctionType) {
+  return load2D(dataset.first, dataset.second, maxID, addNoise, smart,
+      noiseFormat, kernelFunctionType);
 }
 
 /* ************************************************************************* */
-pair load2D(
-    const string& filename, boost::optional model, int maxID,
-    bool addNoise, bool smart) {
-  cout << "Will try to read " << filename << endl;
+// Read noise parameters and interpret them according to flags
+static SharedNoiseModel readNoiseModel(ifstream& is, bool smart,
+    NoiseFormat noiseFormat, KernelFunctionType kernelFunctionType) {
+  double v1, v2, v3, v4, v5, v6;
+  is >> v1 >> v2 >> v3 >> v4 >> v5 >> v6;
+
+  // Read matrix and check that diagonal entries are non-zero
+  Matrix M(3, 3);
+  switch (noiseFormat) {
+  case NoiseFormatG2O:
+  case NoiseFormatCOV:
+    // i.e., [ v1 v2 v3; v2' v4 v5; v3' v5' v6 ]
+    if (v1 == 0.0 || v4 == 0.0 || v6 == 0.0)
+      throw runtime_error(
+          "load2D::readNoiseModel looks like this is not G2O matrix order");
+    M << v1, v2, v3, v2, v4, v5, v3, v5, v6;
+    break;
+  case NoiseFormatTORO:
+  case NoiseFormatGRAPH:
+    // http://www.openslam.org/toro.html
+    // inf_ff inf_fs inf_ss inf_rr inf_fr inf_sr
+    // i.e., [ v1 v2 v5; v2' v3 v6; v5' v6' v4 ]
+    if (v1 == 0.0 || v3 == 0.0 || v4 == 0.0)
+      throw invalid_argument(
+          "load2D::readNoiseModel looks like this is not TORO matrix order");
+    M << v1, v2, v5, v2, v3, v6, v5, v6, v4;
+    break;
+  default:
+    throw runtime_error("load2D: invalid noise format");
+  }
+
+  // Now, create a Gaussian noise model
+  // The smart flag will try to detect a simpler model, e.g., unit
+  SharedNoiseModel model;
+  switch (noiseFormat) {
+  case NoiseFormatG2O:
+  case NoiseFormatTORO:
+    // In both cases, what is stored in file is the information matrix
+    model = noiseModel::Gaussian::Information(M, smart);
+    break;
+  case NoiseFormatGRAPH:
+  case NoiseFormatCOV:
+    // These cases expect covariance matrix
+    model = noiseModel::Gaussian::Covariance(M, smart);
+    break;
+  default:
+    throw invalid_argument("load2D: invalid noise format");
+  }
+
+  switch (kernelFunctionType) {
+  case KernelFunctionTypeNONE:
+    return model;
+    break;
+  case KernelFunctionTypeHUBER:
+    return noiseModel::Robust::Create(
+        noiseModel::mEstimator::Huber::Create(1.345), model);
+    break;
+  case KernelFunctionTypeTUKEY:
+    return noiseModel::Robust::Create(
+        noiseModel::mEstimator::Tukey::Create(4.6851), model);
+    break;
+  default:
+    throw invalid_argument("load2D: invalid kernel function type");
+  }
+}
+
+/* ************************************************************************* */
+GraphAndValues load2D(const string& filename, SharedNoiseModel model, int maxID,
+    bool addNoise, bool smart, NoiseFormat noiseFormat,
+    KernelFunctionType kernelFunctionType) {
+
   ifstream is(filename.c_str());
   if (!is)
-    throw std::invalid_argument("load2D: can not find the file!");
+    throw invalid_argument("load2D: can not find file " + filename);
 
   Values::shared_ptr initial(new Values);
   NonlinearFactorGraph::shared_ptr graph(new NonlinearFactorGraph);
@@ -92,16 +179,18 @@ pair load2D(
 
   // load the poses
   while (is) {
-    if(! (is >> tag))
+    if (!(is >> tag))
       break;
 
-    if ((tag == "VERTEX2") || (tag == "VERTEX")) {
+    if ((tag == "VERTEX2") || (tag == "VERTEX_SE2") || (tag == "VERTEX")) {
       int id;
       double x, y, yaw;
       is >> id >> x >> y >> yaw;
+
       // optional filter
       if (maxID && id >= maxID)
         continue;
+
       initial->insert(id, Pose2(x, y, yaw));
     }
     is.ignore(LINESIZE, '\n');
@@ -109,54 +198,47 @@ pair load2D(
   is.clear(); /* clears the end-of-file and error flags */
   is.seekg(0, ios::beg);
 
-  // Create a sampler with random number generator
-  Sampler sampler(42u);
+  // If asked, create a sampler with random number generator
+  Sampler sampler;
+  if (addNoise) {
+    noiseModel::Diagonal::shared_ptr noise;
+    if (model)
+      noise = boost::dynamic_pointer_cast(model);
+    if (!noise)
+      throw invalid_argument(
+          "gtsam::load2D: invalid noise model for adding noise"
+              "(current version assumes diagonal noise model)!");
+    sampler = Sampler(noise);
+  }
 
   // Parse the pose constraints
   int id1, id2;
   bool haveLandmark = false;
   while (is) {
-    if(! (is >> tag))
+    if (!(is >> tag))
       break;
 
-    if ((tag == "EDGE2") || (tag == "EDGE") || (tag == "ODOMETRY")) {
+    if ((tag == "EDGE2") || (tag == "EDGE") || (tag == "EDGE_SE2")
+        || (tag == "ODOMETRY")) {
+
+      // Read transform
       double x, y, yaw;
-      double v1, v2, v3, v4, v5, v6;
-
       is >> id1 >> id2 >> x >> y >> yaw;
-      is >> v1 >> v2 >> v3 >> v4 >> v5 >> v6;
+      Pose2 l1Xl2(x, y, yaw);
 
-      // Try to guess covariance matrix layout
-      Matrix m(3,3);
-      if(v1 != 0.0 && v2 == 0.0 && v3 != 0.0 && v4 != 0.0 && v5 == 0.0 && v6 == 0.0)
-      {
-        // Looks like [ v1 v2 v5; v2' v3 v6; v5' v6' v4 ]
-        m <<  v1, v2, v5,  v2, v3, v6,  v5, v6, v4;
-      }
-      else if(v1 != 0.0 && v2 == 0.0 && v3 == 0.0 && v4 != 0.0 && v5 == 0.0 && v6 != 0.0)
-      {
-        // Looks like [ v1 v2 v3; v2' v4 v5; v3' v5' v6 ]
-        m << v1, v2, v3,  v2, v4, v5,  v3, v5, v6;
-      }
-      else
-      {
-        throw std::invalid_argument("load2D: unrecognized covariance matrix format in dataset file");
-      }
+      // read noise model
+      SharedNoiseModel modelInFile = readNoiseModel(is, smart, noiseFormat,
+          kernelFunctionType);
 
       // optional filter
       if (maxID && (id1 >= maxID || id2 >= maxID))
         continue;
 
-      Pose2 l1Xl2(x, y, yaw);
-
-      // SharedNoiseModel noise = noiseModel::Gaussian::Covariance(m, smart);
-      if (!model) {
-        Vector variances = (Vector(3) << m(0, 0), m(1, 1), m(2, 2));
-        model = noiseModel::Diagonal::Variances(variances, smart);
-      }
+      if (!model)
+        model = modelInFile;
 
       if (addNoise)
-        l1Xl2 = l1Xl2.retract(sampler.sampleNewModel(*model));
+        l1Xl2 = l1Xl2.retract(sampler.sample());
 
       // Insert vertices if pure odometry file
       if (!initial->exists(id1))
@@ -165,7 +247,7 @@ pair load2D(
         initial->insert(id2, initial->at(id1) * l1Xl2);
 
       NonlinearFactor::shared_ptr factor(
-          new BetweenFactor(id1, id2, l1Xl2, *model));
+          new BetweenFactor(id1, id2, l1Xl2, model));
       graph->push_back(factor);
     }
 
@@ -185,23 +267,22 @@ pair load2D(
       is >> id1 >> id2 >> lmx >> lmy >> v1 >> v2 >> v3;
 
       // Convert x,y to bearing,range
-      bearing = std::atan2(lmy, lmx);
-      range = std::sqrt(lmx*lmx + lmy*lmy);
+      bearing = atan2(lmy, lmx);
+      range = sqrt(lmx * lmx + lmy * lmy);
 
       // In our experience, the x-y covariance on landmark sightings is not very good, so assume
       // it describes the uncertainty at a range of 10m, and convert that to bearing/range uncertainty.
-      if(std::abs(v1 - v3) < 1e-4)
-      {
+      if (std::abs(v1 - v3) < 1e-4) {
         bearing_std = sqrt(v1 / 10.0);
         range_std = sqrt(v1);
-      }
-      else
-      {
+      } else {
         bearing_std = 1;
         range_std = 1;
-        if(!haveLandmark) {
-          cout << "Warning: load2D is a very simple dataset loader and is ignoring the\n"
-              "non-uniform covariance on LANDMARK measurements in this file." << endl;
+        if (!haveLandmark) {
+          cout
+              << "Warning: load2D is a very simple dataset loader and is ignoring the\n"
+                  "non-uniform covariance on LANDMARK measurements in this file."
+              << endl;
           haveLandmark = true;
         }
       }
@@ -227,7 +308,7 @@ pair load2D(
         initial->insert(id1, Pose2());
       if (!initial->exists(L(id2))) {
         Pose2 pose = initial->at(id1);
-        Point2 local(cos(bearing)*range,sin(bearing)*range);
+        Point2 local(cos(bearing) * range, sin(bearing) * range);
         Point2 global = pose.transform_from(local);
         initial->insert(L(id2), global);
       }
@@ -235,12 +316,15 @@ pair load2D(
     is.ignore(LINESIZE, '\n');
   }
 
-  cout << "load2D read a graph file with " << initial->size()
-      << " vertices and " << graph->nrFactors() << " factors" << endl;
-
   return make_pair(graph, initial);
 }
 
+/* ************************************************************************* */
+GraphAndValues load2D_robust(const string& filename,
+    noiseModel::Base::shared_ptr& model, int maxID) {
+  return load2D(filename, model, maxID);
+}
+
 /* ************************************************************************* */
 void save2D(const NonlinearFactorGraph& graph, const Values& config,
     const noiseModel::Diagonal::shared_ptr model, const string& filename) {
@@ -248,18 +332,16 @@ void save2D(const NonlinearFactorGraph& graph, const Values& config,
   fstream stream(filename.c_str(), fstream::out);
 
   // save poses
-  BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, config)
-  {
+  BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, config) {
     const Pose2& pose = dynamic_cast(key_value.value);
-    stream << "VERTEX2 " << key_value.key << " " << pose.x() << " "
-        << pose.y() << " " << pose.theta() << endl;
+    stream << "VERTEX2 " << key_value.key << " " << pose.x() << " " << pose.y()
+        << " " << pose.theta() << endl;
   }
 
   // save edges
   Matrix R = model->R();
   Matrix RR = trans(R) * R; //prod(trans(R),R);
-  BOOST_FOREACH(boost::shared_ptr factor_, graph)
-  {
+  BOOST_FOREACH(boost::shared_ptr factor_, graph) {
     boost::shared_ptr > factor =
         boost::dynamic_pointer_cast >(factor_);
     if (!factor)
@@ -267,14 +349,62 @@ void save2D(const NonlinearFactorGraph& graph, const Values& config,
 
     Pose2 pose = factor->measured().inverse();
     stream << "EDGE2 " << factor->key2() << " " << factor->key1() << " "
-        << pose.x() << " " << pose.y() << " " << pose.theta() << " "
-        << RR(0, 0) << " " << RR(0, 1) << " " << RR(1, 1) << " "
-        << RR(2, 2) << " " << RR(0, 2) << " " << RR(1, 2) << endl;
+        << pose.x() << " " << pose.y() << " " << pose.theta() << " " << RR(0, 0)
+        << " " << RR(0, 1) << " " << RR(1, 1) << " " << RR(2, 2) << " "
+        << RR(0, 2) << " " << RR(1, 2) << endl;
   }
 
   stream.close();
 }
 
+/* ************************************************************************* */
+GraphAndValues readG2o(const string& g2oFile,
+    KernelFunctionType kernelFunctionType) {
+  // just call load2D
+  int maxID = 0;
+  bool addNoise = false;
+  bool smart = true;
+  return load2D(g2oFile, SharedNoiseModel(), maxID, addNoise, smart,
+      NoiseFormatG2O, kernelFunctionType);
+}
+
+/* ************************************************************************* */
+void writeG2o(const NonlinearFactorGraph& graph, const Values& estimate,
+    const string& filename) {
+
+  fstream stream(filename.c_str(), fstream::out);
+
+  // save poses
+  BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, estimate) {
+    const Pose2& pose = dynamic_cast(key_value.value);
+    stream << "VERTEX_SE2 " << key_value.key << " " << pose.x() << " "
+        << pose.y() << " " << pose.theta() << endl;
+  }
+
+  // save edges
+  BOOST_FOREACH(boost::shared_ptr factor_, graph) {
+    boost::shared_ptr > factor =
+        boost::dynamic_pointer_cast >(factor_);
+    if (!factor)
+      continue;
+
+    SharedNoiseModel model = factor->get_noiseModel();
+    boost::shared_ptr diagonalModel =
+        boost::dynamic_pointer_cast(model);
+    if (!diagonalModel)
+      throw invalid_argument(
+          "writeG2o: invalid noise model (current version assumes diagonal noise model)!");
+
+    Pose2 pose = factor->measured(); //.inverse();
+    stream << "EDGE_SE2 " << factor->key1() << " " << factor->key2() << " "
+        << pose.x() << " " << pose.y() << " " << pose.theta() << " "
+        << diagonalModel->precision(0) << " " << 0.0 << " " << 0.0 << " "
+        << diagonalModel->precision(1) << " " << 0.0 << " "
+        << diagonalModel->precision(2) << endl;
+  }
+  stream.close();
+}
+
 /* ************************************************************************* */
 bool load3D(const string& filename) {
   ifstream is(filename.c_str());
@@ -318,161 +448,60 @@ bool load3D(const string& filename) {
 }
 
 /* ************************************************************************* */
-pair load2D_robust(
-    const string& filename, noiseModel::Base::shared_ptr& model, int maxID) {
-  cout << "Will try to read " << filename << endl;
-  ifstream is(filename.c_str());
-  if (!is)
-    throw std::invalid_argument("load2D: can not find the file!");
-
-  Values::shared_ptr initial(new Values);
-  NonlinearFactorGraph::shared_ptr graph(new NonlinearFactorGraph);
-
-  string tag;
-
-  // load the poses
-  while (is) {
-    is >> tag;
-
-    if ((tag == "VERTEX2") || (tag == "VERTEX")) {
-      int id;
-      double x, y, yaw;
-      is >> id >> x >> y >> yaw;
-      // optional filter
-      if (maxID && id >= maxID)
-        continue;
-      initial->insert(id, Pose2(x, y, yaw));
-    }
-    is.ignore(LINESIZE, '\n');
-  }
-  is.clear(); /* clears the end-of-file and error flags */
-  is.seekg(0, ios::beg);
-
-  // Create a sampler with random number generator
-  Sampler sampler(42u);
-
-  // load the factors
-  while (is) {
-    is >> tag;
-
-    if ((tag == "EDGE2") || (tag == "EDGE") || (tag == "ODOMETRY")) {
-      int id1, id2;
-      double x, y, yaw;
-
-      is >> id1 >> id2 >> x >> y >> yaw;
-      Matrix m = eye(3);
-      is >> m(0, 0) >> m(0, 1) >> m(1, 1) >> m(2, 2) >> m(0, 2) >> m(1, 2);
-      m(2, 0) = m(0, 2);
-      m(2, 1) = m(1, 2);
-      m(1, 0) = m(0, 1);
-
-      // optional filter
-      if (maxID && (id1 >= maxID || id2 >= maxID))
-        continue;
-
-      Pose2 l1Xl2(x, y, yaw);
-
-      // Insert vertices if pure odometry file
-      if (!initial->exists(id1))
-        initial->insert(id1, Pose2());
-      if (!initial->exists(id2))
-        initial->insert(id2, initial->at(id1) * l1Xl2);
-
-      NonlinearFactor::shared_ptr factor(
-          new BetweenFactor(id1, id2, l1Xl2, model));
-      graph->push_back(factor);
-    }
-    if (tag == "BR") {
-      int id1, id2;
-      double bearing, range, bearing_std, range_std;
-
-      is >> id1 >> id2 >> bearing >> range >> bearing_std >> range_std;
-
-      // optional filter
-      if (maxID && (id1 >= maxID || id2 >= maxID))
-        continue;
-
-      noiseModel::Diagonal::shared_ptr measurementNoise =
-          noiseModel::Diagonal::Sigmas((Vector(2) << bearing_std, range_std));
-      *graph += BearingRangeFactor(id1, id2, bearing, range, measurementNoise);
-
-      // Insert poses or points if they do not exist yet
-      if (!initial->exists(id1))
-        initial->insert(id1, Pose2());
-      if (!initial->exists(id2)) {
-        Pose2 pose = initial->at(id1);
-        Point2 local(cos(bearing)*range,sin(bearing)*range);
-        Point2 global = pose.transform_from(local);
-        initial->insert(id2, global);
-      }
-    }
-    is.ignore(LINESIZE, '\n');
-  }
-
-  cout << "load2D read a graph file with " << initial->size()
-                        << " vertices and " << graph->nrFactors() << " factors" << endl;
-
-  return make_pair(graph, initial);
-}
-
-/* ************************************************************************* */
-Rot3 openGLFixedRotation(){ // this is due to different convention for cameras in gtsam and openGL
+Rot3 openGLFixedRotation() { // this is due to different convention for cameras in gtsam and openGL
   /* R = [ 1   0   0
    *       0  -1   0
    *       0   0  -1]
    */
-  Matrix3  R_mat = Matrix3::Zero(3,3);
-  R_mat(0,0) = 1.0;  R_mat(1,1) = -1.0; R_mat(2,2) = -1.0;
+  Matrix3 R_mat = Matrix3::Zero(3, 3);
+  R_mat(0, 0) = 1.0;
+  R_mat(1, 1) = -1.0;
+  R_mat(2, 2) = -1.0;
   return Rot3(R_mat);
 }
 
 /* ************************************************************************* */
-Pose3 openGL2gtsam(const Rot3& R, double tx, double ty, double tz)
-{
+Pose3 openGL2gtsam(const Rot3& R, double tx, double ty, double tz) {
   Rot3 R90 = openGLFixedRotation();
-  Rot3 wRc = (  R.inverse() ).compose(R90);
+  Rot3 wRc = (R.inverse()).compose(R90);
 
   // Our camera-to-world translation wTc = -R'*t
-  return Pose3 (wRc, R.unrotate(Point3(-tx,-ty,-tz)));
+  return Pose3(wRc, R.unrotate(Point3(-tx, -ty, -tz)));
 }
 
 /* ************************************************************************* */
-Pose3 gtsam2openGL(const Rot3& R, double tx, double ty, double tz)
-{
+Pose3 gtsam2openGL(const Rot3& R, double tx, double ty, double tz) {
   Rot3 R90 = openGLFixedRotation();
-  Rot3 cRw_openGL = R90.compose(  R.inverse() );
-  Point3 t_openGL = cRw_openGL.rotate(Point3(-tx,-ty,-tz));
+  Rot3 cRw_openGL = R90.compose(R.inverse());
+  Point3 t_openGL = cRw_openGL.rotate(Point3(-tx, -ty, -tz));
   return Pose3(cRw_openGL, t_openGL);
 }
 
 /* ************************************************************************* */
-Pose3 gtsam2openGL(const Pose3& PoseGTSAM)
-{
-  return gtsam2openGL(PoseGTSAM.rotation(), PoseGTSAM.x(), PoseGTSAM.y(), PoseGTSAM.z());
+Pose3 gtsam2openGL(const Pose3& PoseGTSAM) {
+  return gtsam2openGL(PoseGTSAM.rotation(), PoseGTSAM.x(), PoseGTSAM.y(),
+      PoseGTSAM.z());
 }
 
 /* ************************************************************************* */
-bool readBundler(const string& filename, SfM_data &data)
-{
+bool readBundler(const string& filename, SfM_data &data) {
   // Load the data file
-  ifstream is(filename.c_str(),ifstream::in);
-  if(!is)
-  {
+  ifstream is(filename.c_str(), ifstream::in);
+  if (!is) {
     cout << "Error in readBundler: can not find the file!!" << endl;
     return false;
   }
 
   // Ignore the first line
   char aux[500];
-  is.getline(aux,500);
+  is.getline(aux, 500);
 
   // Get the number of camera poses and 3D points
   size_t nrPoses, nrPoints;
   is >> nrPoses >> nrPoints;
 
   // Get the information for the camera poses
-  for( size_t i = 0; i < nrPoses; i++ )
-  {
+  for (size_t i = 0; i < nrPoses; i++) {
     // Get the focal length and the radial distortion parameters
     float f, k1, k2;
     is >> f >> k1 >> k2;
@@ -482,20 +511,15 @@ bool readBundler(const string& filename, SfM_data &data)
     float r11, r12, r13;
     float r21, r22, r23;
     float r31, r32, r33;
-    is >> r11 >> r12 >> r13
-    >> r21 >> r22 >> r23
-    >> r31 >> r32 >> r33;
+    is >> r11 >> r12 >> r13 >> r21 >> r22 >> r23 >> r31 >> r32 >> r33;
 
     // Bundler-OpenGL rotation matrix
-    Rot3 R(
-        r11, r12, r13,
-        r21, r22, r23,
-        r31, r32, r33);
+    Rot3 R(r11, r12, r13, r21, r22, r23, r31, r32, r33);
 
     // Check for all-zero R, in which case quit
-    if(r11==0 && r12==0 && r13==0)
-    {
-      cout << "Error in readBundler: zero rotation matrix for pose " << i << endl;
+    if (r11 == 0 && r12 == 0 && r13 == 0) {
+      cout << "Error in readBundler: zero rotation matrix for pose " << i
+          << endl;
       return false;
     }
 
@@ -503,38 +527,36 @@ bool readBundler(const string& filename, SfM_data &data)
     float tx, ty, tz;
     is >> tx >> ty >> tz;
 
-    Pose3 pose = openGL2gtsam(R,tx,ty,tz);
+    Pose3 pose = openGL2gtsam(R, tx, ty, tz);
 
-    data.cameras.push_back(SfM_Camera(pose,K));
+    data.cameras.push_back(SfM_Camera(pose, K));
   }
 
   // Get the information for the 3D points
-  for( size_t j = 0; j < nrPoints; j++ )
-  {
+  for (size_t j = 0; j < nrPoints; j++) {
     SfM_Track track;
 
     // Get the 3D position
     float x, y, z;
     is >> x >> y >> z;
-    track.p = Point3(x,y,z);
+    track.p = Point3(x, y, z);
 
     // Get the color information
     float r, g, b;
     is >> r >> g >> b;
-    track.r = r/255.f;
-    track.g = g/255.f;
-    track.b = b/255.f;
+    track.r = r / 255.f;
+    track.g = g / 255.f;
+    track.b = b / 255.f;
 
     // Now get the visibility information
     size_t nvisible = 0;
     is >> nvisible;
 
-    for( size_t k = 0; k < nvisible; k++ )
-    {
+    for (size_t k = 0; k < nvisible; k++) {
       size_t cam_idx = 0, point_idx = 0;
       float u, v;
       is >> cam_idx >> point_idx >> u >> v;
-      track.measurements.push_back(make_pair(cam_idx,Point2(u,-v)));
+      track.measurements.push_back(make_pair(cam_idx, Point2(u, -v)));
     }
 
     data.tracks.push_back(track);
@@ -545,123 +567,10 @@ bool readBundler(const string& filename, SfM_data &data)
 }
 
 /* ************************************************************************* */
-bool readG2o(const std::string& g2oFile, NonlinearFactorGraph& graph, Values& initial,
-    const kernelFunctionType kernelFunction){
-
-  ifstream is(g2oFile.c_str());
-  if (!is){
-    throw std::invalid_argument("File not found!");
-    return false;
-  }
-
-  // READ INITIAL GUESS FROM G2O FILE
-  string tag;
-  while (is) {
-    if(! (is >> tag))
-      break;
-
-    if (tag == "VERTEX_SE2" || tag == "VERTEX2") {
-      int id;
-      double x, y, yaw;
-      is >> id >> x >> y >> yaw;
-      initial.insert(id, Pose2(x, y, yaw));
-    }
-    is.ignore(LINESIZE, '\n');
-  }
-  is.clear(); /* clears the end-of-file and error flags */
-  is.seekg(0, ios::beg);
-  // initial.print("initial guess");
-
-  // READ MEASUREMENTS FROM G2O FILE
-  while (is) {
-    if(! (is >> tag))
-      break;
-
-    if (tag == "EDGE_SE2" || tag == "EDGE2") {
-      int id1, id2;
-      double x, y, yaw;
-      double I11, I12, I13, I22, I23, I33;
-
-      is >> id1 >> id2 >> x >> y >> yaw;
-      is >> I11 >> I12 >> I13 >> I22 >> I23 >> I33;
-      Pose2 l1Xl2(x, y, yaw);
-      noiseModel::Diagonal::shared_ptr model = noiseModel::Diagonal::Precisions((Vector(3) << I11, I22, I33));
-
-      switch (kernelFunction) {
-      {case QUADRATIC:
-        NonlinearFactor::shared_ptr factor(new BetweenFactor(id1, id2, l1Xl2, model));
-        graph.add(factor);
-        break;}
-      {case HUBER:
-        NonlinearFactor::shared_ptr huberFactor(new BetweenFactor(id1, id2, l1Xl2,
-            noiseModel::Robust::Create(noiseModel::mEstimator::Huber::Create(1.345), model)));
-        graph.add(huberFactor);
-        break;}
-      {case TUKEY:
-        NonlinearFactor::shared_ptr tukeyFactor(new BetweenFactor(id1, id2, l1Xl2,
-            noiseModel::Robust::Create(noiseModel::mEstimator::Tukey::Create(4.6851), model)));
-        graph.add(tukeyFactor);
-        break;}
-      }
-    }
-    is.ignore(LINESIZE, '\n');
-  }
-  // Output which kernel is used
-  switch (kernelFunction) {
-  case QUADRATIC:
-      break;
-  case HUBER:
-    std::cout << "Robust kernel: Huber" << std::endl; break;
-  case TUKEY:
-    std::cout << "Robust kernel: Tukey" << std::endl; break;
-  }
-  return true;
-}
-
-/* ************************************************************************* */
-bool writeG2o(const std::string& filename, const NonlinearFactorGraph& graph, const Values& estimate){
-
-  fstream stream(filename.c_str(), fstream::out);
-
-  // save poses
-  BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, estimate)
-  {
-    const Pose2& pose = dynamic_cast(key_value.value);
-    stream << "VERTEX_SE2 " << key_value.key << " " << pose.x() << " "
-        << pose.y() << " " << pose.theta() << endl;
-  }
-
-  // save edges
-  BOOST_FOREACH(boost::shared_ptr factor_, graph)
-  {
-    boost::shared_ptr > factor =
-        boost::dynamic_pointer_cast >(factor_);
-    if (!factor)
-      continue;
-
-    SharedNoiseModel model = factor->get_noiseModel();
-    boost::shared_ptr diagonalModel =
-        boost::dynamic_pointer_cast(model);
-    if (!diagonalModel)
-      throw std::invalid_argument("writeG2o: invalid noise model (current version assumes diagonal noise model)!");
-
-    Pose2 pose = factor->measured(); //.inverse();
-    stream << "EDGE_SE2 " << factor->key1() << " " << factor->key2() << " "
-        << pose.x() << " " << pose.y() << " " << pose.theta() << " "
-        << diagonalModel->precision(0) << " " << 0.0 << " " << 0.0 << " "
-        << diagonalModel->precision(1) << " " << 0.0 << " " << diagonalModel->precision(2) << endl;
-  }
-  stream.close();
-  return true;
-}
-
-/* ************************************************************************* */
-bool readBAL(const string& filename, SfM_data &data)
-{
+bool readBAL(const string& filename, SfM_data &data) {
   // Load the data file
-  ifstream is(filename.c_str(),ifstream::in);
-  if(!is)
-  {
+  ifstream is(filename.c_str(), ifstream::in);
+  if (!is) {
     cout << "Error in readBAL: can not find the file!!" << endl;
     return false;
   }
@@ -673,44 +582,41 @@ bool readBAL(const string& filename, SfM_data &data)
   data.tracks.resize(nrPoints);
 
   // Get the information for the observations
-  for( size_t k = 0; k < nrObservations; k++ )
-  {
+  for (size_t k = 0; k < nrObservations; k++) {
     size_t i = 0, j = 0;
     float u, v;
     is >> i >> j >> u >> v;
-    data.tracks[j].measurements.push_back(make_pair(i,Point2(u,-v)));
+    data.tracks[j].measurements.push_back(make_pair(i, Point2(u, -v)));
   }
 
   // Get the information for the camera poses
-  for( size_t i = 0; i < nrPoses; i++ )
-  {
+  for (size_t i = 0; i < nrPoses; i++) {
     // Get the rodriguez vector
     float wx, wy, wz;
     is >> wx >> wy >> wz;
-    Rot3 R = Rot3::rodriguez(wx, wy, wz);// BAL-OpenGL rotation matrix
+    Rot3 R = Rot3::rodriguez(wx, wy, wz); // BAL-OpenGL rotation matrix
 
     // Get the translation vector
     float tx, ty, tz;
     is >> tx >> ty >> tz;
 
-    Pose3 pose = openGL2gtsam(R,tx,ty,tz);
+    Pose3 pose = openGL2gtsam(R, tx, ty, tz);
 
     // Get the focal length and the radial distortion parameters
     float f, k1, k2;
     is >> f >> k1 >> k2;
     Cal3Bundler K(f, k1, k2);
 
-    data.cameras.push_back(SfM_Camera(pose,K));
+    data.cameras.push_back(SfM_Camera(pose, K));
   }
 
   // Get the information for the 3D points
-  for( size_t j = 0; j < nrPoints; j++ )
-  {
+  for (size_t j = 0; j < nrPoints; j++) {
     // Get the 3D position
     float x, y, z;
     is >> x >> y >> z;
     SfM_Track& track = data.tracks[j];
-    track.p = Point3(x,y,z);
+    track.p = Point3(x, y, z);
     track.r = 0.4f;
     track.g = 0.4f;
     track.b = 0.4f;
@@ -721,8 +627,7 @@ bool readBAL(const string& filename, SfM_data &data)
 }
 
 /* ************************************************************************* */
-bool writeBAL(const string& filename, SfM_data &data)
-{
+bool writeBAL(const string& filename, SfM_data &data) {
   // Open the output file
   ofstream os;
   os.open(filename.c_str());
@@ -733,49 +638,55 @@ bool writeBAL(const string& filename, SfM_data &data)
   }
 
   // Write the number of camera poses and 3D points
-  size_t nrObservations=0;
-  for (size_t j = 0; j < data.number_tracks(); j++){
+  size_t nrObservations = 0;
+  for (size_t j = 0; j < data.number_tracks(); j++) {
     nrObservations += data.tracks[j].number_measurements();
   }
 
   // Write observations
-  os <<  data.number_cameras() << " " << data.number_tracks() << " " << nrObservations << endl;
+  os << data.number_cameras() << " " << data.number_tracks() << " "
+      << nrObservations << endl;
   os << endl;
 
-  for (size_t j = 0; j < data.number_tracks(); j++){ // for each 3D point j
+  for (size_t j = 0; j < data.number_tracks(); j++) { // for each 3D point j
     SfM_Track track = data.tracks[j];
 
-    for(size_t k = 0; k < track.number_measurements(); k++){ // for each observation of the 3D point j
+    for (size_t k = 0; k < track.number_measurements(); k++) { // for each observation of the 3D point j
       size_t i = track.measurements[k].first; // camera id
       double u0 = data.cameras[i].calibration().u0();
       double v0 = data.cameras[i].calibration().v0();
 
-      if(u0 != 0 || v0 != 0){cout<< "writeBAL has not been tested for calibration with nonzero (u0,v0)"<< endl;}
+      if (u0 != 0 || v0 != 0) {
+        cout
+            << "writeBAL has not been tested for calibration with nonzero (u0,v0)"
+            << endl;
+      }
 
       double pixelBALx = track.measurements[k].second.x() - u0; // center of image is the origin
-      double pixelBALy = - (track.measurements[k].second.y() - v0); // center of image is the origin
+      double pixelBALy = -(track.measurements[k].second.y() - v0); // center of image is the origin
       Point2 pixelMeasurement(pixelBALx, pixelBALy);
-      os <<  i /*camera id*/ << " " << j /*point id*/ << " "
-          << pixelMeasurement.x() /*u of the pixel*/ << " " << pixelMeasurement.y() /*v of the pixel*/ << endl;
+      os << i /*camera id*/<< " " << j /*point id*/<< " "
+          << pixelMeasurement.x() /*u of the pixel*/<< " "
+          << pixelMeasurement.y() /*v of the pixel*/<< endl;
     }
   }
   os << endl;
 
   // Write cameras
-  for (size_t i = 0; i < data.number_cameras(); i++){ // for each camera
+  for (size_t i = 0; i < data.number_cameras(); i++) { // for each camera
     Pose3 poseGTSAM = data.cameras[i].pose();
     Cal3Bundler cameraCalibration = data.cameras[i].calibration();
     Pose3 poseOpenGL = gtsam2openGL(poseGTSAM);
-    os <<  Rot3::Logmap(poseOpenGL.rotation()) << endl;
-    os <<  poseOpenGL.translation().vector() << endl;
-    os <<  cameraCalibration.fx() << endl;
-    os <<  cameraCalibration.k1() << endl;
-    os <<  cameraCalibration.k2() << endl;
+    os << Rot3::Logmap(poseOpenGL.rotation()) << endl;
+    os << poseOpenGL.translation().vector() << endl;
+    os << cameraCalibration.fx() << endl;
+    os << cameraCalibration.k1() << endl;
+    os << cameraCalibration.k2() << endl;
     os << endl;
   }
 
   // Write the points
-  for (size_t j = 0; j < data.number_tracks(); j++){ // for each 3D point j
+  for (size_t j = 0; j < data.number_tracks(); j++) { // for each 3D point j
     Point3 point = data.tracks[j].p;
     os << point.x() << endl;
     os << point.y() << endl;
@@ -787,48 +698,55 @@ bool writeBAL(const string& filename, SfM_data &data)
   return true;
 }
 
-bool writeBALfromValues(const string& filename, const SfM_data &data, Values& values){
+bool writeBALfromValues(const string& filename, const SfM_data &data,
+    Values& values) {
 
   SfM_data dataValues = data;
 
   // Store poses or cameras in SfM_data
   Values valuesPoses = values.filter();
-  if( valuesPoses.size() == dataValues.number_cameras() ){ // we only estimated camera poses
-    for (size_t i = 0; i < dataValues.number_cameras(); i++){ // for each camera
-      Key poseKey = symbol('x',i);
+  if (valuesPoses.size() == dataValues.number_cameras()) { // we only estimated camera poses
+    for (size_t i = 0; i < dataValues.number_cameras(); i++) { // for each camera
+      Key poseKey = symbol('x', i);
       Pose3 pose = values.at(poseKey);
       Cal3Bundler K = dataValues.cameras[i].calibration();
       PinholeCamera camera(pose, K);
       dataValues.cameras[i] = camera;
     }
   } else {
-    Values valuesCameras = values.filter< PinholeCamera >();
-    if ( valuesCameras.size() == dataValues.number_cameras() ){  // we only estimated camera poses and calibration
-      for (size_t i = 0; i < dataValues.number_cameras(); i++){ // for each camera
+    Values valuesCameras = values.filter >();
+    if (valuesCameras.size() == dataValues.number_cameras()) { // we only estimated camera poses and calibration
+      for (size_t i = 0; i < dataValues.number_cameras(); i++) { // for each camera
         Key cameraKey = i; // symbol('c',i);
-        PinholeCamera camera = values.at >(cameraKey);
+        PinholeCamera camera =
+            values.at >(cameraKey);
         dataValues.cameras[i] = camera;
       }
-    }else{
-      cout << "writeBALfromValues: different number of cameras in SfM_dataValues (#cameras= " << dataValues.number_cameras()
-              <<") and values (#cameras " << valuesPoses.size() << ", #poses " << valuesCameras.size() << ")!!" << endl;
+    } else {
+      cout
+          << "writeBALfromValues: different number of cameras in SfM_dataValues (#cameras= "
+          << dataValues.number_cameras() << ") and values (#cameras "
+          << valuesPoses.size() << ", #poses " << valuesCameras.size() << ")!!"
+          << endl;
       return false;
     }
   }
 
   // Store 3D points in SfM_data
   Values valuesPoints = values.filter();
-  if( valuesPoints.size() != dataValues.number_tracks()){
-    cout << "writeBALfromValues: different number of points in SfM_dataValues (#points= " << dataValues.number_tracks()
-            <<") and values (#points " << valuesPoints.size() << ")!!" << endl;
+  if (valuesPoints.size() != dataValues.number_tracks()) {
+    cout
+        << "writeBALfromValues: different number of points in SfM_dataValues (#points= "
+        << dataValues.number_tracks() << ") and values (#points "
+        << valuesPoints.size() << ")!!" << endl;
   }
 
-  for (size_t j = 0; j < dataValues.number_tracks(); j++){ // for each point
+  for (size_t j = 0; j < dataValues.number_tracks(); j++) { // for each point
     Key pointKey = P(j);
-    if(values.exists(pointKey)){
+    if (values.exists(pointKey)) {
       Point3 point = values.at(pointKey);
       dataValues.tracks[j].p = point;
-    }else{
+    } else {
       dataValues.tracks[j].r = 1.0;
       dataValues.tracks[j].g = 0.0;
       dataValues.tracks[j].b = 0.0;
@@ -844,7 +762,7 @@ Values initialCamerasEstimate(const SfM_data& db) {
   Values initial;
   size_t i = 0; // NO POINTS:  j = 0;
   BOOST_FOREACH(const SfM_Camera& camera, db.cameras)
-  initial.insert(i++, camera);
+    initial.insert(i++, camera);
   return initial;
 }
 
@@ -852,9 +770,9 @@ Values initialCamerasAndPointsEstimate(const SfM_data& db) {
   Values initial;
   size_t i = 0, j = 0;
   BOOST_FOREACH(const SfM_Camera& camera, db.cameras)
-  initial.insert((i++), camera);
+    initial.insert((i++), camera);
   BOOST_FOREACH(const SfM_Track& track, db.tracks)
-  initial.insert(P(j++), track.p);
+    initial.insert(P(j++), track.p);
   return initial;
 }
 
diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h
index 98297ac04..8fd75269c 100644
--- a/gtsam/slam/dataset.h
+++ b/gtsam/slam/dataset.h
@@ -35,7 +35,7 @@ namespace gtsam {
 /**
  * Find the full path to an example dataset distributed with gtsam.  The name
  * may be specified with or without a file extension - if no extension is
- * give, this function first looks for the .graph extension, then .txt.  We
+ * given, this function first looks for the .graph extension, then .txt.  We
  * first check the gtsam source tree for the file, followed by the installed
  * example dataset location.  Both the source tree and installed locations
  * are obtained from CMake during compilation.
@@ -44,8 +44,30 @@ namespace gtsam {
  * search process described above.
  */
 GTSAM_EXPORT std::string findExampleDataFile(const std::string& name);
+
+/**
+ * Creates a temporary file name that needs to be ignored in .gitingnore
+ * for checking read-write oprations
+ */
+GTSAM_EXPORT std::string createRewrittenFileName(const std::string& name);
 #endif
 
+/// Indicates how noise parameters are stored in file
+enum NoiseFormat {
+  NoiseFormatG2O, ///< Information matrix I11, I12, I13, I22, I23, I33
+  NoiseFormatTORO, ///< Information matrix, but inf_ff inf_fs inf_ss inf_rr inf_fr inf_sr
+  NoiseFormatGRAPH, ///< default: toro-style order, but covariance matrix !
+  NoiseFormatCOV ///< Covariance matrix C11, C12, C13, C22, C23, C33
+};
+
+/// Robust kernel type to wrap around quadratic noise model
+enum KernelFunctionType {
+  KernelFunctionTypeNONE, KernelFunctionTypeHUBER, KernelFunctionTypeTUKEY
+};
+
+/// Return type for load functions
+typedef std::pair GraphAndValues;
+
 /**
  * Load TORO 2D Graph
  * @param dataset/model pair as constructed by [dataset]
@@ -53,31 +75,57 @@ GTSAM_EXPORT std::string findExampleDataFile(const std::string& name);
  * @param addNoise add noise to the edges
  * @param smart try to reduce complexity of covariance to cheapest model
  */
-GTSAM_EXPORT std::pair load2D(
-    std::pair > dataset,
-    int maxID = 0, bool addNoise = false, bool smart = true);
+GTSAM_EXPORT GraphAndValues load2D(
+    std::pair dataset, int maxID = 0,
+    bool addNoise = false,
+    bool smart = true, //
+    NoiseFormat noiseFormat = NoiseFormatGRAPH,
+    KernelFunctionType kernelFunctionType = KernelFunctionTypeNONE);
 
 /**
- * Load TORO 2D Graph
+ * Load TORO/G2O style graph files
  * @param filename
  * @param model optional noise model to use instead of one specified by file
  * @param maxID if non-zero cut out vertices >= maxID
  * @param addNoise add noise to the edges
  * @param smart try to reduce complexity of covariance to cheapest model
+ * @param noiseFormat how noise parameters are stored
+ * @param kernelFunctionType whether to wrap the noise model in a robust kernel
+ * @return graph and initial values
  */
-GTSAM_EXPORT std::pair load2D(
-    const std::string& filename,
-    boost::optional model = boost::optional<
-    noiseModel::Diagonal::shared_ptr>(), int maxID = 0, bool addNoise = false,
-    bool smart = true);
+GTSAM_EXPORT GraphAndValues load2D(const std::string& filename,
+    SharedNoiseModel model = SharedNoiseModel(), int maxID = 0, bool addNoise =
+        false, bool smart = true, NoiseFormat noiseFormat = NoiseFormatGRAPH, //
+    KernelFunctionType kernelFunctionType = KernelFunctionTypeNONE);
 
-GTSAM_EXPORT std::pair load2D_robust(
-    const std::string& filename,
-    gtsam::noiseModel::Base::shared_ptr& model, int maxID = 0);
+/// @deprecated load2D now allows for arbitrary models and wrapping a robust kernel
+GTSAM_EXPORT GraphAndValues load2D_robust(const std::string& filename,
+    noiseModel::Base::shared_ptr& model, int maxID = 0);
 
 /** save 2d graph */
-GTSAM_EXPORT void save2D(const NonlinearFactorGraph& graph, const Values& config,
-    const noiseModel::Diagonal::shared_ptr model, const std::string& filename);
+GTSAM_EXPORT void save2D(const NonlinearFactorGraph& graph,
+    const Values& config, const noiseModel::Diagonal::shared_ptr model,
+    const std::string& filename);
+
+/**
+ * @brief This function parses a g2o file and stores the measurements into a
+ * NonlinearFactorGraph and the initial guess in a Values structure
+ * @param filename The name of the g2o file
+ * @param kernelFunctionType whether to wrap the noise model in a robust kernel
+ * @return graph and initial values
+ */
+GTSAM_EXPORT GraphAndValues readG2o(const std::string& g2oFile,
+    KernelFunctionType kernelFunctionType = KernelFunctionTypeNONE);
+
+/**
+ * @brief This function writes a g2o file from
+ * NonlinearFactorGraph and a Values structure
+ * @param filename The name of the g2o file to write
+ * @param graph NonlinearFactor graph storing the measurements
+ * @param estimate Values
+ */
+GTSAM_EXPORT void writeG2o(const NonlinearFactorGraph& graph,
+    const Values& estimate, const std::string& filename);
 
 /**
  * Load TORO 3D Graph
@@ -85,27 +133,31 @@ GTSAM_EXPORT void save2D(const NonlinearFactorGraph& graph, const Values& config
 GTSAM_EXPORT bool load3D(const std::string& filename);
 
 /// A measurement with its camera index
-typedef std::pair SfM_Measurement;
+typedef std::pair SfM_Measurement;
 
 /// Define the structure for the 3D points
-struct SfM_Track
-{
-  gtsam::Point3 p; ///< 3D position of the point
-  float r,g,b; ///< RGB color of the 3D point
+struct SfM_Track {
+  Point3 p; ///< 3D position of the point
+  float r, g, b; ///< RGB color of the 3D point
   std::vector measurements; ///< The 2D image projections (id,(u,v))
-  size_t number_measurements() const { return measurements.size();}
+  size_t number_measurements() const {
+    return measurements.size();
+  }
 };
 
 /// Define the structure for the camera poses
-typedef gtsam::PinholeCamera SfM_Camera;
+typedef PinholeCamera SfM_Camera;
 
 /// Define the structure for SfM data
-struct SfM_data
-{
-  std::vector cameras;    ///< Set of cameras
+struct SfM_data {
+  std::vector cameras; ///< Set of cameras
   std::vector tracks; ///< Sparse set of points
-  size_t number_cameras() const { return cameras.size();}   ///< The number of camera poses
-  size_t number_tracks()  const { return tracks.size();}  ///< The number of reconstructed 3D points
+  size_t number_cameras() const {
+    return cameras.size();
+  } ///< The number of camera poses
+  size_t number_tracks() const {
+    return tracks.size();
+  } ///< The number of reconstructed 3D points
 };
 
 /**
@@ -117,25 +169,6 @@ struct SfM_data
  */
 GTSAM_EXPORT bool readBundler(const std::string& filename, SfM_data &data);
 
-/**
- * @brief This function parses a g2o file and stores the measurements into a
- * NonlinearFactorGraph and the initial guess in a Values structure
- * @param filename The name of the g2o file
- * @param graph NonlinearFactor graph storing the measurements (EDGE_SE2). NOTE: information matrix is assumed diagonal.
- * @return initial Values containing the initial guess (VERTEX_SE2)
- */
-enum kernelFunctionType { QUADRATIC, HUBER, TUKEY };
-GTSAM_EXPORT bool readG2o(const std::string& g2oFile, NonlinearFactorGraph& graph, Values& initial, const kernelFunctionType kernelFunction = QUADRATIC);
-
-/**
- * @brief This function writes a g2o file from
- * NonlinearFactorGraph and a Values structure
- * @param filename The name of the g2o file to write
- * @param graph NonlinearFactor graph storing the measurements (EDGE_SE2)
- * @return estimate Values containing the values (VERTEX_SE2)
- */
-GTSAM_EXPORT bool writeG2o(const std::string& filename, const NonlinearFactorGraph& graph, const Values& estimate);
-
 /**
  * @brief This function parses a "Bundle Adjustment in the Large" (BAL) file and stores the data into a
  * SfM_data structure
@@ -165,7 +198,8 @@ GTSAM_EXPORT bool writeBAL(const std::string& filename, SfM_data &data);
  * assumes that the keys are "x1" for pose 1 (or "c1" for camera 1) and "l1" for landmark 1
  * @return true if the parsing was successful, false otherwise
  */
-GTSAM_EXPORT bool writeBALfromValues(const std::string& filename, const SfM_data &data, Values& values);
+GTSAM_EXPORT bool writeBALfromValues(const std::string& filename,
+    const SfM_data &data, Values& values);
 
 /**
  * @brief This function converts an openGL camera pose to an GTSAM camera pose
@@ -208,5 +242,4 @@ GTSAM_EXPORT Values initialCamerasEstimate(const SfM_data& db);
  */
 GTSAM_EXPORT Values initialCamerasAndPointsEstimate(const SfM_data& db);
 
-
 } // namespace gtsam
diff --git a/gtsam/nonlinear/LagoInitializer.cpp b/gtsam/slam/lago.cpp
similarity index 51%
rename from gtsam/nonlinear/LagoInitializer.cpp
rename to gtsam/slam/lago.cpp
index 3451beaf3..abb72021a 100644
--- a/gtsam/nonlinear/LagoInitializer.cpp
+++ b/gtsam/slam/lago.cpp
@@ -10,38 +10,60 @@
  * -------------------------------------------------------------------------- */
 
 /**
- *  @file  LagoInitializer.h
+ *  @file  lago.h
  *  @author Luca Carlone
  *  @author Frank Dellaert
  *  @date   May 14, 2014
  */
 
-#include 
-#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include 
 
-namespace gtsam {
+using namespace std;
 
-static Matrix I = eye(1);
-static Matrix I3 = eye(3);
+namespace gtsam {
+namespace lago {
+
+static const Matrix I = eye(1);
+static const Matrix I3 = eye(3);
+
+static const Key keyAnchor = symbol('Z', 9999999);
+static const noiseModel::Diagonal::shared_ptr priorOrientationNoise =
+    noiseModel::Diagonal::Sigmas((Vector(1) << 0));
+static const noiseModel::Diagonal::shared_ptr priorPose2Noise =
+    noiseModel::Diagonal::Variances((Vector(3) << 1e-6, 1e-6, 1e-8));
 
 /* ************************************************************************* */
-double computeThetaToRoot(const Key nodeKey, const PredecessorMap& tree,
-    const key2doubleMap& deltaThetaMap, const key2doubleMap& thetaFromRootMap) {
+/**
+ * Compute the cumulative orientation (without wrapping) wrt the root of a
+ * spanning tree (tree) for a node (nodeKey). The function starts at the nodes and
+ * moves towards the root summing up the (directed) rotation measurements.
+ * Relative measurements are encoded in "deltaThetaMap".
+ * The root is assumed to have orientation zero.
+ */
+static double computeThetaToRoot(const Key nodeKey,
+    const PredecessorMap& tree, const key2doubleMap& deltaThetaMap,
+    const key2doubleMap& thetaFromRootMap) {
 
   double nodeTheta = 0;
   Key key_child = nodeKey; // the node
   Key key_parent = 0; // the initialization does not matter
-  while(1){
+  while (1) {
     // We check if we reached the root
-    if(tree.at(key_child)==key_child) // if we reached the root
+    if (tree.at(key_child) == key_child) // if we reached the root
       break;
     // we sum the delta theta corresponding to the edge parent->child
     nodeTheta += deltaThetaMap.at(key_child);
     // we get the parent
     key_parent = tree.at(key_child); // the parent
     // we check if we connected to some part of the tree we know
-    if(thetaFromRootMap.find(key_parent)!=thetaFromRootMap.end()){
+    if (thetaFromRootMap.find(key_parent) != thetaFromRootMap.end()) {
       nodeTheta += thetaFromRootMap.at(key_parent);
       break;
     }
@@ -55,53 +77,55 @@ key2doubleMap computeThetasToRoot(const key2doubleMap& deltaThetaMap,
     const PredecessorMap