Getting Started (C++)¶
Installation¶
Add Tangent to your CMake project using FetchContent:
include(FetchContent)
FetchContent_Declare(tangent
GIT_REPOSITORY https://github.com/k-sheridan/Tangent.git
GIT_TAG main
)
FetchContent_MakeAvailable(tangent)
target_link_libraries(your_target PRIVATE Tangent::Tangent)
Requirements¶
C++20 compiler (GCC 10+, Clang 12+, MSVC 2019+)
CMake 3.20+
Eigen 3.4+ (auto-fetched if not found)
Sophus 1.22+ (auto-fetched if not found)
Testing & Benchmarking¶
Using Docker:
docker-compose up test # Run all Tangent tests
docker-compose up benchmark # Run performance benchmarks
Quick Start¶
1. Define a custom error term
#include "tangent/ErrorTerms/AutoDiffErrorTerm.h"
using namespace Tangent;
// Error term: wants two scalars to be equal
class DifferenceError
: public AutoDiffErrorTerm<DifferenceError, double, 1,
SimpleScalar, SimpleScalar> {
public:
DifferenceError(VariableKey<SimpleScalar> k1, VariableKey<SimpleScalar> k2) {
std::get<0>(variableKeys) = k1;
std::get<1>(variableKeys) = k2;
information.setIdentity();
}
// Templated error function - Jacobians are computed automatically
template <typename T, typename Scalar1, typename Scalar2>
Eigen::Matrix<T, 1, 1> computeError(const Scalar1& v1,
const Scalar2& v2) const {
Eigen::Matrix<T, 1, 1> error;
error(0) = v2 - v1;
return error;
}
};
2. Set up and run the optimizer
#include "tangent/Optimization/SSEOptimizer.h"
#include "tangent/Optimization/PSDSchurSolver.h"
#include "tangent/Optimization/HuberLossFunction.h"
// Define optimizer type (typically a type alias)
using Solver = PSDSchurSolver<
Scalar<double>,
LossFunction<HuberLossFunction<double>>,
ErrorTermGroup<DifferenceError>,
VariableGroup<SimpleScalar>,
VariableGroup<>>; // uncorrelated variables (empty here)
using Optimizer = SSEOptimizer<
Scalar<double>, Solver,
GaussianPrior<Scalar<double>, VariableGroup<SimpleScalar>>,
Marginalizer<Scalar<double>, VariableGroup<SimpleScalar>,
ErrorTermGroup<DifferenceError>>,
VariableGroup<SimpleScalar>,
ErrorTermGroup<DifferenceError>>;
// Create optimizer
HuberLossFunction<double> loss(1000);
Optimizer opt(Solver(loss));
// Add variables
auto k1 = opt.addVariable(SimpleScalar(0.0));
auto k2 = opt.addVariable(SimpleScalar(10.0));
// Add error term
opt.addErrorTerm(DifferenceError(k1, k2));
// Optimize
auto result = opt.optimize();
// Access results
double v1 = opt.getVariable(k1).value; // ~5.0
double v2 = opt.getVariable(k2).value; // ~5.0
Key concepts:
Variables: Inherit from
OptimizableVariableBase, definedimensionandupdate(delta)Error terms: Inherit from
AutoDiffErrorTerm, implementcomputeError()- Jacobians are computed automaticallyKeys: Type-safe handles for accessing variables/error terms in containers
See Concepts for more details on variables, error terms, and autodiff.
For a complete working example with SE3 poses and landmarks, see test/TestSSEOptimizer.cpp.