Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
4a0d802
WNOA Motion Prior Factor + Lost-in-the-woods dataset
holmesco Jul 18, 2025
27c1a0e
- Extended WNOA Factor to handle vector spaces
SvenLilge Jul 30, 2025
9ee58d7
Implemented unit tests for Point1 manifold
SvenLilge Jul 30, 2025
875ac2a
Added WNOA unit tests for Point1, Point2, Point3 manifolds
SvenLilge Jul 30, 2025
ff1cf7e
Implemented GiantGlassOfMilk dataset example
SvenLilge Jul 30, 2025
5ec7e7d
Added plotting script for GiantGlassOfMilk example
SvenLilge Jul 30, 2025
749183a
- WNOA Motion Prior Factor for Vector Spaces
SvenLilge Jul 30, 2025
514b722
Inputs for LITW example are now coming from a yaml file for easy tuni…
holmesco Jul 24, 2025
d209931
Added steam and lgmath to docker container. Started building steam re…
holmesco Jul 29, 2025
e4f87d5
steam running for odometry and WNOA prior for LostInTheWoods
holmesco Jul 30, 2025
05d9ce7
STEAM implementation matches GTSAM for Lost in the woods with odometr…
holmesco Jul 31, 2025
bebc7d0
Added bearing-range measurements into STEAM version of the problem.
holmesco Aug 2, 2025
6e4027f
Moved bearing-range error class into steam repo
holmesco Aug 3, 2025
98ec454
initial A3 implementation
Jul 24, 2025
51acbe2
implemented post-solve interpolation for WNOA - should be easy to ext…
Aug 4, 2025
58a2627
Merge pull request #1 from utiasASRL/daniel_rebased
qetuo1098 Aug 4, 2025
4f10af5
small adjustments to interpolator to work for Point1/2/3 manifolds
SvenLilge Aug 5, 2025
d657b8d
moved WNOA files to nonlinear subdir
holmesco Aug 6, 2025
76e2ed4
small changes
Aug 5, 2025
b167759
refactored interpolator. started covariance interpolation (not workin…
Aug 12, 2025
5d92109
covariance interpolation works after reordering MarginalCovariance
Aug 12, 2025
a432d11
covariance interpolation should work for any user-defined name for po…
Aug 12, 2025
9365b2a
Interpolator fixes + covariance computation
holmesco Aug 13, 2025
37aa00f
started Interpolator unit tests
Aug 14, 2025
dd29742
interpolator unit tests
Aug 20, 2025
a8fb192
added extrapolation for the mean, and unit tests for extrapolation
Aug 20, 2025
e212023
move covariance interpolation inside of interpolatePoseAndVelocity (n…
Aug 20, 2025
aa1e1fe
added covariance extrapolation
Aug 20, 2025
d8915cf
Merge pull request #3 from utiasASRL/interpolator-unit-test
holmesco Aug 21, 2025
53f66cd
Merge pull request #4 from utiasASRL/interpolator-extrapolate
holmesco Aug 21, 2025
b326c71
WNOA Interpolation Wrapper Factor (#5)
holmesco Aug 25, 2025
c760451
Adding option to run SLAM on A2
SvenLilge Aug 25, 2025
6ca66ed
Adding option to run SLAM on A2
holmesco Aug 25, 2025
1cc5189
Interpolator bug fix:
holmesco Aug 25, 2025
711d535
Runtime optimization (#7)
SvenLilge Aug 25, 2025
f685a5d
split Interpolator into cpp (#8)
qetuo1098 Aug 25, 2025
b220a37
adding covariances and jacobians when interpolating to a discrete time
SvenLilge Aug 25, 2025
b9da0e1
bug fix
SvenLilge Aug 25, 2025
b4a91bd
added alternative method to compute lambda and psi during covariance …
qetuo1098 Aug 26, 2025
0747771
Adding Jacobians and Covariance to discrete states in interpolator
SvenLilge Aug 26, 2025
d5b87e8
Merge branch 'develop' into interpolate_discrete
SvenLilge Aug 26, 2025
8936bf0
added A3 data
Aug 26, 2025
a98caa9
added config file for A1 example
SvenLilge Aug 26, 2025
e13484c
removing obsolete comment
SvenLilge Aug 26, 2025
fa7641d
Returning Jacobians and Covariances when requesting states at non-int…
holmesco Aug 26, 2025
9f6f996
ordered sets of StateData structure update (#11)
holmesco Aug 27, 2025
634c9d3
In Interpolator
Aug 27, 2025
bbe5c7a
WNOA Prior Factor StateData input constructor (#12)
holmesco Aug 28, 2025
13ee3c0
- changed ordering of TimestampedPoseVel to be (pose, vel, time)
Aug 28, 2025
4a1ab60
Update Interpolator to use StateData
holmesco Aug 28, 2025
3701f58
Changing computation of Lambda and Psi to be more efficient
SvenLilge Aug 29, 2025
7a8975e
Adding back in general code for LambdaPsi
SvenLilge Aug 29, 2025
243b0d4
working on caching of interpolated values
SvenLilge Aug 29, 2025
e16bbe8
Changing computation of Lambda and Psi to be more efficient (#15)
SvenLilge Aug 29, 2025
bb2c451
Remove SafeMatrixAdd function.
holmesco Aug 29, 2025
179f116
Replace `safeMatAdd` function
holmesco Aug 29, 2025
72dba33
Working on caching of interpolated values
SvenLilge Aug 29, 2025
44e9754
Separate analyses directory (#19)
holmesco Sep 5, 2025
2b7449b
Profiling
SvenLilge Sep 5, 2025
790ffc7
Working on graph to compute interpolated values and Jacobians once
SvenLilge Sep 5, 2025
9811621
Merge branch 'develop' into cache_interpolated_values
SvenLilge Sep 5, 2025
76060f3
debugging
SvenLilge Sep 8, 2025
4816a8a
Slightly faster interp covariance (#22)
qetuo1098 Sep 8, 2025
4104718
Clean up interpolation function (#23)
holmesco Sep 10, 2025
88f6d11
precomputing cached values is now faster if multi-threading is turned…
SvenLilge Sep 12, 2025
7c90f9a
slight debugging
SvenLilge Sep 12, 2025
37259bc
added shorthand for querying which factor is a wrapper factor
SvenLilge Sep 12, 2025
855148c
disable LM verbosity
SvenLilge Sep 12, 2025
2805d3f
TODO: parallelization
SvenLilge Sep 12, 2025
7354c27
Further runtime optimizations
SvenLilge Sep 15, 2025
e042dc6
flatten Jacobian map
SvenLilge Sep 16, 2025
1e245cb
Revert "flatten Jacobian map"
SvenLilge Sep 16, 2025
f057c94
profiling
SvenLilge Sep 16, 2025
89037df
removed outer key caching from WNOAInterpFactor as it broke unit test
SvenLilge Sep 16, 2025
9a49643
Profiling
SvenLilge Sep 16, 2025
d99d151
Merge branch 'develop' into cache_interpolated_values
SvenLilge Sep 16, 2025
0de7ea7
Fix plotting script for A1
SvenLilge Sep 16, 2025
47a12a6
Added detailed timing analysis to investigate bottlenecks
SvenLilge Sep 20, 2025
87623a9
Merge pull request #24 from utiasASRL/cache_interpolated_values
holmesco Oct 13, 2025
2a39b7a
[WIP] Interpolator speed up (#26)
holmesco Oct 20, 2025
565571e
Cache interpolated values (#27)
SvenLilge Dec 6, 2025
6333eac
API cleanup (#28)
SvenLilge Jan 6, 2026
23587a6
Set up devcontainer
holmesco Feb 6, 2026
52928ef
Merge remote-tracking branch 'upstream/develop' into develop
holmesco Feb 6, 2026
0a006a9
Remove analyses files used for paper.
holmesco Feb 10, 2026
9b0ec45
Fix chrono bug for Equiv Filter Ex (see issue #2366).
holmesco Feb 10, 2026
4f88d9c
remove dev container
holmesco Feb 10, 2026
e09775b
reset timing files
holmesco Feb 10, 2026
a3e75ab
cleanup comment
holmesco Feb 10, 2026
e501461
Reformat files. Add cleanup flags where cleanup needed. Add comments …
holmesco Feb 11, 2026
e11127a
Add cleanup comments. Reformat. Add explanatory comments
holmesco Feb 11, 2026
dc45b84
Added comments for caching mappings from inner keys to outer keys (th…
SvenLilge Feb 12, 2026
3587430
Added comments for WNOAFactorGraph interpolation function. Specifical…
SvenLilge Feb 12, 2026
850944f
Merge branch 'develop' into cache_interpolated_values
SvenLilge Sep 16, 2025
571bd80
added option for slam in A3. cleaned up matlab file for A3.
Feb 12, 2026
f9b91e3
revert a comment
Feb 12, 2026
23aae76
removed dead code
Feb 12, 2026
601936e
removed dead results
Feb 12, 2026
3514923
Rename Interpolator to WNOAInterpolator
holmesco Feb 13, 2026
9b811d8
Remove "small_angle" versions of methods.
holmesco Feb 14, 2026
5dfe3fb
Remove tictocs.
holmesco Feb 14, 2026
3956eb9
Merge pull request #29 from utiasASRL/code-cleanup
holmesco Feb 14, 2026
9d5236d
Add files from dev repo
holmesco Feb 16, 2026
cec55e4
Add StateData file. Rename StateData header file to WNOAStateData. Ad…
holmesco Feb 16, 2026
d338cd4
Resolved all copilot comments. Namely, removal of `using namespace std`
holmesco Feb 17, 2026
f2a6b4a
Second round of copilot comments. Some changes to improve search time…
holmesco Feb 17, 2026
869985e
precomputation of interpolation matrices (lambda psi) now uses an uno…
SvenLilge Feb 20, 2026
a5d7022
remove references to boost
holmesco Feb 21, 2026
cb1a4cc
Add export macro for class defined in cpp file.
holmesco Feb 21, 2026
afa48a3
Merge remote-tracking branch 'upstream/develop' into develop
holmesco Feb 21, 2026
a31764d
Merge updates from PR branch
holmesco Feb 21, 2026
6d0a771
Updates to remove using namespace std
holmesco Feb 21, 2026
cbbe25f
Remove examples
holmesco Feb 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/build
/build-steam
/debug*
.idea
*.pyc
Expand All @@ -19,13 +20,26 @@ vcpkg_installed/
# for QtCreator:
CMakeLists.txt.user*
xcode/
/Dockerfile
# /Dockerfile
/python/gtsam/notebooks/.ipynb_checkpoints/ellipses-checkpoint.ipynb
.cache/
.venv/

# MyST build outputs
_build

/lib
/include
*.egg-info
/results/*.csv
/examples/*.asv
uv.lock

# analyses
analyses/build
analyses/results
analyses/plots
*callgrind.out*
GEMINI.md
doc/#*.lyx#
/cmake-build-debug/
Expand Down
1 change: 1 addition & 0 deletions examples/AbcEquivariantFilterExample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <gtsam/slam/dataset.h>
#include <gtsam_unstable/geometry/ABC.h>
#include <gtsam_unstable/geometry/ABCEquivariantFilter.h>
#include <chrono>

#include <array>
#include <chrono>
Expand Down
2 changes: 1 addition & 1 deletion examples/Data/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
*.txt

110 changes: 82 additions & 28 deletions examples/Pose2SLAMExample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,49 +20,87 @@
* A simple 2D pose slam example
* - 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)
* - 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
* - We have a loop closure constraint when the robot returns to the first
* position
*/

// In planar SLAM example we use Pose2 variables (x, y, theta) to represent the robot poses
// In planar SLAM example we use Pose2 variables (x, y, theta) to represent the
// robot poses
#include <gtsam/geometry/Pose2.h>

// We will use simple integer Keys to refer to the robot poses.
#include <gtsam/inference/Key.h>

// 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.
// 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.
#include <gtsam/slam/BetweenFactor.h>

// 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.
// 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 <gtsam/nonlinear/NonlinearFactorGraph.h>

// 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 the
// a Gauss-Newton solver
// 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 the a Gauss-Newton solver
#include <gtsam/nonlinear/GaussNewtonOptimizer.h>

// Once the optimized values have been calculated, we can also calculate the marginal covariance
// of desired variables
// Once the optimized values have been calculated, we can also calculate the
// marginal covariance of desired variables
#include <gtsam/nonlinear/Marginals.h>

// 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.
// 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 <gtsam/nonlinear/Values.h>
#include <gtsam/slam/dataset.h>

#include <iomanip>

using namespace std;
using namespace gtsam;

// --- Save Poses to CSV ---
int saveResultToFile(Values& result, NonlinearFactorGraph& graph,
const string& filename) {
// Get marginals
Marginals marginals(graph, result);

// open file, print header
ofstream poses_file(filename);
if (poses_file.is_open()) {
poses_file
<< "key,x,y,theta,C11,C12,C13,C22,C23,C33\n"; // Header for Pose2
// filter results for pose2
for (const auto& [key, pose] : result.extract<Pose2>()) {
Matrix cov = marginals.marginalCovariance(key);
poses_file << key << "," << setprecision(6) << pose.x() << ","
<< setprecision(6) << pose.y() << "," << setprecision(6)
<< pose.theta() << "," << setprecision(6) << cov(0, 0) << ","
<< setprecision(6) << cov(0, 1) << "," << setprecision(6)
<< cov(0, 2) << "," << setprecision(6) << cov(1, 1) << ","
<< setprecision(6) << cov(1, 2) << "," << setprecision(6)
<< cov(2, 2) << "\n";
}
poses_file.close();
return 1;
} else {
cerr << "Error opening file" << endl;
return 0;
}
}

int main(int argc, char** argv) {
// 1. Create a factor graph container and add factors to it
NonlinearFactorGraph graph;
Expand All @@ -72,7 +110,8 @@ int main(int argc, char** argv) {
auto priorNoise = noiseModel::Diagonal::Sigmas(Vector3(0.3, 0.3, 0.1));
graph.addPrior(1, Pose2(0, 0, 0), priorNoise);

// For simplicity, we will use the same noise model for odometry and loop closures
// For simplicity, we will use the same noise model for odometry and loop
// closures
auto model = noiseModel::Diagonal::Sigmas(Vector3(0.2, 0.2, 0.1));

// 2b. Add odometry factors
Expand All @@ -83,14 +122,16 @@ int main(int argc, char** argv) {
graph.emplace_shared<BetweenFactor<Pose2> >(4, 5, Pose2(2, 0, M_PI_2), model);

// 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:
// 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:
graph.emplace_shared<BetweenFactor<Pose2> >(5, 2, Pose2(2, 0, M_PI_2), model);
graph.print("\nFactor Graph:\n"); // print

// 3. Create the data structure to hold the initialEstimate estimate to the solution
// For illustrative purposes, these have been deliberately set to incorrect values
// 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, -0.2));
Expand All @@ -105,7 +146,8 @@ int main(int argc, char** argv) {
// system solver to use, and the amount of information displayed during
// optimization. We will set a few parameters as a demonstration.
GaussNewtonParams parameters;
// Stop iterating once the change in error between steps is less than this value
// Stop iterating once the change in error between steps is less than this
// value
parameters.relativeErrorTol = 1e-5;
// Do not perform more than N iteration steps
parameters.maxIterations = 100;
Expand All @@ -124,5 +166,17 @@ int main(int argc, char** argv) {
cout << "x4 covariance:\n" << marginals.marginalCovariance(4) << endl;
cout << "x5 covariance:\n" << marginals.marginalCovariance(5) << endl;

// save to file
string outfile = "../results/Pose2SLAMExample.csv";
if (argc > 1) {
outfile = argv[1];
}
int success = saveResultToFile(result, graph, outfile);
if (!success) {
cerr << "Failed to save results to file." << endl;
return 1;
}
cout << "Results saved to " << outfile << endl;

return 0;
}
44 changes: 44 additions & 0 deletions gtsam/geometry/Point1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <gtsam/geometry/Point1.h>
#include <cmath>
#include <iostream>



using namespace std;

namespace gtsam {

/* ************************************************************************* */
double norm1(const Point1& p, OptionalJacobian<1,1> H) {
double r = std::abs(p.x());
if (H) {
if (std::abs(p.x()) > 1e-10)
*H << (p.x() >= 0 ? 1.0 : -1.0);
else
*H << 1.0; // derivative of abs(x) at x=0 is undefined, using 1 as convention
}
return r;
}

/* ************************************************************************* */
double distance1(const Point1& p, const Point1& q, OptionalJacobian<1, 1> H1,
OptionalJacobian<1, 1> H2) {
Point1 d = q - p;
if (H1 || H2) {
Matrix11 H;
double r = norm1(d, H);
if (H1) *H1 = -H;
if (H2) *H2 = H;
return r;
} else {
return std::abs(d.x());
}
}

/* ************************************************************************* */
ostream &operator<<(ostream &os, const gtsam::Point1Pair &p) {
os << p.first << " <-> " << p.second;
return os;
}

} // namespace gtsam
81 changes: 81 additions & 0 deletions gtsam/geometry/Point1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#pragma once

#include <gtsam/base/Manifold.h>
#include <gtsam/base/OptionalJacobian.h>
#include <gtsam/base/VectorSpace.h>
#include <gtsam/base/std_optional_serialization.h>
#if GTSAM_ENABLE_BOOST_SERIALIZATION
#include <boost/serialization/nvp.hpp>
#endif

#include <iostream>
#include <optional>
#include <utility>
#include <vector>

namespace gtsam {

typedef Vector1 Point1;

/// Convenience typedefs
using Point1Pair = std::pair<Point1, Point1>;
using Point1Pairs = std::vector<Point1Pair>;

/**
* @brief Stream insertion operator for Point1Pair.
*
* Outputs a human-readable representation of a Point1Pair to the given output
* stream.
*
* @param os The output stream to write to.
* @param p The Point1Pair to be serialized to the stream.
* @return A reference to the output stream \p os after insertion.
*/
GTSAM_EXPORT std::ostream& operator<<(std::ostream& os,
const gtsam::Point1Pair& p);

/**
* @brief Compute the distance between point and origin.
*
* Calculates the absolute distance between two Point1 objects,
* with optional Jacobians with respect to each point.
*
* @param p The first 1D point.
* @param H Optional Jacobian of the distance with respect to the first point \p
* p1.
* @return The scalar distance between \p p and 0.
*/
GTSAM_EXPORT double norm1(const Point1& p, OptionalJacobian<1, 1> H = {});

/**
* @brief Compute the distance between two 1D points.
*
* Calculates the absolute distance between two Point1 objects,
* with optional Jacobians with respect to each point.
*
* @param p1 The first 1D point.
* @param q The second 1D point.
* @param H1 Optional Jacobian of the distance with respect to the first point
* \p p1.
* @param H2 Optional Jacobian of the distance with respect to the second point
* \p q.
* @return The scalar distance between \p p1 and \p q.
*/
GTSAM_EXPORT double distance1(const Point1& p1, const Point1& q,
OptionalJacobian<1, 1> H1 = {},
OptionalJacobian<1, 1> H2 = {});

template <typename A1, typename A2>
struct Range;

template <>
struct Range<Point1, Point1> {
typedef double result_type;
double operator()(const Point1& p, const Point1& q,
OptionalJacobian<1, 1> H1 = {},
OptionalJacobian<1, 1> H2 = {}) {
return distance1(p, q, H1, H2);
}
};

} // namespace gtsam
Loading
Loading