|
|
|
|
@ -6,6 +6,7 @@
|
|
|
|
|
|
|
|
|
|
#include <gtsam/base/debug.h>
|
|
|
|
|
#include <gtsam/base/TestableAssertions.h>
|
|
|
|
|
#include <gtsam/inference/SymbolicFactorGraph.h>
|
|
|
|
|
#include <gtsam/nonlinear/Ordering.h>
|
|
|
|
|
#include <gtsam/linear/GaussianBayesNet.h>
|
|
|
|
|
#include <gtsam/linear/GaussianSequentialSolver.h>
|
|
|
|
|
@ -43,7 +44,6 @@ ISAM2 createSlamlikeISAM2(
|
|
|
|
|
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(params);
|
|
|
|
|
// ISAM2 isam(ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false, true));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
|
|
|
|
|
@ -135,7 +135,7 @@ ISAM2 createSlamlikeISAM2(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST_UNSAFE(ISAM2, AddVariables) {
|
|
|
|
|
TEST_UNSAFE(ISAM2, ImplAddVariables) {
|
|
|
|
|
|
|
|
|
|
// Create initial state
|
|
|
|
|
Values theta;
|
|
|
|
|
@ -160,8 +160,6 @@ TEST_UNSAFE(ISAM2, AddVariables) {
|
|
|
|
|
|
|
|
|
|
Ordering ordering; ordering += 100, 0;
|
|
|
|
|
|
|
|
|
|
ISAM2::Nodes nodes(2);
|
|
|
|
|
|
|
|
|
|
// Verify initial state
|
|
|
|
|
LONGS_EQUAL(0, ordering[100]);
|
|
|
|
|
LONGS_EQUAL(1, ordering[0]);
|
|
|
|
|
@ -193,10 +191,8 @@ TEST_UNSAFE(ISAM2, AddVariables) {
|
|
|
|
|
|
|
|
|
|
Ordering orderingExpected; orderingExpected += 100, 0, 1;
|
|
|
|
|
|
|
|
|
|
ISAM2::Nodes nodesExpected(3, ISAM2::sharedClique());
|
|
|
|
|
|
|
|
|
|
// Expand initial state
|
|
|
|
|
ISAM2::Impl::AddVariables(newTheta, theta, delta, deltaNewton, deltaRg, replacedKeys, ordering, nodes);
|
|
|
|
|
ISAM2::Impl::AddVariables(newTheta, theta, delta, deltaNewton, deltaRg, replacedKeys, ordering);
|
|
|
|
|
|
|
|
|
|
EXPECT(assert_equal(thetaExpected, theta));
|
|
|
|
|
EXPECT(assert_equal(deltaExpected, delta));
|
|
|
|
|
@ -205,6 +201,95 @@ TEST_UNSAFE(ISAM2, AddVariables) {
|
|
|
|
|
EXPECT(assert_container_equality(replacedKeysExpected, replacedKeys));
|
|
|
|
|
EXPECT(assert_equal(orderingExpected, ordering));
|
|
|
|
|
}
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST_UNSAFE(ISAM2, ImplRemoveVariables) {
|
|
|
|
|
|
|
|
|
|
// Create initial state
|
|
|
|
|
Values theta;
|
|
|
|
|
theta.insert(0, Pose2(.1, .2, .3));
|
|
|
|
|
theta.insert(1, Pose2(.6, .7, .8));
|
|
|
|
|
theta.insert(100, Point2(.4, .5));
|
|
|
|
|
|
|
|
|
|
SymbolicFactorGraph sfg;
|
|
|
|
|
sfg.push_back(boost::make_shared<IndexFactor>(Index(0), Index(2)));
|
|
|
|
|
sfg.push_back(boost::make_shared<IndexFactor>(Index(0), Index(1)));
|
|
|
|
|
VariableIndex variableIndex(sfg);
|
|
|
|
|
|
|
|
|
|
VectorValues delta;
|
|
|
|
|
delta.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
delta.insert(1, Vector_(3, .4, .5, .6));
|
|
|
|
|
delta.insert(2, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
VectorValues deltaNewton;
|
|
|
|
|
deltaNewton.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
deltaNewton.insert(1, Vector_(3, .4, .5, .6));
|
|
|
|
|
deltaNewton.insert(2, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
VectorValues deltaRg;
|
|
|
|
|
deltaRg.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
deltaRg.insert(1, Vector_(3, .4, .5, .6));
|
|
|
|
|
deltaRg.insert(2, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
vector<bool> replacedKeys(3, false);
|
|
|
|
|
replacedKeys[0] = true;
|
|
|
|
|
replacedKeys[1] = false;
|
|
|
|
|
replacedKeys[2] = true;
|
|
|
|
|
|
|
|
|
|
Ordering ordering; ordering += 100, 1, 0;
|
|
|
|
|
|
|
|
|
|
ISAM2::Nodes nodes(3);
|
|
|
|
|
|
|
|
|
|
// Verify initial state
|
|
|
|
|
LONGS_EQUAL(0, ordering[100]);
|
|
|
|
|
LONGS_EQUAL(1, ordering[1]);
|
|
|
|
|
LONGS_EQUAL(2, ordering[0]);
|
|
|
|
|
|
|
|
|
|
// Create expected state
|
|
|
|
|
Values thetaExpected;
|
|
|
|
|
thetaExpected.insert(0, Pose2(.1, .2, .3));
|
|
|
|
|
thetaExpected.insert(100, Point2(.4, .5));
|
|
|
|
|
|
|
|
|
|
SymbolicFactorGraph sfgRemoved;
|
|
|
|
|
sfgRemoved.push_back(boost::make_shared<IndexFactor>(Index(0), Index(1)));
|
|
|
|
|
sfgRemoved.push_back(SymbolicFactorGraph::sharedFactor()); // Add empty factor to keep factor indices consistent
|
|
|
|
|
VariableIndex variableIndexExpected(sfgRemoved);
|
|
|
|
|
|
|
|
|
|
VectorValues deltaExpected;
|
|
|
|
|
deltaExpected.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
deltaExpected.insert(1, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
VectorValues deltaNewtonExpected;
|
|
|
|
|
deltaNewtonExpected.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
deltaNewtonExpected.insert(1, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
VectorValues deltaRgExpected;
|
|
|
|
|
deltaRgExpected.insert(0, Vector_(3, .1, .2, .3));
|
|
|
|
|
deltaRgExpected.insert(1, Vector_(2, .7, .8));
|
|
|
|
|
|
|
|
|
|
vector<bool> replacedKeysExpected(2, true);
|
|
|
|
|
|
|
|
|
|
Ordering orderingExpected; orderingExpected += 100, 0;
|
|
|
|
|
|
|
|
|
|
ISAM2::Nodes nodesExpected(2);
|
|
|
|
|
|
|
|
|
|
// Reduce initial state
|
|
|
|
|
FastSet<Key> unusedKeys;
|
|
|
|
|
unusedKeys.insert(1);
|
|
|
|
|
vector<size_t> removedFactorsI; removedFactorsI.push_back(1);
|
|
|
|
|
SymbolicFactorGraph removedFactors; removedFactors.push_back(sfg[1]);
|
|
|
|
|
variableIndex.remove(removedFactorsI, removedFactors);
|
|
|
|
|
GaussianFactorGraph linearFactors;
|
|
|
|
|
ISAM2::Impl::RemoveVariables(unusedKeys, ISAM2::sharedClique(), theta, variableIndex, delta, deltaNewton, deltaRg,
|
|
|
|
|
replacedKeys, ordering, nodes, linearFactors);
|
|
|
|
|
|
|
|
|
|
EXPECT(assert_equal(thetaExpected, theta));
|
|
|
|
|
EXPECT(assert_equal(variableIndexExpected, variableIndex));
|
|
|
|
|
EXPECT(assert_equal(deltaExpected, delta));
|
|
|
|
|
EXPECT(assert_equal(deltaNewtonExpected, deltaNewton));
|
|
|
|
|
EXPECT(assert_equal(deltaRgExpected, deltaRg));
|
|
|
|
|
EXPECT(assert_container_equality(replacedKeysExpected, replacedKeys));
|
|
|
|
|
EXPECT(assert_equal(orderingExpected, ordering));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
//TEST(ISAM2, IndicesFromFactors) {
|
|
|
|
|
@ -293,7 +378,11 @@ TEST(ISAM2, optimize2) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
bool isam_check(const planarSLAM::Graph& fullgraph, const Values& fullinit, const ISAM2& isam) {
|
|
|
|
|
bool isam_check(const planarSLAM::Graph& fullgraph, const Values& fullinit, const ISAM2& isam, Test& test, TestResult& result) {
|
|
|
|
|
|
|
|
|
|
TestResult& result_ = result;
|
|
|
|
|
const SimpleString name_ = test.getName();
|
|
|
|
|
|
|
|
|
|
Values actual = isam.calculateEstimate();
|
|
|
|
|
Ordering ordering = isam.getOrdering(); // *fullgraph.orderingCOLAMD(fullinit).first;
|
|
|
|
|
GaussianFactorGraph linearized = *fullgraph.linearize(fullinit, ordering);
|
|
|
|
|
@ -303,488 +392,94 @@ bool isam_check(const planarSLAM::Graph& fullgraph, const Values& fullinit, cons
|
|
|
|
|
VectorValues delta = optimize(gbn);
|
|
|
|
|
Values expected = fullinit.retract(delta, ordering);
|
|
|
|
|
|
|
|
|
|
return assert_equal(expected, actual);
|
|
|
|
|
bool isamEqual = assert_equal(expected, actual);
|
|
|
|
|
|
|
|
|
|
// The following two checks make sure that the cached gradients are maintained and used correctly
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
bool nodeGradientsOk = true;
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
bool gradOk = assert_equal(expectedGradient[*jit], actual);
|
|
|
|
|
EXPECT(gradOk);
|
|
|
|
|
nodeGradientsOk = nodeGradientsOk && gradOk;
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
bool dimOk = clique->gradientContribution().rows() == variablePosition;
|
|
|
|
|
EXPECT(dimOk);
|
|
|
|
|
nodeGradientsOk = nodeGradientsOk && dimOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
bool expectedGradOk = assert_equal(expectedGradient2, expectedGradient);
|
|
|
|
|
EXPECT(expectedGradOk);
|
|
|
|
|
bool totalGradOk = assert_equal(expectedGradient, actualGradient);
|
|
|
|
|
EXPECT(totalGradOk);
|
|
|
|
|
|
|
|
|
|
return nodeGradientsOk && expectedGradOk && totalGradOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST(ISAM2, slamlike_solution_gaussnewton)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false));
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST(ISAM2, slamlike_solution_dogleg)
|
|
|
|
|
{
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(ISAM2Params(ISAM2DoglegParams(1.0), 0.0, 0, false));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2DoglegParams(1.0), 0.0, 0, false));
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST(ISAM2, slamlike_solution_gaussnewton_qr)
|
|
|
|
|
{
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false, false, ISAM2Params::QR));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false, false, ISAM2Params::QR));
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST(ISAM2, slamlike_solution_dogleg_qr)
|
|
|
|
|
{
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(ISAM2Params(ISAM2DoglegParams(1.0), 0.0, 0, false, false, ISAM2Params::QR));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2DoglegParams(1.0), 0.0, 0, false, false, ISAM2Params::QR));
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
@ -888,127 +583,43 @@ TEST(ISAM2, removeFactors)
|
|
|
|
|
// then removes the 2nd-to-last landmark measurement
|
|
|
|
|
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2 isam(ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false));
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false));
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
// Remove the 2nd measurement on landmark 0 (Key 100)
|
|
|
|
|
FastVector<size_t> toRemove;
|
|
|
|
|
toRemove.push_back(12);
|
|
|
|
|
isam.update(planarSLAM::Graph(), Values(), toRemove);
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors[0]);
|
|
|
|
|
fullgraph.push_back(newfactors[2]); // Don't add measurement on landmark 0
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
ISAM2Result result = isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
|
|
|
|
|
// Remove the measurement on landmark 0
|
|
|
|
|
FastVector<size_t> toRemove;
|
|
|
|
|
EXPECT_LONGS_EQUAL(isam.getFactorsUnsafe().size()-2, result.newFactorsIndices[1]);
|
|
|
|
|
toRemove.push_back(result.newFactorsIndices[1]);
|
|
|
|
|
isam.update(planarSLAM::Graph(), Values(), toRemove);
|
|
|
|
|
}
|
|
|
|
|
// Remove the factor from the full system
|
|
|
|
|
fullgraph.remove(12);
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
TEST_UNSAFE(ISAM2, removeVariables)
|
|
|
|
|
{
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, ISAM2Params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false));
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
// Remove the measurement on landmark 0 (Key 100)
|
|
|
|
|
FastVector<size_t> toRemove;
|
|
|
|
|
toRemove.push_back(7);
|
|
|
|
|
toRemove.push_back(14);
|
|
|
|
|
isam.update(planarSLAM::Graph(), Values(), toRemove);
|
|
|
|
|
|
|
|
|
|
// Remove the factors and variable from the full system
|
|
|
|
|
fullgraph.remove(7);
|
|
|
|
|
fullgraph.remove(14);
|
|
|
|
|
fullinit.erase(100);
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
@ -1037,7 +648,7 @@ TEST_UNSAFE(ISAM2, swapFactors)
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
EXPECT(assert_equal(fullgraph, planarSLAM::Graph(isam.getFactorsUnsafe())));
|
|
|
|
|
EXPECT(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
EXPECT(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
@ -1097,7 +708,7 @@ TEST(ISAM2, constrained_ordering)
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
@ -1165,7 +776,7 @@ TEST(ISAM2, constrained_ordering)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
EXPECT(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
EXPECT(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
|
|
|
|
|
// Check that x3 and x4 are last, but either can come before the other
|
|
|
|
|
EXPECT(isam.getOrdering()[(3)] == 12 && isam.getOrdering()[(4)] == 13);
|
|
|
|
|
@ -1204,122 +815,14 @@ TEST(ISAM2, slamlike_solution_partial_relinearization_check)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// These variables will be reused and accumulate factors and values
|
|
|
|
|
ISAM2Params params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false);
|
|
|
|
|
params.enablePartialRelinearizationCheck = true;
|
|
|
|
|
ISAM2 isam(params);
|
|
|
|
|
Values fullinit;
|
|
|
|
|
planarSLAM::Graph fullgraph;
|
|
|
|
|
|
|
|
|
|
// i keeps track of the time step
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Add a prior at time 0 and update isam
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addPosePrior(0, Pose2(0.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert((0), Pose2(0.01, 0.01, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 0 to time 5
|
|
|
|
|
for( ; i<5; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 5 to 6 and landmark measurement at time 5
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0), 5.0, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
init.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
init.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert((i+1), Pose2(1.01, 0.01, 0.01));
|
|
|
|
|
fullinit.insert(100, Point2(5.0/sqrt(2.0), 5.0/sqrt(2.0)));
|
|
|
|
|
fullinit.insert(101, Point2(5.0/sqrt(2.0), -5.0/sqrt(2.0)));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 6 to time 10
|
|
|
|
|
for( ; i<10; ++i) {
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(double(i+1)+0.1, -0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add odometry from time 10 to 11 and landmark measurement at time 10
|
|
|
|
|
{
|
|
|
|
|
planarSLAM::Graph newfactors;
|
|
|
|
|
newfactors.addRelativePose(i, i+1, Pose2(1.0, 0.0, 0.0), odoNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 100, Rot2::fromAngle(M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
newfactors.addBearingRange(i, 101, Rot2::fromAngle(-M_PI/4.0 + M_PI/16.0), 4.5, brNoise);
|
|
|
|
|
fullgraph.push_back(newfactors);
|
|
|
|
|
|
|
|
|
|
Values init;
|
|
|
|
|
init.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
fullinit.insert((i+1), Pose2(6.9, 0.1, 0.01));
|
|
|
|
|
|
|
|
|
|
isam.update(newfactors, init);
|
|
|
|
|
++ i;
|
|
|
|
|
}
|
|
|
|
|
ISAM2Params params(ISAM2GaussNewtonParams(0.001), 0.0, 0, false);
|
|
|
|
|
params.enablePartialRelinearizationCheck = true;
|
|
|
|
|
ISAM2 isam = createSlamlikeISAM2(fullinit, fullgraph, params);
|
|
|
|
|
|
|
|
|
|
// Compare solutions
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam));
|
|
|
|
|
|
|
|
|
|
// Check gradient at each node
|
|
|
|
|
typedef ISAM2::sharedClique sharedClique;
|
|
|
|
|
BOOST_FOREACH(const sharedClique& clique, isam.nodes()) {
|
|
|
|
|
// Compute expected gradient
|
|
|
|
|
FactorGraph<JacobianFactor> jfg;
|
|
|
|
|
jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional())));
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(jfg, expectedGradient);
|
|
|
|
|
// Compare with actual gradients
|
|
|
|
|
int variablePosition = 0;
|
|
|
|
|
for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) {
|
|
|
|
|
const int dim = clique->conditional()->dim(jit);
|
|
|
|
|
Vector actual = clique->gradientContribution().segment(variablePosition, dim);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient[*jit], actual));
|
|
|
|
|
variablePosition += dim;
|
|
|
|
|
}
|
|
|
|
|
LONGS_EQUAL(clique->gradientContribution().rows(), variablePosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check gradient
|
|
|
|
|
VectorValues expectedGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(FactorGraph<JacobianFactor>(isam), expectedGradient);
|
|
|
|
|
VectorValues expectedGradient2(gradient(FactorGraph<JacobianFactor>(isam), VectorValues::Zero(expectedGradient)));
|
|
|
|
|
VectorValues actualGradient(*allocateVectorValues(isam));
|
|
|
|
|
gradientAtZero(isam, actualGradient);
|
|
|
|
|
EXPECT(assert_equal(expectedGradient2, expectedGradient));
|
|
|
|
|
EXPECT(assert_equal(expectedGradient, actualGradient));
|
|
|
|
|
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
|