216 lines
6.5 KiB
C++
216 lines
6.5 KiB
C++
/* ----------------------------------------------------------------------------
|
|
|
|
* 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 testHybridBayesTree.cpp
|
|
* @brief Unit tests for HybridBayesTree
|
|
* @author Varun Agrawal
|
|
* @date August 2022
|
|
*/
|
|
|
|
#include <gtsam/base/serializationTestHelpers.h>
|
|
#include <gtsam/discrete/DiscreteFactorGraph.h>
|
|
#include <gtsam/hybrid/HybridBayesTree.h>
|
|
#include <gtsam/hybrid/HybridGaussianISAM.h>
|
|
|
|
#include "Switching.h"
|
|
|
|
// Include for test suite
|
|
#include <CppUnitLite/TestHarness.h>
|
|
|
|
using namespace std;
|
|
using namespace gtsam;
|
|
using noiseModel::Isotropic;
|
|
using symbol_shorthand::M;
|
|
using symbol_shorthand::X;
|
|
|
|
/* ****************************************************************************/
|
|
// Test multifrontal optimize
|
|
TEST(HybridBayesTree, OptimizeMultifrontal) {
|
|
Switching s(4);
|
|
|
|
HybridBayesTree::shared_ptr hybridBayesTree =
|
|
s.linearizedFactorGraph.eliminateMultifrontal();
|
|
HybridValues delta = hybridBayesTree->optimize();
|
|
|
|
VectorValues expectedValues;
|
|
expectedValues.insert(X(0), -0.999904 * Vector1::Ones());
|
|
expectedValues.insert(X(1), -0.99029 * Vector1::Ones());
|
|
expectedValues.insert(X(2), -1.00971 * Vector1::Ones());
|
|
expectedValues.insert(X(3), -1.0001 * Vector1::Ones());
|
|
|
|
EXPECT(assert_equal(expectedValues, delta.continuous(), 1e-5));
|
|
}
|
|
|
|
/* ****************************************************************************/
|
|
// Test for optimizing a HybridBayesTree with a given assignment.
|
|
TEST(HybridBayesTree, OptimizeAssignment) {
|
|
Switching s(4);
|
|
|
|
HybridGaussianISAM isam;
|
|
HybridGaussianFactorGraph graph1;
|
|
|
|
// Add the 3 hybrid factors, x1-x2, x2-x3, x3-x4
|
|
for (size_t i = 1; i < 4; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the Gaussian factors, 1 prior on X(1),
|
|
// 3 measurements on X(2), X(3), X(4)
|
|
graph1.push_back(s.linearizedFactorGraph.at(0));
|
|
for (size_t i = 4; i <= 7; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the discrete factors
|
|
for (size_t i = 7; i <= 9; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
isam.update(graph1);
|
|
|
|
DiscreteValues assignment;
|
|
assignment[M(0)] = 1;
|
|
assignment[M(1)] = 1;
|
|
assignment[M(2)] = 1;
|
|
|
|
VectorValues delta = isam.optimize(assignment);
|
|
|
|
// The linearization point has the same value as the key index,
|
|
// e.g. X(1) = 1, X(2) = 2,
|
|
// but the factors specify X(k) = k-1, so delta should be -1.
|
|
VectorValues expected_delta;
|
|
expected_delta.insert(make_pair(X(0), -Vector1::Ones()));
|
|
expected_delta.insert(make_pair(X(1), -Vector1::Ones()));
|
|
expected_delta.insert(make_pair(X(2), -Vector1::Ones()));
|
|
expected_delta.insert(make_pair(X(3), -Vector1::Ones()));
|
|
|
|
EXPECT(assert_equal(expected_delta, delta));
|
|
|
|
// Create ordering.
|
|
Ordering ordering;
|
|
for (size_t k = 0; k < s.K; k++) ordering.push_back(X(k));
|
|
|
|
const auto [hybridBayesNet, remainingFactorGraph] =
|
|
s.linearizedFactorGraph.eliminatePartialSequential(ordering);
|
|
|
|
GaussianBayesNet gbn = hybridBayesNet->choose(assignment);
|
|
VectorValues expected = gbn.optimize();
|
|
|
|
EXPECT(assert_equal(expected, delta));
|
|
}
|
|
|
|
/* ****************************************************************************/
|
|
// Test for optimizing a HybridBayesTree.
|
|
TEST(HybridBayesTree, Optimize) {
|
|
Switching s(4);
|
|
|
|
HybridGaussianISAM isam;
|
|
HybridGaussianFactorGraph graph1;
|
|
|
|
// Add the 3 hybrid factors, x1-x2, x2-x3, x3-x4
|
|
for (size_t i = 1; i < 4; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the Gaussian factors, 1 prior on X(0),
|
|
// 3 measurements on X(2), X(3), X(4)
|
|
graph1.push_back(s.linearizedFactorGraph.at(0));
|
|
for (size_t i = 4; i <= 6; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the discrete factors
|
|
for (size_t i = 7; i <= 9; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
isam.update(graph1);
|
|
|
|
HybridValues delta = isam.optimize();
|
|
|
|
// Create ordering.
|
|
Ordering ordering;
|
|
for (size_t k = 0; k < s.K; k++) ordering.push_back(X(k));
|
|
|
|
const auto [hybridBayesNet, remainingFactorGraph] =
|
|
s.linearizedFactorGraph.eliminatePartialSequential(ordering);
|
|
|
|
DiscreteFactorGraph dfg;
|
|
for (auto&& f : *remainingFactorGraph) {
|
|
auto discreteFactor = dynamic_pointer_cast<DiscreteFactor>(f);
|
|
assert(discreteFactor);
|
|
dfg.push_back(discreteFactor);
|
|
}
|
|
|
|
// Add the probabilities for each branch
|
|
DiscreteKeys discrete_keys = {{M(0), 2}, {M(1), 2}, {M(2), 2}};
|
|
vector<double> probs = {0.012519475, 0.041280228, 0.075018647, 0.081663656,
|
|
0.037152205, 0.12248971, 0.07349729, 0.08};
|
|
dfg.emplace_shared<DecisionTreeFactor>(discrete_keys, probs);
|
|
|
|
DiscreteValues expectedMPE = dfg.optimize();
|
|
VectorValues expectedValues = hybridBayesNet->optimize(expectedMPE);
|
|
|
|
EXPECT(assert_equal(expectedMPE, delta.discrete()));
|
|
EXPECT(assert_equal(expectedValues, delta.continuous()));
|
|
}
|
|
|
|
/* ****************************************************************************/
|
|
// Test for choosing a GaussianBayesTree from a HybridBayesTree.
|
|
TEST(HybridBayesTree, Choose) {
|
|
Switching s(4);
|
|
|
|
HybridGaussianISAM isam;
|
|
HybridGaussianFactorGraph graph1;
|
|
|
|
// Add the 3 hybrid factors, x1-x2, x2-x3, x3-x4
|
|
for (size_t i = 1; i < 4; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the Gaussian factors, 1 prior on X(0),
|
|
// 3 measurements on X(2), X(3), X(4)
|
|
graph1.push_back(s.linearizedFactorGraph.at(0));
|
|
for (size_t i = 4; i <= 6; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
// Add the discrete factors
|
|
for (size_t i = 7; i <= 9; i++) {
|
|
graph1.push_back(s.linearizedFactorGraph.at(i));
|
|
}
|
|
|
|
isam.update(graph1);
|
|
|
|
DiscreteValues assignment;
|
|
assignment[M(0)] = 1;
|
|
assignment[M(1)] = 1;
|
|
assignment[M(2)] = 1;
|
|
|
|
GaussianBayesTree gbt = isam.choose(assignment);
|
|
|
|
// Specify ordering so it matches that of HybridGaussianISAM.
|
|
Ordering ordering(KeyVector{X(0), X(1), X(2), X(3), M(0), M(1), M(2)});
|
|
auto bayesTree = s.linearizedFactorGraph.eliminateMultifrontal(ordering);
|
|
|
|
auto expected_gbt = bayesTree->choose(assignment);
|
|
|
|
EXPECT(assert_equal(expected_gbt, gbt));
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
int main() {
|
|
TestResult tr;
|
|
return TestRegistry::runAllTests(tr);
|
|
}
|
|
/* ************************************************************************* */
|