/* ---------------------------------------------------------------------------- * 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 testGaussianFactorGraphB.cpp * @brief Unit tests for Linear Factor Graph * @author Christian Potthast **/ #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace gtsam; using namespace example; double tol=1e-5; using symbol_shorthand::X; using symbol_shorthand::L; static auto kUnit2 = noiseModel::Unit::Create(2); /* ************************************************************************* */ TEST( GaussianFactorGraph, equals ) { GaussianFactorGraph fg = createGaussianFactorGraph(); GaussianFactorGraph fg2 = createGaussianFactorGraph(); EXPECT(fg.equals(fg2)); } /* ************************************************************************* */ TEST( GaussianFactorGraph, error ) { GaussianFactorGraph fg = createGaussianFactorGraph(); VectorValues cfg = createZeroDelta(); // note the error is the same as in testNonlinearFactorGraph as a // zero delta config in the linear graph is equivalent to noisy in // non-linear, which is really linear under the hood double actual = fg.error(cfg); DOUBLES_EQUAL( 5.625, actual, 1e-9 ); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_x1) { GaussianFactorGraph fg = createGaussianFactorGraph(); GaussianConditional::shared_ptr conditional; auto result = fg.eliminatePartialSequential(Ordering{X(1)}); conditional = result.first->front(); // create expected Conditional Gaussian Matrix I = 15 * I_2x2, R11 = I, S12 = -0.111111 * I, S13 = -0.444444 * I; Vector d = Vector2(-0.133333, -0.0222222); GaussianConditional expected(X(1), 15 * d, R11, L(1), S12, X(2), S13); EXPECT(assert_equal(expected, *conditional, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_x2) { const Ordering ordering{X(2), L(1), X(1)}; GaussianFactorGraph fg = createGaussianFactorGraph(); auto actual = EliminateQR(fg, Ordering{X(2)}).first; // create expected Conditional Gaussian double sigma = 0.0894427; Matrix I = I_2x2 / sigma, R11 = I, S12 = -0.2 * I, S13 = -0.8 * I; Vector d = Vector2(0.2, -0.14) / sigma; GaussianConditional expected(X(2), d, R11, L(1), S12, X(1), S13, kUnit2); EXPECT(assert_equal(expected, *actual, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_l1) { const Ordering ordering{L(1), X(1), X(2)}; GaussianFactorGraph fg = createGaussianFactorGraph(); auto actual = EliminateQR(fg, Ordering{L(1)}).first; // create expected Conditional Gaussian double sigma = sqrt(2.0) / 10.; Matrix I = I_2x2 / sigma, R11 = I, S12 = -0.5 * I, S13 = -0.5 * I; Vector d = Vector2(-0.1, 0.25) / sigma; GaussianConditional expected(L(1), d, R11, X(1), S12, X(2), S13, kUnit2); EXPECT(assert_equal(expected, *actual, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_x1_fast) { GaussianFactorGraph fg = createGaussianFactorGraph(); const auto [conditional, remaining] = EliminateQR(fg, Ordering{X(1)}); // create expected Conditional Gaussian Matrix I = 15 * I_2x2, R11 = I, S12 = -0.111111 * I, S13 = -0.444444 * I; Vector d = Vector2(-0.133333, -0.0222222); GaussianConditional expected(X(1), 15 * d, R11, L(1), S12, X(2), S13, kUnit2); // Create expected remaining new factor JacobianFactor expectedFactor( L(1), (Matrix(4, 2) << 6.87184, 0, 0, 6.87184, 0, 0, 0, 0).finished(), X(2), (Matrix(4, 2) << -5.25494, 0, 0, -5.25494, -7.27607, 0, 0, -7.27607) .finished(), (Vector(4) << -1.21268, 1.73817, -0.727607, 1.45521).finished(), noiseModel::Unit::Create(4)); EXPECT(assert_equal(expected, *conditional, tol)); EXPECT(assert_equal(expectedFactor, *remaining, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_x2_fast) { GaussianFactorGraph fg = createGaussianFactorGraph(); auto actual = EliminateQR(fg, Ordering{X(2)}).first; // create expected Conditional Gaussian double sigma = 0.0894427; Matrix I = I_2x2 / sigma, R11 = -I, S12 = 0.2 * I, S13 = 0.8 * I; Vector d = Vector2(-0.2, 0.14) / sigma; GaussianConditional expected(X(2), d, R11, L(1), S12, X(1), S13, kUnit2); EXPECT(assert_equal(expected, *actual, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, eliminateOne_l1_fast) { GaussianFactorGraph fg = createGaussianFactorGraph(); auto actual = EliminateQR(fg, Ordering{L(1)}).first; // create expected Conditional Gaussian double sigma = sqrt(2.0) / 10.; Matrix I = I_2x2 / sigma, R11 = -I, S12 = 0.5 * I, S13 = 0.5 * I; Vector d = Vector2(0.1, -0.25) / sigma; GaussianConditional expected(L(1), d, R11, X(1), S12, X(2), S13, kUnit2); EXPECT(assert_equal(expected, *actual, tol)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, copying) { // Create a graph GaussianFactorGraph actual = createGaussianFactorGraph(); // Copy the graph ! GaussianFactorGraph copy = actual; // now eliminate the copy GaussianBayesNet actual1 = *copy.eliminateSequential(); // Create the same graph, but not by copying GaussianFactorGraph expected = createGaussianFactorGraph(); // and check that original is still the same graph EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, CONSTRUCTOR_GaussianBayesNet) { GaussianFactorGraph fg = createGaussianFactorGraph(); // render with a given ordering GaussianBayesNet CBN = *fg.eliminateSequential(); // True GaussianFactorGraph GaussianFactorGraph fg2(CBN); GaussianBayesNet CBN2 = *fg2.eliminateSequential(); EXPECT(assert_equal(CBN, CBN2)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, optimize_Cholesky) { // create a graph GaussianFactorGraph fg = createGaussianFactorGraph(); // optimize the graph VectorValues actual = fg.optimize(EliminateCholesky); // verify VectorValues expected = createCorrectDelta(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST( GaussianFactorGraph, optimize_QR ) { // create a graph GaussianFactorGraph fg = createGaussianFactorGraph(); // optimize the graph VectorValues actual = fg.optimize(EliminateQR); // verify VectorValues expected = createCorrectDelta(); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, combine) { // create a test graph GaussianFactorGraph fg1 = createGaussianFactorGraph(); // create another factor graph GaussianFactorGraph fg2 = createGaussianFactorGraph(); // get sizes size_t size1 = fg1.size(); size_t size2 = fg2.size(); // combine them fg1.push_back(fg2); EXPECT(size1 + size2 == fg1.size()); } /* ************************************************************************* */ // print a vector of ints if needed for debugging void print(vector v) { for (size_t k = 0; k < v.size(); k++) cout << v[k] << " "; cout << endl; } /* ************************************************************************* */ TEST(GaussianFactorGraph, createSmoother) { GaussianFactorGraph fg1 = createSmoother(2); LONGS_EQUAL(3, fg1.size()); GaussianFactorGraph fg2 = createSmoother(3); LONGS_EQUAL(5, fg2.size()); } /* ************************************************************************* */ double error(const VectorValues& x) { GaussianFactorGraph fg = createGaussianFactorGraph(); return fg.error(x); } /* ************************************************************************* */ TEST(GaussianFactorGraph, multiplication) { GaussianFactorGraph A = createGaussianFactorGraph(); VectorValues x = createCorrectDelta(); Errors actual = A * x; Errors expected; expected.push_back(Vector2(-1.0, -1.0)); expected.push_back(Vector2(2.0, -1.0)); expected.push_back(Vector2(0.0, 1.0)); expected.push_back(Vector2(-1.0, 1.5)); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ // Extra test on elimination prompted by Michael's email to Frank 1/4/2010 TEST(GaussianFactorGraph, elimination) { // Create Gaussian Factor Graph GaussianFactorGraph fg; Matrix Ap = I_1x1, An = I_1x1 * -1; Vector b = (Vector(1) << 0.0).finished(); SharedDiagonal sigma = noiseModel::Isotropic::Sigma(1, 2.0); fg.emplace_shared(X(1), An, X(2), Ap, b, sigma); fg.emplace_shared(X(1), Ap, b, sigma); fg.emplace_shared(X(2), Ap, b, sigma); // Eliminate const Ordering ordering{X(1), X(2)}; GaussianBayesNet bayesNet = *fg.eliminateSequential(); // Check matrix const auto [R, d] = bayesNet.matrix(); Matrix expected = (Matrix(2, 2) << 0.707107, -0.353553, 0.0, 0.612372).finished(); Matrix expected2 = (Matrix(2, 2) << 0.707107, -0.353553, 0.0, -0.612372).finished(); EXPECT(assert_equal(expected, R, 1e-6)); EXPECT(equal_with_abs_tol(expected, R, 1e-6) || equal_with_abs_tol(expected2, R, 1e-6)); } /* ************************************************************************* */ // Tests ported from ConstrainedGaussianFactorGraph /* ************************************************************************* */ TEST(GaussianFactorGraph, constrained_simple) { // get a graph with a constraint in it GaussianFactorGraph fg = createSimpleConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve VectorValues actual = fg.eliminateSequential()->optimize(); // verify VectorValues expected = createSimpleConstraintValues(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, constrained_single) { // get a graph with a constraint in it GaussianFactorGraph fg = createSingleConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve VectorValues actual = fg.eliminateSequential()->optimize(); // verify VectorValues expected = createSingleConstraintValues(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, constrained_multi1) { // get a graph with a constraint in it GaussianFactorGraph fg = createMultiConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve VectorValues actual = fg.eliminateSequential()->optimize(); // verify VectorValues expected = createMultiConstraintValues(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ static SharedDiagonal model = noiseModel::Isotropic::Sigma(2,1); /* ************************************************************************* */ TEST(GaussianFactorGraph, replace) { SharedDiagonal noise(noiseModel::Isotropic::Sigma(3, 1.0)); GaussianFactorGraph::sharedFactor f1(new JacobianFactor( X(1), I_3x3, X(2), I_3x3, Z_3x1, noise)); GaussianFactorGraph::sharedFactor f2(new JacobianFactor( X(2), I_3x3, X(3), I_3x3, Z_3x1, noise)); GaussianFactorGraph::sharedFactor f3(new JacobianFactor( X(3), I_3x3, X(4), I_3x3, Z_3x1, noise)); GaussianFactorGraph::sharedFactor f4(new JacobianFactor( X(5), I_3x3, X(6), I_3x3, Z_3x1, noise)); GaussianFactorGraph actual; actual.push_back(f1); actual.push_back(f2); actual.push_back(f3); actual.replace(0, f4); GaussianFactorGraph expected; expected.push_back(f4); expected.push_back(f2); expected.push_back(f3); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST(GaussianFactorGraph, hasConstraints) { FactorGraph fgc1 = createMultiConstraintGraph(); EXPECT(hasConstraints(fgc1)); FactorGraph fgc2 = createSimpleConstraintGraph() ; EXPECT(hasConstraints(fgc2)); GaussianFactorGraph fg = createGaussianFactorGraph(); EXPECT(!hasConstraints(fg)); } #include #include #include /* ************************************************************************* */ TEST( GaussianFactorGraph, conditional_sigma_failure) { // This system derives from a failure case in DDF in which a Bayes Tree // has non-unit sigmas for conditionals in the Bayes Tree, which // should never happen by construction // Reason for the failure: using Vector_() is dangerous as having a non-float gets set to zero, resulting in constraints gtsam::Key xC1 = 0, l32 = 1, l41 = 2; // noisemodels at nonlinear level gtsam::SharedNoiseModel priorModel = noiseModel::Diagonal::Sigmas((Vector(6) << 0.05, 0.05, 3.0, 0.2, 0.2, 0.2).finished()); gtsam::SharedNoiseModel measModel = kUnit2; gtsam::SharedNoiseModel elevationModel = noiseModel::Isotropic::Sigma(1, 3.0); double fov = 60; // degrees int imgW = 640; // pixels int imgH = 480; // pixels gtsam::Cal3_S2::shared_ptr K(new gtsam::Cal3_S2(fov, imgW, imgH)); typedef GenericProjectionFactor ProjectionFactor; double relElevation = 6; Values initValues; initValues.insert(xC1, Pose3(Rot3( -1., 0.0, 1.2246468e-16, 0.0, 1., 0.0, -1.2246468e-16, 0.0, -1.), Point3(0.511832102, 8.42819594, 5.76841725))); initValues.insert(l32, Point3(0.364081507, 6.89766221, -0.231582751) ); initValues.insert(l41, Point3(1.61051523, 6.7373052, -0.231582751) ); NonlinearFactorGraph factors; factors.addPrior(xC1, Pose3(Rot3( -1., 0.0, 1.2246468e-16, 0.0, 1., 0.0, -1.2246468e-16, 0.0, -1), Point3(0.511832102, 8.42819594, 5.76841725)), priorModel); factors.emplace_shared(Point2(333.648615, 98.61535), measModel, xC1, l32, K); factors.emplace_shared(Point2(218.508, 83.8022039), measModel, xC1, l41, K); factors.emplace_shared>(xC1, l32, relElevation, elevationModel); factors.emplace_shared>(xC1, l41, relElevation, elevationModel); // Check that sigmas are correct (i.e., unit) GaussianFactorGraph lfg = *factors.linearize(initValues); GaussianBayesTree actBT = *lfg.eliminateMultifrontal(); // Check that all sigmas in an unconstrained bayes tree are set to one for (const auto& [key, clique]: actBT.nodes()) { GaussianConditional::shared_ptr conditional = clique->conditional(); //size_t dim = conditional->rows(); //EXPECT(assert_equal(gtsam::Vector::Ones(dim), conditional->get_model()->sigmas(), tol)); EXPECT(!conditional->get_model()); } } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr);} /* ************************************************************************* */