diff --git a/.cproject b/.cproject
index 7086ce250..5d8469baa 100644
--- a/.cproject
+++ b/.cproject
@@ -747,6 +747,14 @@
true
true
+
+ make
+ -j4
+ testSimilarity3.run
+ true
+ true
+ true
+
make
-j5
@@ -1011,6 +1019,30 @@
true
true
+
+ make
+ -j4
+ testOrientedPlane3.run
+ true
+ true
+ true
+
+
+ make
+ -j4
+ testPinholePose.run
+ true
+ true
+ true
+
+
+ make
+ -j4
+ testCyclic.run
+ true
+ true
+ true
+
make
-j2
@@ -1277,6 +1309,7 @@
make
+
testSimulated2DOriented.run
true
false
@@ -1316,6 +1349,7 @@
make
+
testSimulated2D.run
true
false
@@ -1323,6 +1357,7 @@
make
+
testSimulated3D.run
true
false
@@ -1426,7 +1461,6 @@
make
-
testErrors.run
true
false
@@ -1520,6 +1554,22 @@
true
true
+
+ make
+ -j4
+ testOrientedPlane3Factor.run
+ true
+ true
+ true
+
+
+ make
+ -j4
+ testSmartProjectionPoseFactor.run
+ true
+ true
+ true
+
make
-j3
@@ -1721,7 +1771,6 @@
cpack
-
-G DEB
true
false
@@ -1729,7 +1778,6 @@
cpack
-
-G RPM
true
false
@@ -1737,7 +1785,6 @@
cpack
-
-G TGZ
true
false
@@ -1745,7 +1792,6 @@
cpack
-
--config CPackSourceConfig.cmake
true
false
@@ -1937,6 +1983,7 @@
make
+
tests/testGaussianISAM2
true
false
@@ -1998,22 +2045,6 @@
true
true
-
- make
- -j5
- testExpressionMeta.run
- true
- true
- true
-
-
- make
- -j4
- testCustomChartExpression.run
- true
- true
- true
-
make
-j5
@@ -2088,7 +2119,6 @@
make
-
tests/testBayesTree.run
true
false
@@ -2096,7 +2126,6 @@
make
-
testBinaryBayesNet.run
true
false
@@ -2144,7 +2173,6 @@
make
-
testSymbolicBayesNet.run
true
false
@@ -2152,7 +2180,6 @@
make
-
tests/testSymbolicFactor.run
true
false
@@ -2160,7 +2187,6 @@
make
-
testSymbolicFactorGraph.run
true
false
@@ -2176,7 +2202,6 @@
make
-
tests/testBayesTree
true
false
@@ -2422,6 +2447,14 @@
true
true
+
+ make
+ -j4
+ SFMExampleExpressions_bal.run
+ true
+ true
+ true
+
make
-j2
@@ -2606,14 +2639,6 @@
true
true
-
- make
- -j4
- testOrdering.run
- true
- true
- true
-
make
-j2
@@ -2678,14 +2703,6 @@
true
true
-
- make
- -j4
- testSymbolicBayesTree.run
- true
- true
- true
-
make
-j5
@@ -2758,6 +2775,14 @@
true
true
+
+ make
+ -j4
+ testExecutionTrace.run
+ true
+ true
+ true
+
make
-j5
@@ -2870,6 +2895,14 @@
true
true
+
+ make
+ -j4
+ timeSchurFactors.run
+ true
+ true
+ true
+
make
-j5
@@ -3166,6 +3199,14 @@
true
true
+
+ make
+ -j4
+ testGroup.run
+ true
+ true
+ true
+
make
-j5
@@ -3304,7 +3345,6 @@
make
-
testGraph.run
true
false
@@ -3312,7 +3352,6 @@
make
-
testJunctionTree.run
true
false
@@ -3320,7 +3359,6 @@
make
-
testSymbolicBayesNetB.run
true
false
@@ -3390,6 +3428,14 @@
true
true
+
+ make
+ -j4
+ testLie.run
+ true
+ true
+ true
+
make
-j2
diff --git a/.settings/.gitignore b/.settings/.gitignore
new file mode 100644
index 000000000..faa6d2991
--- /dev/null
+++ b/.settings/.gitignore
@@ -0,0 +1 @@
+/org.eclipse.cdt.codan.core.prefs
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38ee89760..fd11a6733 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -158,6 +158,12 @@ else()
set(GTSAM_USE_TBB 0) # This will go into config.h
endif()
+###############################################################################
+# Prohibit Timing build mode in combination with TBB
+if(GTSAM_USE_TBB AND (CMAKE_BUILD_TYPE STREQUAL "Timing"))
+ message(FATAL_ERROR "Timing build mode cannot be used together with TBB. Use a sampling profiler such as Instruments or Intel VTune Amplifier instead.")
+endif()
+
###############################################################################
# Find Google perftools
@@ -173,6 +179,11 @@ if(MKL_FOUND AND GTSAM_WITH_EIGEN_MKL)
set(EIGEN_USE_MKL_ALL 1) # This will go into config.h - it makes Eigen use MKL
include_directories(${MKL_INCLUDE_DIR})
list(APPEND GTSAM_ADDITIONAL_LIBRARIES ${MKL_LIBRARIES})
+
+ # --no-as-needed is required with gcc according to the MKL link advisor
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-as-needed")
+ endif()
else()
set(GTSAM_USE_EIGEN_MKL 0)
set(EIGEN_USE_MKL_ALL 0)
@@ -192,36 +203,40 @@ endif()
###############################################################################
# Option for using system Eigen or GTSAM-bundled Eigen
-### Disabled until our patches are included in Eigen ###
+### These patches only affect usage of MKL. If you want to enable MKL, you *must*
+### use our patched version of Eigen
### See: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=704 (Householder QR MKL selection)
### http://eigen.tuxfamily.org/bz/show_bug.cgi?id=705 (Fix MKL LLT return code)
-### http://eigen.tuxfamily.org/bz/show_bug.cgi?id=716 (Improved comma initialization)
-# option(GTSAM_USE_SYSTEM_EIGEN "Find and use system-installed Eigen. If 'off', use the one bundled with GTSAM" OFF)
-set(GTSAM_USE_SYSTEM_EIGEN OFF)
+option(GTSAM_USE_SYSTEM_EIGEN "Find and use system-installed Eigen. If 'off', use the one bundled with GTSAM" OFF)
# Switch for using system Eigen or GTSAM-bundled Eigen
if(GTSAM_USE_SYSTEM_EIGEN)
- # Use generic Eigen include paths e.g.
- set(GTSAM_EIGEN_INCLUDE_PREFIX "")
-
find_package(Eigen3 REQUIRED)
include_directories(AFTER "${EIGEN3_INCLUDE_DIR}")
+
+ # Use generic Eigen include paths e.g.
+ set(GTSAM_EIGEN_INCLUDE_PREFIX "${EIGEN3_INCLUDE_DIR}")
+
+ # check if MKL is also enabled - can have one or the other, but not both!
+ if(EIGEN_USE_MKL_ALL)
+ message(FATAL_ERROR "MKL cannot be used together with system-installed Eigen, as MKL support relies on patches which are not yet in the system-installed Eigen. Disable either GTSAM_USE_SYSTEM_EIGEN or GTSAM_WITH_EIGEN_MKL")
+ endif()
else()
- # Use bundled Eigen include paths e.g.
- set(GTSAM_EIGEN_INCLUDE_PREFIX "gtsam/3rdparty/Eigen/")
-
+ # Use bundled Eigen include path.
# Clear any variables set by FindEigen3
if(EIGEN3_INCLUDE_DIR)
set(EIGEN3_INCLUDE_DIR NOTFOUND CACHE STRING "" FORCE)
endif()
+ # Add the bundled version of eigen to the include path so that it can still be included
+ # with #include
+ include_directories(BEFORE "gtsam/3rdparty/Eigen/")
+
+ # set full path to be used by external projects
+ # this will be added to GTSAM_INCLUDE_DIR by gtsam_extra.cmake.in
+ set(GTSAM_EIGEN_INCLUDE_PREFIX "${CMAKE_INSTALL_PREFIX}/include/gtsam/3rdparty/Eigen/")
+
endif()
-# Write Eigen include file with the paths for either the system Eigen or the GTSAM-bundled Eigen
-configure_file(gtsam/3rdparty/gtsam_eigen_includes.h.in gtsam/3rdparty/gtsam_eigen_includes.h)
-
-# Install the configuration file for Eigen
-install(FILES ${PROJECT_BINARY_DIR}/gtsam/3rdparty/gtsam_eigen_includes.h DESTINATION include/gtsam/3rdparty)
-
###############################################################################
# Global compile options
@@ -389,6 +404,11 @@ if(NOT MSVC AND NOT XCODE_VERSION)
message(STATUS " C compilation flags : ${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${cmake_build_type_toupper}}")
message(STATUS " C++ compilation flags : ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${cmake_build_type_toupper}}")
endif()
+if(GTSAM_USE_SYSTEM_EIGEN)
+ message(STATUS " Use System Eigen : Yes")
+else()
+ message(STATUS " Use System Eigen : No")
+endif()
if(GTSAM_USE_TBB)
message(STATUS " Use Intel TBB : Yes")
elseif(TBB_FOUND)
diff --git a/cmake/GtsamBuildTypes.cmake b/cmake/GtsamBuildTypes.cmake
index 1bead58d8..c2cd7b449 100644
--- a/cmake/GtsamBuildTypes.cmake
+++ b/cmake/GtsamBuildTypes.cmake
@@ -53,11 +53,12 @@ if(NOT FIRST_PASS_DONE)
endif()
endif()
-# Clang on Mac uses a template depth that is less than standard and is too small
+# Clang uses a template depth that is less than standard and is too small
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
- if(NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "5.0")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024")
- endif()
+ # Apple Clang before 5.0 does not support -ftemplate-depth.
+ if(NOT (APPLE AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "5.0"))
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024")
+ endif()
endif()
# Set up build type library postfixes
@@ -97,7 +98,8 @@ if( NOT cmake_build_type_tolower STREQUAL ""
AND NOT cmake_build_type_tolower STREQUAL "release"
AND NOT cmake_build_type_tolower STREQUAL "timing"
AND NOT cmake_build_type_tolower STREQUAL "profiling"
- AND NOT cmake_build_type_tolower STREQUAL "relwithdebinfo")
+ AND NOT cmake_build_type_tolower STREQUAL "relwithdebinfo"
+ AND NOT cmake_build_type_tolower STREQUAL "minsizerel")
message(FATAL_ERROR "Unknown build type \"${CMAKE_BUILD_TYPE}\". Allowed values are None, Debug, Release, Timing, Profiling, RelWithDebInfo (case-insensitive).")
endif()
diff --git a/cmake/GtsamMatlabWrap.cmake b/cmake/GtsamMatlabWrap.cmake
index ba616b025..d1d3d93dd 100644
--- a/cmake/GtsamMatlabWrap.cmake
+++ b/cmake/GtsamMatlabWrap.cmake
@@ -270,7 +270,7 @@ function(install_wrapped_library_internal interfaceHeader)
if(GTSAM_BUILD_TYPE_POSTFIXES)
foreach(build_type ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER "${build_type}" build_type_upper)
- if("${build_type_upper}" STREQUAL "RELEASE")
+ if(${build_type_upper} STREQUAL "RELEASE")
set(build_type_tag "") # Don't create release mode tag on installed directory
else()
set(build_type_tag "${build_type}")
@@ -367,13 +367,18 @@ endfunction()
# should be installed to all build type toolboxes
function(install_matlab_scripts source_directory patterns)
set(patterns_args "")
+ set(exclude_patterns "")
+ if(NOT GTSAM_WRAP_SERIALIZATION)
+ set(exclude_patterns "testSerialization.m")
+ endif()
+
foreach(pattern ${patterns})
list(APPEND patterns_args PATTERN "${pattern}")
endforeach()
if(GTSAM_BUILD_TYPE_POSTFIXES)
foreach(build_type ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER "${build_type}" build_type_upper)
- if("${build_type_upper}" STREQUAL "RELEASE")
+ if(${build_type_upper} STREQUAL "RELEASE")
set(build_type_tag "") # Don't create release mode tag on installed directory
else()
set(build_type_tag "${build_type}")
@@ -381,10 +386,10 @@ function(install_matlab_scripts source_directory patterns)
# Split up filename to strip trailing '/' in GTSAM_TOOLBOX_INSTALL_PATH if there is one
get_filename_component(location "${GTSAM_TOOLBOX_INSTALL_PATH}" PATH)
get_filename_component(name "${GTSAM_TOOLBOX_INSTALL_PATH}" NAME)
- install(DIRECTORY "${source_directory}" DESTINATION "${location}/${name}${build_type_tag}" CONFIGURATIONS "${build_type}" FILES_MATCHING ${patterns_args} PATTERN ".svn" EXCLUDE)
+ install(DIRECTORY "${source_directory}" DESTINATION "${location}/${name}${build_type_tag}" CONFIGURATIONS "${build_type}" FILES_MATCHING ${patterns_args} PATTERN "${exclude_patterns}" EXCLUDE)
endforeach()
else()
- install(DIRECTORY "${source_directory}" DESTINATION "${GTSAM_TOOLBOX_INSTALL_PATH}" FILES_MATCHING ${patterns_args} PATTERN ".svn" EXCLUDE)
+ install(DIRECTORY "${source_directory}" DESTINATION "${GTSAM_TOOLBOX_INSTALL_PATH}" FILES_MATCHING ${patterns_args} PATTERN "${exclude_patterns}" EXCLUDE)
endif()
endfunction()
diff --git a/cmake/GtsamTesting.cmake b/cmake/GtsamTesting.cmake
index 4b3af9810..3e5cadd32 100644
--- a/cmake/GtsamTesting.cmake
+++ b/cmake/GtsamTesting.cmake
@@ -195,7 +195,9 @@ macro(gtsamAddTestsGlob_impl groupName globPatterns excludedFiles linkLibraries)
add_test(NAME ${target_name} COMMAND ${target_name})
add_dependencies(check.${groupName} ${target_name})
add_dependencies(check ${target_name})
- add_dependencies(all.tests ${script_name})
+ if(NOT XCODE_VERSION)
+ add_dependencies(all.tests ${script_name})
+ endif()
# Add TOPSRCDIR
set_property(SOURCE ${script_srcs} APPEND PROPERTY COMPILE_DEFINITIONS "TOPSRCDIR=\"${PROJECT_SOURCE_DIR}\"")
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 000000000..ac7af2e80
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+/html/
diff --git a/examples/Data/.gitignore b/examples/Data/.gitignore
new file mode 100644
index 000000000..2211df63d
--- /dev/null
+++ b/examples/Data/.gitignore
@@ -0,0 +1 @@
+*.txt
diff --git a/examples/Pose2SLAMExampleExpressions.cpp b/examples/Pose2SLAMExampleExpressions.cpp
index 92f94c3f3..1f6de6cb1 100644
--- a/examples/Pose2SLAMExampleExpressions.cpp
+++ b/examples/Pose2SLAMExampleExpressions.cpp
@@ -14,20 +14,18 @@
* @brief Expressions version of Pose2SLAMExample.cpp
* @date Oct 2, 2014
* @author Frank Dellaert
- * @author Yong Dian Jian
*/
// The two new headers that allow using our Automatic Differentiation Expression framework
#include
#include
-// Header order is close to far
-#include
+// For an explanation of headers below, please see Pose2SLAMExample.cpp
+#include
+#include
+#include
#include
#include
-#include
-#include
-#include
using namespace std;
using namespace gtsam;
diff --git a/examples/Pose2SLAMExample_g2o.cpp b/examples/Pose2SLAMExample_g2o.cpp
index 564930d74..35f9884e1 100644
--- a/examples/Pose2SLAMExample_g2o.cpp
+++ b/examples/Pose2SLAMExample_g2o.cpp
@@ -20,6 +20,7 @@
#include
#include
+#include
#include
#include
diff --git a/examples/Pose2SLAMExample_graph.cpp b/examples/Pose2SLAMExample_graph.cpp
index 46ca02ee4..c3d901507 100644
--- a/examples/Pose2SLAMExample_graph.cpp
+++ b/examples/Pose2SLAMExample_graph.cpp
@@ -16,11 +16,15 @@
* @author Frank Dellaert
*/
-#include
+// For an explanation of headers below, please see Pose2SLAMExample.cpp
#include
-#include
-#include
+#include
#include
+#include
+#include
+
+// This new header allows us to read examples easily from .graph files
+#include
using namespace std;
using namespace gtsam;
diff --git a/examples/Pose2SLAMExample_graphviz.cpp b/examples/Pose2SLAMExample_graphviz.cpp
index 818a9e577..314ccbdb4 100644
--- a/examples/Pose2SLAMExample_graphviz.cpp
+++ b/examples/Pose2SLAMExample_graphviz.cpp
@@ -16,11 +16,11 @@
* @author Frank Dellaert
*/
+// For an explanation of headers below, please see Pose2SLAMExample.cpp
#include
#include
-#include
-#include
#include
+#include
#include
using namespace std;
diff --git a/examples/Pose2SLAMExample_lago.cpp b/examples/Pose2SLAMExample_lago.cpp
index 9507797eb..b83dfa1db 100644
--- a/examples/Pose2SLAMExample_lago.cpp
+++ b/examples/Pose2SLAMExample_lago.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
using namespace std;
diff --git a/examples/Pose2SLAMwSPCG.cpp b/examples/Pose2SLAMwSPCG.cpp
index 4422586b0..2c25d2f8e 100644
--- a/examples/Pose2SLAMwSPCG.cpp
+++ b/examples/Pose2SLAMwSPCG.cpp
@@ -16,47 +16,15 @@
* @date June 2, 2012
*/
-/**
- * A simple 2D pose slam example solved using a Conjugate-Gradient method
- * - The robot moves in a 2 meter square
- * - The robot moves 2 meters each step, turning 90 degrees after each step
- * - The robot initially faces along the X axis (horizontal, to the right in 2D)
- * - We have full odometry between pose
- * - We have a loop closure constraint when the robot returns to the first position
- */
-
-// As this is a planar SLAM example, we will use Pose2 variables (x, y, theta) to represent
-// the robot positions
-#include
-#include
-
-// Each variable in the system (poses) 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 simple integer keys
-#include
-
-// In GTSAM, measurement functions are represented as 'factors'. Several common factors
-// have been provided with the library for solving robotics/SLAM/Bundle Adjustment problems.
-// Here we will use Between factors for the relative motion described by odometry measurements.
-// We will also use a Between Factor to encode the loop closure constraint
-// Also, we will initialize the robot at the origin using a Prior factor.
+// For an explanation of headers below, please see Pose2SLAMExample.cpp
#include
#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
-
-// 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
+#include
#include
+// In contrast to that example, however, we will use a PCG solver here
+#include
+
using namespace std;
using namespace gtsam;
@@ -66,32 +34,24 @@ int main(int argc, char** argv) {
NonlinearFactorGraph graph;
// 2a. Add a prior on the first pose, setting it to the origin
- // A prior factor consists of a mean and a noise model (covariance matrix)
Pose2 prior(0.0, 0.0, 0.0); // prior at origin
noiseModel::Diagonal::shared_ptr priorNoise = noiseModel::Diagonal::Sigmas(Vector3(0.3, 0.3, 0.1));
graph.push_back(PriorFactor(1, prior, priorNoise));
// 2b. Add odometry factors
- // For simplicity, we will use the same noise model for each odometry factor
noiseModel::Diagonal::shared_ptr odometryNoise = noiseModel::Diagonal::Sigmas(Vector3(0.2, 0.2, 0.1));
- // Create odometry (Between) factors between consecutive poses
graph.push_back(BetweenFactor(1, 2, Pose2(2.0, 0.0, M_PI_2), odometryNoise));
graph.push_back(BetweenFactor(2, 3, Pose2(2.0, 0.0, M_PI_2), odometryNoise));
graph.push_back(BetweenFactor(3, 4, Pose2(2.0, 0.0, M_PI_2), odometryNoise));
graph.push_back(BetweenFactor(4, 5, Pose2(2.0, 0.0, M_PI_2), odometryNoise));
// 2c. Add the loop closure constraint
- // This factor encodes the fact that we have returned to the same pose. In real systems,
- // these constraints may be identified in many ways, such as appearance-based techniques
- // with camera images.
- // We will use another Between Factor to enforce this constraint, with the distance set to zero,
noiseModel::Diagonal::shared_ptr model = noiseModel::Diagonal::Sigmas(Vector3(0.2, 0.2, 0.1));
graph.push_back(BetweenFactor(5, 1, Pose2(0.0, 0.0, 0.0), model));
graph.print("\nFactor Graph:\n"); // print
// 3. Create the data structure to hold the initialEstimate estimate to the solution
- // For illustrative purposes, these have been deliberately set to incorrect values
Values initialEstimate;
initialEstimate.insert(1, Pose2(0.5, 0.0, 0.2));
initialEstimate.insert(2, Pose2(2.3, 0.1, 1.1));
@@ -104,15 +64,18 @@ int main(int argc, char** argv) {
LevenbergMarquardtParams parameters;
parameters.verbosity = NonlinearOptimizerParams::ERROR;
parameters.verbosityLM = LevenbergMarquardtParams::LAMBDA;
- parameters.linearSolverType = NonlinearOptimizerParams::Iterative;
- {
- parameters.iterativeParams = boost::make_shared();
- LevenbergMarquardtOptimizer optimizer(graph, initialEstimate, parameters);
- Values result = optimizer.optimize();
- result.print("Final Result:\n");
- cout << "subgraph solver final error = " << graph.error(result) << endl;
- }
+ // LM is still the outer optimization loop, but by specifying "Iterative" below
+ // We indicate that an iterative linear solver should be used.
+ // In addition, the *type* of the iterativeParams decides on the type of
+ // iterative solver, in this case the SPCG (subgraph PCG)
+ parameters.linearSolverType = NonlinearOptimizerParams::Iterative;
+ parameters.iterativeParams = boost::make_shared();
+
+ LevenbergMarquardtOptimizer optimizer(graph, initialEstimate, parameters);
+ Values result = optimizer.optimize();
+ result.print("Final Result:\n");
+ cout << "subgraph solver final error = " << graph.error(result) << endl;
return 0;
}
diff --git a/examples/SFMExample.cpp b/examples/SFMExample.cpp
index 5be266d11..38dd1ca81 100644
--- a/examples/SFMExample.cpp
+++ b/examples/SFMExample.cpp
@@ -15,13 +15,7 @@
* @author Duy-Nguyen Ta
*/
-/**
- * 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
+// For loading the data, see the comments therein for scenario (camera rotates around cube)
#include "SFMdata.h"
// Camera observations of landmarks (i.e. pixel coordinates) will be stored as Point2 (x, y).
diff --git a/examples/SFMExample_SmartFactor.cpp b/examples/SFMExample_SmartFactor.cpp
index b999e6600..97d646552 100644
--- a/examples/SFMExample_SmartFactor.cpp
+++ b/examples/SFMExample_SmartFactor.cpp
@@ -17,51 +17,25 @@
* @author Frank Dellaert
*/
-/**
- * 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
-
// 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.
+// The factor we used here is SmartProjectionPoseFactor.
+// Every smart factor represent a single landmark, seen from multiple cameras.
+// The SmartProjectionPoseFactor only optimizes for the poses of a camera,
+// not the calibration, which is assumed 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
+// For an explanation of these headers, see SFMExample.cpp
+#include "SFMdata.h"
+#include
using namespace std;
using namespace gtsam;
// Make the typename short so it looks much cleaner
-typedef gtsam::SmartProjectionPoseFactor SmartFactor;
+typedef SmartProjectionPoseFactor SmartFactor;
+
+// create a typedef to the camera type
+typedef PinholePose Camera;
/* ************************************************************************* */
int main(int argc, char* argv[]) {
@@ -84,12 +58,12 @@ int main(int argc, char* argv[]) {
for (size_t j = 0; j < points.size(); ++j) {
// every landmark represent a single landmark, we use shared pointer to init the factor, and then insert measurements.
- SmartFactor::shared_ptr smartfactor(new SmartFactor());
+ SmartFactor::shared_ptr smartfactor(new SmartFactor(K));
for (size_t i = 0; i < poses.size(); ++i) {
// generate the 2D measurement
- SimpleCamera camera(poses[i], *K);
+ Camera camera(poses[i], K);
Point2 measurement = camera.project(points[j]);
// call add() function to add measurement into a single factor, here we need to add:
@@ -97,7 +71,7 @@ int main(int argc, char* argv[]) {
// 2. the corresponding camera's key
// 3. camera noise model
// 4. camera calibration
- smartfactor->add(measurement, i, measurementNoise, K);
+ smartfactor->add(measurement, i, measurementNoise);
}
// insert the smart factor in the graph
@@ -106,15 +80,15 @@ int main(int argc, char* argv[]) {
// Add a prior on pose x0. This indirectly specifies where the origin is.
// 30cm std on x,y,z 0.1 rad on roll,pitch,yaw
- noiseModel::Diagonal::shared_ptr poseNoise = noiseModel::Diagonal::Sigmas(
+ noiseModel::Diagonal::shared_ptr noise = noiseModel::Diagonal::Sigmas(
(Vector(6) << Vector3::Constant(0.3), Vector3::Constant(0.1)).finished());
- graph.push_back(PriorFactor(0, poses[0], poseNoise));
+ graph.push_back(PriorFactor(0, Camera(poses[0],K), noise));
// 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 of the poses will be also be fixed.
- graph.push_back(PriorFactor(1, poses[1], poseNoise)); // add directly to graph
+ graph.push_back(PriorFactor(1, Camera(poses[1],K), noise)); // add directly to graph
graph.print("Factor Graph:\n");
@@ -123,11 +97,12 @@ int main(int argc, char* argv[]) {
Values initialEstimate;
Pose3 delta(Rot3::rodriguez(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20));
for (size_t i = 0; i < poses.size(); ++i)
- initialEstimate.insert(i, poses[i].compose(delta));
+ initialEstimate.insert(i, Camera(poses[i].compose(delta), K));
initialEstimate.print("Initial Estimates:\n");
// Optimize the graph and print results
- Values result = DoglegOptimizer(graph, initialEstimate).optimize();
+ LevenbergMarquardtOptimizer optimizer(graph, initialEstimate);
+ Values result = optimizer.optimize();
result.print("Final results:\n");
// A smart factor represent the 3D point inside the factor, not as a variable.
@@ -136,20 +111,20 @@ int main(int argc, char* argv[]) {
Values landmark_result;
for (size_t j = 0; j < points.size(); ++j) {
- // The output of point() is in boost::optional, as sometimes
- // the triangulation operation inside smart factor will encounter degeneracy.
- boost::optional point;
-
// The graph stores Factor shared_ptrs, so we cast back to a SmartFactor first
SmartFactor::shared_ptr smart = boost::dynamic_pointer_cast(graph[j]);
if (smart) {
- point = smart->point(result);
+ // The output of point() is in boost::optional, as sometimes
+ // the triangulation operation inside smart factor will encounter degeneracy.
+ boost::optional point = smart->point(result);
if (point) // ignore if boost::optional return NULL
landmark_result.insert(j, *point);
}
}
landmark_result.print("Landmark results:\n");
+ cout << "final error: " << graph.error(result) << endl;
+ cout << "number of iterations: " << optimizer.iterations() << endl;
return 0;
}
diff --git a/examples/SFMExample_SmartFactorPCG.cpp b/examples/SFMExample_SmartFactorPCG.cpp
new file mode 100644
index 000000000..c1b18a946
--- /dev/null
+++ b/examples/SFMExample_SmartFactorPCG.cpp
@@ -0,0 +1,129 @@
+/* ----------------------------------------------------------------------------
+
+ * 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_SmartFactorPCG.cpp
+ * @brief Version of SFMExample_SmartFactor that uses Preconditioned Conjugate Gradient
+ * @author Frank Dellaert
+ */
+
+// For an explanation of these headers, see SFMExample_SmartFactor.cpp
+#include "SFMdata.h"
+#include
+
+// These extra headers allow us a LM outer loop with PCG linear solver (inner loop)
+#include
+#include
+#include
+
+using namespace std;
+using namespace gtsam;
+
+// Make the typename short so it looks much cleaner
+typedef SmartProjectionPoseFactor SmartFactor;
+
+// create a typedef to the camera type
+typedef PinholePose Camera;
+
+/* ************************************************************************* */
+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 and poses
+ vector points = createPoints();
+ vector poses = createPoses();
+
+ // Create a factor graph
+ NonlinearFactorGraph graph;
+
+ // Simulated measurements from each camera pose, adding them to the factor graph
+ for (size_t j = 0; j < points.size(); ++j) {
+
+ // every landmark represent a single landmark, we use shared pointer to init the factor, and then insert measurements.
+ SmartFactor::shared_ptr smartfactor(new SmartFactor(K));
+
+ for (size_t i = 0; i < poses.size(); ++i) {
+
+ // generate the 2D measurement
+ Camera camera(poses[i], K);
+ Point2 measurement = camera.project(points[j]);
+
+ // call add() function to add measurement into a single factor, here we need to add:
+ smartfactor->add(measurement, i, measurementNoise);
+ }
+
+ // insert the smart factor in the graph
+ graph.push_back(smartfactor);
+ }
+
+ // Add a prior on pose x0. This indirectly specifies where the origin is.
+ // 30cm std on x,y,z 0.1 rad on roll,pitch,yaw
+ noiseModel::Diagonal::shared_ptr noise = noiseModel::Diagonal::Sigmas(
+ (Vector(6) << Vector3::Constant(0.3), Vector3::Constant(0.1)).finished());
+ graph.push_back(PriorFactor(0, Camera(poses[0],K), noise));
+
+ // Fix the scale ambiguity by adding a prior
+ graph.push_back(PriorFactor(1, Camera(poses[0],K), noise));
+
+ // Create the initial estimate to the solution
+ Values initialEstimate;
+ Pose3 delta(Rot3::rodriguez(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20));
+ for (size_t i = 0; i < poses.size(); ++i)
+ initialEstimate.insert(i, Camera(poses[i].compose(delta),K));
+
+ // We will use LM in the outer optimization loop, but by specifying "Iterative" below
+ // We indicate that an iterative linear solver should be used.
+ // In addition, the *type* of the iterativeParams decides on the type of
+ // iterative solver, in this case the SPCG (subgraph PCG)
+ LevenbergMarquardtParams parameters;
+ parameters.linearSolverType = NonlinearOptimizerParams::Iterative;
+ parameters.absoluteErrorTol = 1e-10;
+ parameters.relativeErrorTol = 1e-10;
+ parameters.maxIterations = 500;
+ PCGSolverParameters::shared_ptr pcg =
+ boost::make_shared();
+ pcg->preconditioner_ =
+ boost::make_shared();
+ // Following is crucial:
+ pcg->setEpsilon_abs(1e-10);
+ pcg->setEpsilon_rel(1e-10);
+ parameters.iterativeParams = pcg;
+
+ LevenbergMarquardtOptimizer optimizer(graph, initialEstimate, parameters);
+ Values result = optimizer.optimize();
+
+ // Display result as in SFMExample_SmartFactor.run
+ result.print("Final results:\n");
+ Values landmark_result;
+ for (size_t j = 0; j < points.size(); ++j) {
+ SmartFactor::shared_ptr smart = //
+ boost::dynamic_pointer_cast(graph[j]);
+ if (smart) {
+ boost::optional point = smart->point(result);
+ if (point) // ignore if boost::optional return NULL
+ landmark_result.insert(j, *point);
+ }
+ }
+
+ landmark_result.print("Landmark results:\n");
+ cout << "final error: " << graph.error(result) << endl;
+ cout << "number of iterations: " << optimizer.iterations() << endl;
+
+ return 0;
+}
+/* ************************************************************************* */
+
diff --git a/examples/SolverComparer.cpp b/examples/SolverComparer.cpp
index 0f61a4220..068846884 100644
--- a/examples/SolverComparer.cpp
+++ b/examples/SolverComparer.cpp
@@ -31,28 +31,30 @@
*
*/
-#include
-#include
-#include
-#include
-#include
#include
#include
-#include
-#include
-#include
+#include
+#include
+#include
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include // for GTSAM_USE_TBB
-#include
-#include
-#include
#include
-#include
+#include
#include
#include
#include
+#include
+
+#include
+#include
#ifdef GTSAM_USE_TBB
#include
@@ -72,23 +74,6 @@ typedef NoiseModelFactor1 NM1;
typedef NoiseModelFactor2 NM2;
typedef BearingRangeFactor BR;
-//GTSAM_VALUE_EXPORT(Value);
-//GTSAM_VALUE_EXPORT(Pose);
-//GTSAM_VALUE_EXPORT(Rot2);
-//GTSAM_VALUE_EXPORT(Point2);
-//GTSAM_VALUE_EXPORT(NonlinearFactor);
-//GTSAM_VALUE_EXPORT(NoiseModelFactor);
-//GTSAM_VALUE_EXPORT(NM1);
-//GTSAM_VALUE_EXPORT(NM2);
-//GTSAM_VALUE_EXPORT(BetweenFactor);
-//GTSAM_VALUE_EXPORT(PriorFactor);
-//GTSAM_VALUE_EXPORT(BR);
-//GTSAM_VALUE_EXPORT(noiseModel::Base);
-//GTSAM_VALUE_EXPORT(noiseModel::Isotropic);
-//GTSAM_VALUE_EXPORT(noiseModel::Gaussian);
-//GTSAM_VALUE_EXPORT(noiseModel::Diagonal);
-//GTSAM_VALUE_EXPORT(noiseModel::Unit);
-
double chi2_red(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& config) {
// Compute degrees of freedom (observations - variables)
// In ocaml, +1 was added to the observations to account for the prior, but
@@ -269,12 +254,12 @@ void runIncremental()
boost::dynamic_pointer_cast >(datasetMeasurements[nextMeasurement]))
{
Key key1 = measurement->key1(), key2 = measurement->key2();
- if((key1 >= firstStep && key1 < key2) || (key2 >= firstStep && key2 < key1)) {
+ if(((int)key1 >= firstStep && key1 < key2) || ((int)key2 >= firstStep && key2 < key1)) {
// We found an odometry starting at firstStep
firstPose = std::min(key1, key2);
break;
}
- if((key2 >= firstStep && key1 < key2) || (key1 >= firstStep && key2 < key1)) {
+ if(((int)key2 >= firstStep && key1 < key2) || ((int)key1 >= firstStep && key2 < key1)) {
// We found an odometry joining firstStep with a previous pose
havePreviousPose = true;
firstPose = std::max(key1, key2);
@@ -303,7 +288,9 @@ void runIncremental()
cout << "Playing forward time steps..." << endl;
- for(size_t step = firstPose; nextMeasurement < datasetMeasurements.size() && (lastStep == -1 || step <= lastStep); ++step)
+ for (size_t step = firstPose;
+ nextMeasurement < datasetMeasurements.size() && (lastStep == -1 || (int)step <= lastStep);
+ ++step)
{
Values newVariables;
NonlinearFactorGraph newFactors;
diff --git a/examples/TimeTBB.cpp b/examples/TimeTBB.cpp
index a35980836..602a00593 100644
--- a/examples/TimeTBB.cpp
+++ b/examples/TimeTBB.cpp
@@ -17,6 +17,7 @@
#include
#include
+
#include
#include
#include