testHybridGaussianFactor.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
21 #include <gtsam/base/Testable.h>
30 #include <gtsam/inference/Symbol.h>
35 
36 // Include for test suite
38 
39 #include <memory>
40 
41 using namespace std;
42 using namespace gtsam;
46 
47 /* ************************************************************************* */
48 // Check iterators of empty hybrid factor.
49 TEST(HybridGaussianFactor, Constructor) {
50  HybridGaussianFactor factor;
51  HybridGaussianFactor::const_iterator const_it = factor.begin();
52  CHECK(const_it == factor.end());
53  HybridGaussianFactor::iterator it = factor.begin();
54  CHECK(it == factor.end());
55 }
56 
57 /* ************************************************************************* */
58 namespace test_constructor {
59 DiscreteKey m1(1, 2);
60 
61 auto A1 = Matrix::Zero(2, 1);
62 auto A2 = Matrix::Zero(2, 2);
63 auto b = Matrix::Zero(2, 1);
64 
65 auto f10 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
66 auto f11 = std::make_shared<JacobianFactor>(X(1), A1, X(2), A2, b);
67 } // namespace test_constructor
68 
69 /* ************************************************************************* */
70 // Test simple to complex constructors...
71 TEST(HybridGaussianFactor, ConstructorVariants) {
72  using namespace test_constructor;
73  HybridGaussianFactor fromFactors(m1, {f10, f11});
74 
75  std::vector<GaussianFactorValuePair> pairs{{f10, 0.0}, {f11, 0.0}};
76  HybridGaussianFactor fromPairs(m1, pairs);
77  assert_equal(fromFactors, fromPairs);
78 
79  HybridGaussianFactor::FactorValuePairs decisionTree({m1}, pairs);
80  HybridGaussianFactor fromDecisionTree({m1}, decisionTree);
81  assert_equal(fromDecisionTree, fromPairs);
82 }
83 
84 /* ************************************************************************* */
85 // "Add" two hybrid factors together.
87  using namespace test_constructor;
88  DiscreteKey m2(2, 3);
89 
90  auto A3 = Matrix::Zero(2, 3);
91  auto f20 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
92  auto f21 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
93  auto f22 = std::make_shared<JacobianFactor>(X(1), A1, X(3), A3, b);
94 
95  // TODO(Frank): why specify keys at all? And: keys in factor should be *all*
96  // keys, deviating from Kevin's scheme. Should we index DT on DiscreteKey?
97  // Design review!
98  HybridGaussianFactor hybridFactorA(m1, {f10, f11});
99  HybridGaussianFactor hybridFactorB(m2, {f20, f21, f22});
100 
101  // Check the number of keys matches what we expect
102  EXPECT_LONGS_EQUAL(3, hybridFactorA.keys().size());
103  EXPECT_LONGS_EQUAL(2, hybridFactorA.continuousKeys().size());
104  EXPECT_LONGS_EQUAL(1, hybridFactorA.discreteKeys().size());
105 
106  // Create sum of two hybrid factors: it will be a decision tree now on both
107  // discrete variables m1 and m2:
109  sum += hybridFactorA;
110  sum += hybridFactorB;
111 
112  // Let's check that this worked:
114  mode[m1.first] = 1;
115  mode[m2.first] = 2;
116  auto actual = sum(mode);
117  EXPECT(actual.at(0) == f11);
118  EXPECT(actual.at(1) == f22);
119 }
120 
121 /* ************************************************************************* */
123  using namespace test_constructor;
124  HybridGaussianFactor hybridFactor(m1, {f10, f11});
125 
126  std::string expected =
127  R"(HybridGaussianFactor
128 Hybrid [x1 x2; 1]{
129  Choice(1)
130  0 Leaf :
131  A[x1] = [
132  0;
133  0
134 ]
135  A[x2] = [
136  0, 0;
137  0, 0
138 ]
139  b = [ 0 0 ]
140  No noise model
141 
142  1 Leaf :
143  A[x1] = [
144  0;
145  0
146 ]
147  A[x2] = [
148  0, 0;
149  0, 0
150 ]
151  b = [ 0 0 ]
152  No noise model
153 
154 }
155 )";
156  EXPECT(assert_print_equal(expected, hybridFactor));
157 }
158 
159 /* ************************************************************************* */
161  DiscreteKeys dKeys;
162  dKeys.emplace_back(M(0), 2);
163  dKeys.emplace_back(M(1), 2);
164 
165  auto gaussians = std::make_shared<GaussianConditional>();
168 
169  EXPECT_LONGS_EQUAL(2, gm.discreteKeys().size());
170 }
171 
172 /* ************************************************************************* */
173 // Test the error of the HybridGaussianFactor
174 TEST(HybridGaussianFactor, Error) {
175  DiscreteKey m1(1, 2);
176 
177  auto A01 = Matrix2::Identity();
178  auto A02 = Matrix2::Identity();
179 
180  auto A11 = Matrix2::Identity();
181  auto A12 = Matrix2::Identity() * 2;
182 
183  auto b = Vector2::Zero();
184 
185  auto f0 = std::make_shared<JacobianFactor>(X(1), A01, X(2), A02, b);
186  auto f1 = std::make_shared<JacobianFactor>(X(1), A11, X(2), A12, b);
187  HybridGaussianFactor hybridFactor(m1, {f0, f1});
188 
189  VectorValues continuousValues;
190  continuousValues.insert(X(1), Vector2(0, 0));
191  continuousValues.insert(X(2), Vector2(1, 1));
192 
193  // error should return a tree of errors, with nodes for each discrete value.
194  AlgebraicDecisionTree<Key> error_tree =
195  hybridFactor.errorTree(continuousValues);
196 
197  std::vector<DiscreteKey> discrete_keys = {m1};
198  // Error values for regression test
199  std::vector<double> errors = {1, 4};
200  AlgebraicDecisionTree<Key> expected_error(discrete_keys, errors);
201 
202  EXPECT(assert_equal(expected_error, error_tree));
203 
204  // Test for single leaf given discrete assignment P(X|M,Z).
205  DiscreteValues discreteValues;
206  discreteValues[m1.first] = 1;
208  4.0, hybridFactor.error({continuousValues, discreteValues}), 1e-9);
209 }
210 
211 /* ************************************************************************* */
212 namespace test_direct_factor_graph {
226  const gtsam::Values &values, const std::vector<double> &means,
227  const std::vector<double> &sigmas, DiscreteKey &m1,
228  double measurement_noise = 1e-3) {
229  auto model0 = noiseModel::Isotropic::Sigma(1, sigmas[0]);
230  auto model1 = noiseModel::Isotropic::Sigma(1, sigmas[1]);
231  auto prior_noise = noiseModel::Isotropic::Sigma(1, measurement_noise);
232 
233  auto f0 =
234  std::make_shared<BetweenFactor<double>>(X(0), X(1), means[0], model0)
235  ->linearize(values);
236  auto f1 =
237  std::make_shared<BetweenFactor<double>>(X(0), X(1), means[1], model1)
238  ->linearize(values);
239 
240  // Create HybridGaussianFactor
241  // We take negative since we want
242  // the underlying scalar to be log(\sqrt(|2πΣ|))
243  std::vector<GaussianFactorValuePair> factors{{f0, model0->negLogConstant()},
244  {f1, model1->negLogConstant()}};
245  HybridGaussianFactor motionFactor(m1, factors);
246 
248  hfg.push_back(motionFactor);
249 
250  hfg.push_back(PriorFactor<double>(X(0), values.at<double>(X(0)), prior_noise)
251  .linearize(values));
252 
253  return hfg;
254 }
255 } // namespace test_direct_factor_graph
256 
257 /* ************************************************************************* */
265 TEST(HybridGaussianFactor, DifferentMeansFG) {
266  using namespace test_direct_factor_graph;
267 
268  DiscreteKey m1(M(1), 2);
269 
270  Values values;
271  double x1 = 0.0, x2 = 1.75;
272  values.insert(X(0), x1);
273  values.insert(X(1), x2);
274 
275  std::vector<double> means = {0.0, 2.0}, sigmas = {1e-0, 1e-0};
276 
278 
279  {
280  auto bn = hfg.eliminateSequential();
281  HybridValues actual = bn->optimize();
282 
284  VectorValues{{X(0), Vector1(0.0)}, {X(1), Vector1(-1.75)}},
285  DiscreteValues{{M(1), 0}});
286 
287  EXPECT(assert_equal(expected, actual));
288 
289  DiscreteValues dv0{{M(1), 0}};
290  VectorValues cont0 = bn->optimize(dv0);
291  double error0 = bn->error(HybridValues(cont0, dv0));
292  // regression
293  EXPECT_DOUBLES_EQUAL(0.69314718056, error0, 1e-9);
294 
295  DiscreteValues dv1{{M(1), 1}};
296  VectorValues cont1 = bn->optimize(dv1);
297  double error1 = bn->error(HybridValues(cont1, dv1));
298  EXPECT_DOUBLES_EQUAL(error0, error1, 1e-9);
299  }
300 
301  {
302  auto prior_noise = noiseModel::Isotropic::Sigma(1, 1e-3);
303  hfg.push_back(
304  PriorFactor<double>(X(1), means[1], prior_noise).linearize(values));
305 
306  auto bn = hfg.eliminateSequential();
307  HybridValues actual = bn->optimize();
308 
310  VectorValues{{X(0), Vector1(0.0)}, {X(1), Vector1(0.25)}},
311  DiscreteValues{{M(1), 1}});
312 
313  EXPECT(assert_equal(expected, actual));
314 
315  {
316  DiscreteValues dv{{M(1), 0}};
317  VectorValues cont = bn->optimize(dv);
318  double error = bn->error(HybridValues(cont, dv));
319  // regression
320  EXPECT_DOUBLES_EQUAL(2.12692448787, error, 1e-9);
321  }
322  {
323  DiscreteValues dv{{M(1), 1}};
324  VectorValues cont = bn->optimize(dv);
325  double error = bn->error(HybridValues(cont, dv));
326  // regression
327  EXPECT_DOUBLES_EQUAL(0.126928487854, error, 1e-9);
328  }
329  }
330 }
331 
332 /* ************************************************************************* */
340 TEST(HybridGaussianFactor, DifferentCovariancesFG) {
341  using namespace test_direct_factor_graph;
342 
343  DiscreteKey m1(M(1), 2);
344 
345  Values values;
346  double x1 = 1.0, x2 = 1.0;
347  values.insert(X(0), x1);
348  values.insert(X(1), x2);
349 
350  std::vector<double> means = {0.0, 0.0}, sigmas = {1e2, 1e-2};
351 
352  // Create FG with HybridGaussianFactor and prior on X1
354  auto hbn = fg.eliminateSequential();
355 
356  VectorValues cv;
357  cv.insert(X(0), Vector1(0.0));
358  cv.insert(X(1), Vector1(0.0));
359 
360  // Check that the error values at the MLE point μ.
361  AlgebraicDecisionTree<Key> errorTree = hbn->errorTree(cv);
362 
363  DiscreteValues dv0{{M(1), 0}};
364  DiscreteValues dv1{{M(1), 1}};
365 
366  // regression
367  EXPECT_DOUBLES_EQUAL(9.90348755254, errorTree(dv0), 1e-9);
368  EXPECT_DOUBLES_EQUAL(0.69314718056, errorTree(dv1), 1e-9);
369 
370  DiscreteConditional expected_m1(m1, "0.5/0.5");
371  DiscreteConditional actual_m1 = *(hbn->at(2)->asDiscrete());
372 
373  EXPECT(assert_equal(expected_m1, actual_m1));
374 }
375 
376 /* ************************************************************************* */
377 int main() {
378  TestResult tr;
379  return TestRegistry::runAllTests(tr);
380 }
381 /* ************************************************************************* */
TestRegistry::runAllTests
static int runAllTests(TestResult &result)
Definition: TestRegistry.cpp:27
gtsam::EliminateableFactorGraph::eliminateSequential
std::shared_ptr< BayesNetType > eliminateSequential(OptionalOrderingType orderingType={}, const Eliminate &function=EliminationTraitsType::DefaultEliminate, OptionalVariableIndex variableIndex={}) const
Definition: EliminateableFactorGraph-inst.h:29
GaussianFactorGraph.h
Linear Factor Graph where all factors are Gaussians.
gtsam::HybridValues
Definition: HybridValues.h:37
test_constructor::b
auto b
Definition: testHybridGaussianFactor.cpp:63
test_constructor::f1
auto f1
Definition: testHybridNonlinearFactor.cpp:56
A3
static const double A3[]
Definition: expn.h:8
HybridGaussianConditional.h
A hybrid conditional in the Conditional Linear Gaussian scheme.
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
EXPECT_LONGS_EQUAL
#define EXPECT_LONGS_EQUAL(expected, actual)
Definition: Test.h:154
Testable.h
Concept check for values that can be used in unit tests.
EXPECT
#define EXPECT(condition)
Definition: Test.h:150
gtsam::Vector2
Eigen::Vector2d Vector2
Definition: Vector.h:42
test_constructor::sigmas
Vector1 sigmas
Definition: testHybridNonlinearFactor.cpp:52
TestHarness.h
test_constructor::m1
DiscreteKey m1(1, 2)
gtsam::VectorValues::insert
iterator insert(const std::pair< Key, Vector > &key_value)
Definition: VectorValues.cpp:88
test_constructor
Definition: testHybridGaussianFactor.cpp:58
gtsam::assert_print_equal
bool assert_print_equal(const std::string &expected, const V &actual, const std::string &s="")
Definition: TestableAssertions.h:352
simple_graph::factors
const GaussianFactorGraph factors
Definition: testJacobianFactor.cpp:213
gtsam::PriorFactor
Definition: nonlinear/PriorFactor.h:30
HybridBayesNet.h
A Bayes net of Gaussian Conditionals indexed by discrete keys.
different_sigmas::values
HybridValues values
Definition: testHybridBayesNet.cpp:195
X
#define X
Definition: icosphere.cpp:20
gtsam::DiscreteKeys
DiscreteKeys is a set of keys that can be assembled using the & operator.
Definition: DiscreteKey.h:41
DiscreteConditional.h
gtsam::Factor::begin
const_iterator begin() const
Definition: Factor.h:146
gtsam::means
Point2Pair means(const std::vector< Point2Pair > &abPointPairs)
Calculate the two means of a set of Point2 pairs.
Definition: Point2.cpp:116
HybridGaussianFactor.h
A set of GaussianFactors, indexed by a set of discrete keys.
equal_constants::conditionals
const std::vector< GaussianConditional::shared_ptr > conditionals
Definition: testHybridGaussianConditional.cpp:50
test_constructor::f10
auto f10
Definition: testHybridGaussianFactor.cpp:65
TestableAssertions.h
Provides additional testing facilities for common data structures.
gtsam::AlgebraicDecisionTree< Key >
m2
MatrixType m2(n_dims)
Vector1
Eigen::Matrix< double, 1, 1 > Vector1
Definition: testEvent.cpp:33
PriorFactor.h
gtsam::VectorValues
Definition: VectorValues.h:74
test_constructor::f0
auto f0
Definition: testHybridNonlinearFactor.cpp:55
BetweenFactor.h
x1
Pose3 x1
Definition: testPose3.cpp:663
mode
static const DiscreteKey mode(modeKey, 2)
A2
static const double A2[]
Definition: expn.h:7
cholesky::expected
Matrix expected
Definition: testMatrix.cpp:971
gtsam::HybridGaussianConditional
A conditional of gaussian conditionals indexed by discrete variables, as part of a Bayes Network....
Definition: HybridGaussianConditional.h:53
main
int main()
Definition: testHybridGaussianFactor.cpp:349
gtsam::HybridGaussianFactorGraph
Definition: HybridGaussianFactorGraph.h:104
test_constructor::f11
auto f11
Definition: testHybridGaussianFactor.cpp:66
Symbol.h
gtsam::Assignment< Key >
gtsam::HybridValues::insert
void insert(Key j, const Vector &value)
Definition: HybridValues.cpp:85
VectorValues.h
Factor Graph Values.
gtsam::Factor::end
const_iterator end() const
Definition: Factor.h:149
A12
static const double A12[]
Definition: expn.h:17
EXPECT_DOUBLES_EQUAL
#define EXPECT_DOUBLES_EQUAL(expected, actual, threshold)
Definition: Test.h:161
TestResult
Definition: TestResult.h:26
gtsam::DecisionTree< Key, GaussianFactorValuePair >
gtsam::DiscreteConditional
Definition: DiscreteConditional.h:37
gtsam::HybridValues::at
Vector & at(Key j)
Definition: HybridValues.cpp:129
TEST
TEST(HybridGaussianFactor, Constructor)
Definition: testHybridGaussianFactor.cpp:49
HybridGaussianFactorGraph.h
Linearized Hybrid factor graph that uses type erasure.
gtsam
traits
Definition: chartTesting.h:28
DiscreteValues.h
error
static double error
Definition: testRot3.cpp:37
gtsam::DiscreteValues
Definition: DiscreteValues.h:34
gtsam::FactorGraph::push_back
IsDerived< DERIVEDFACTOR > push_back(std::shared_ptr< DERIVEDFACTOR > factor)
Add a factor directly using a shared_ptr.
Definition: FactorGraph.h:147
gtsam::Values
Definition: Values.h:65
CHECK
#define CHECK(condition)
Definition: Test.h:108
gtsam::DiscreteKey
std::pair< Key, size_t > DiscreteKey
Definition: DiscreteKey.h:38
std
Definition: BFloat16.h:88
gtsam::HybridGaussianFactor
Implementation of a discrete-conditioned hybrid factor. Implements a joint discrete-continuous factor...
Definition: HybridGaussianFactor.h:59
A1
static const double A1[]
Definition: expn.h:6
A11
static const double A11[]
Definition: expn.h:16
gtsam::assert_equal
bool assert_equal(const Matrix &expected, const Matrix &actual, double tol)
Definition: Matrix.cpp:40
test_direct_factor_graph::CreateFactorGraph
static HybridGaussianFactorGraph CreateFactorGraph(const gtsam::Values &values, const std::vector< double > &means, const std::vector< double > &sigmas, DiscreteKey &m1, double measurement_noise=1e-3)
Create a Factor Graph by directly specifying all the factors instead of creating conditionals first....
Definition: testHybridGaussianFactor.cpp:197
test_direct_factor_graph
Definition: testHybridGaussianFactor.cpp:184
model1
noiseModel::Isotropic::shared_ptr model1
Definition: testEssentialMatrixFactor.cpp:26
Z
#define Z
Definition: icosphere.cpp:21
HybridValues.h
x2
Pose3 x2(Rot3::Ypr(0.0, 0.0, 0.0), l2)
M
Matrix< RealScalar, Dynamic, Dynamic > M
Definition: bench_gemm.cpp:51


gtsam
Author(s):
autogenerated on Fri Oct 4 2024 03:08:41