testHybridGaussianConditional.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 
28 #include <gtsam/inference/Symbol.h>
30 
31 #include <memory>
32 #include <vector>
33 
34 // Include for test suite
36 
37 using namespace gtsam;
41 
42 // Common constants
43 static const Key modeKey = M(0);
44 static const DiscreteKey mode(modeKey, 2);
45 static const VectorValues vv{{Z(0), Vector1(4.9)}, {X(0), Vector1(5.0)}};
46 static const DiscreteValues assignment0{{M(0), 0}}, assignment1{{M(0), 1}};
47 static const HybridValues hv0{vv, assignment0};
48 static const HybridValues hv1{vv, assignment1};
49 
50 /* ************************************************************************* */
51 namespace equal_constants {
52 // Create a simple HybridGaussianConditional
53 const double commonSigma = 2.0;
54 const std::vector<GaussianConditional::shared_ptr> conditionals{
56  commonSigma),
58  commonSigma)};
60 } // namespace equal_constants
61 
62 /* ************************************************************************* */
65  using namespace equal_constants;
66 
67  // Check that the conditional (negative log) normalization constant is the min
68  // of all constants which are all equal, in this case, hence:
69  const double K = hybrid_conditional.negLogConstant();
70  EXPECT_DOUBLES_EQUAL(K, conditionals[0]->negLogConstant(), 1e-8);
71  EXPECT_DOUBLES_EQUAL(K, conditionals[1]->negLogConstant(), 1e-8);
72 
75 }
76 
77 /* ************************************************************************* */
79 TEST(HybridGaussianConditional, LogProbability) {
80  using namespace equal_constants;
81  for (size_t mode : {0, 1}) {
82  const HybridValues hv{vv, {{M(0), mode}}};
83  EXPECT_DOUBLES_EQUAL(conditionals[mode]->logProbability(vv),
85  }
86 }
87 
88 /* ************************************************************************* */
91  using namespace equal_constants;
92  auto actual = hybrid_conditional.errorTree(vv);
93 
94  // Check result.
95  DiscreteKeys discrete_keys{mode};
96  std::vector<double> leaves = {conditionals[0]->error(vv),
97  conditionals[1]->error(vv)};
98  AlgebraicDecisionTree<Key> expected(discrete_keys, leaves);
99 
100  EXPECT(assert_equal(expected, actual, 1e-6));
101 
102  // Check for non-tree version.
103  for (size_t mode : {0, 1}) {
104  const HybridValues hv{vv, {{M(0), mode}}};
106  hybrid_conditional.error(hv), 1e-8);
107  }
108 }
109 
110 /* ************************************************************************* */
114  using namespace equal_constants;
115 
116  // Compute likelihood
117  auto likelihood = hybrid_conditional.likelihood(vv);
118 
119  // Check that the hybrid conditional error and the likelihood error are the
120  // same.
121  EXPECT_DOUBLES_EQUAL(hybrid_conditional.error(hv0), likelihood->error(hv0),
122  1e-8);
123  EXPECT_DOUBLES_EQUAL(hybrid_conditional.error(hv1), likelihood->error(hv1),
124  1e-8);
125 
126  // Check that likelihood error is as expected, i.e., just the errors of the
127  // individual likelihoods, in the `equal_constants` case.
128  std::vector<DiscreteKey> discrete_keys = {mode};
129  std::vector<double> leaves = {conditionals[0]->likelihood(vv)->error(vv),
130  conditionals[1]->likelihood(vv)->error(vv)};
131  AlgebraicDecisionTree<Key> expected(discrete_keys, leaves);
132  EXPECT(assert_equal(expected, likelihood->errorTree(vv), 1e-6));
133 
134  // Check that the ratio of probPrime to evaluate is the same for all modes.
135  std::vector<double> ratio(2);
136  for (size_t mode : {0, 1}) {
137  const HybridValues hv{vv, {{M(0), mode}}};
138  ratio[mode] =
139  std::exp(-likelihood->error(hv)) / hybrid_conditional.evaluate(hv);
140  }
141  EXPECT_DOUBLES_EQUAL(ratio[0], ratio[1], 1e-8);
142 }
143 
144 /* ************************************************************************* */
146 // Create a HybridGaussianConditional with mode-dependent noise models.
147 // 0 is low-noise, 1 is high-noise.
148 const std::vector<GaussianConditional::shared_ptr> conditionals{
150  0.5),
152  3.0)};
154 } // namespace mode_dependent_constants
155 
156 /* ************************************************************************* */
157 // Create a test for continuousParents.
158 TEST(HybridGaussianConditional, ContinuousParents) {
159  using namespace mode_dependent_constants;
160  const KeyVector continuousParentKeys = hybrid_conditional.continuousParents();
161  // Check that the continuous parent keys are correct:
162  EXPECT(continuousParentKeys.size() == 1);
163  EXPECT(continuousParentKeys[0] == X(0));
164 
167 }
168 
169 /* ************************************************************************* */
172  using namespace mode_dependent_constants;
173  auto actual = hybrid_conditional.errorTree(vv);
174 
175  // Check result.
176  DiscreteKeys discrete_keys{mode};
177  double negLogConstant0 = conditionals[0]->negLogConstant();
178  double negLogConstant1 = conditionals[1]->negLogConstant();
179  double minErrorConstant = std::min(negLogConstant0, negLogConstant1);
180 
181  // Expected error is e(X) + log(sqrt(|2πΣ|)).
182  // We normalize log(sqrt(|2πΣ|)) with min(negLogConstant)
183  // so it is non-negative.
184  std::vector<double> leaves = {
185  conditionals[0]->error(vv) + negLogConstant0 - minErrorConstant,
186  conditionals[1]->error(vv) + negLogConstant1 - minErrorConstant};
187  AlgebraicDecisionTree<Key> expected(discrete_keys, leaves);
188 
189  EXPECT(assert_equal(expected, actual, 1e-6));
190 
191  // Check for non-tree version.
192  for (size_t mode : {0, 1}) {
193  const HybridValues hv{vv, {{M(0), mode}}};
195  conditionals[mode]->negLogConstant() -
196  minErrorConstant,
197  hybrid_conditional.error(hv), 1e-8);
198  }
199 }
200 
201 /* ************************************************************************* */
205  using namespace mode_dependent_constants;
206 
207  // Compute likelihood
208  auto likelihood = hybrid_conditional.likelihood(vv);
209 
210  // Check that the hybrid conditional error and the likelihood error are as
211  // expected, this invariant is the same as the equal noise case:
212  EXPECT_DOUBLES_EQUAL(hybrid_conditional.error(hv0), likelihood->error(hv0),
213  1e-8);
214  EXPECT_DOUBLES_EQUAL(hybrid_conditional.error(hv1), likelihood->error(hv1),
215  1e-8);
216 
217  // Check the detailed JacobianFactor calculation for mode==1.
218  {
219  // We have a JacobianFactor
220  const auto [gf1, _] = (*likelihood)(assignment1);
221  const auto jf1 = std::dynamic_pointer_cast<JacobianFactor>(gf1);
222  CHECK(jf1);
223 
224  // Check that the JacobianFactor error with constants is equal to the
225  // conditional error:
227  jf1->error(hv1) + conditionals[1]->negLogConstant() -
229  1e-8);
230  }
231 
232  // Check that the ratio of probPrime to evaluate is the same for all modes.
233  std::vector<double> ratio(2);
234  for (size_t mode : {0, 1}) {
235  const HybridValues hv{vv, {{M(0), mode}}};
236  ratio[mode] =
237  std::exp(-likelihood->error(hv)) / hybrid_conditional.evaluate(hv);
238  }
239  EXPECT_DOUBLES_EQUAL(ratio[0], ratio[1], 1e-8);
240 }
241 
242 /* ************************************************************************* */
244 // Create a two key conditional:
245 const DiscreteKeys modes{{M(1), 2}, {M(2), 2}};
246 const std::vector<GaussianConditional::shared_ptr> gcs = {
252 const auto hgc =
253  std::make_shared<HybridGaussianConditional>(modes, conditionals);
254 } // namespace two_mode_measurement
255 
256 /* ************************************************************************* */
257 // Test pruning a HybridGaussianConditional with two discrete keys, based on a
258 // DecisionTreeFactor with 3 keys:
261 
263  keys.push_back({M(3), 2});
264  {
265  for (size_t i = 0; i < 8; i++) {
266  std::vector<double> potentials{0, 0, 0, 0, 0, 0, 0, 0};
267  potentials[i] = 1;
268  const DecisionTreeFactor decisionTreeFactor(keys, potentials);
269  // Prune the HybridGaussianConditional
270  const auto pruned =
271  hgc->prune(DiscreteConditional(keys.size(), decisionTreeFactor));
272  // Check that the pruned HybridGaussianConditional has 1 conditional
273  EXPECT_LONGS_EQUAL(1, pruned->nrComponents());
274  }
275  }
276  {
277  const std::vector<double> potentials{0, 0, 0.5, 0, //
278  0, 0, 0.5, 0};
279  const DecisionTreeFactor decisionTreeFactor(keys, potentials);
280 
281  const auto pruned =
282  hgc->prune(DiscreteConditional(keys.size(), decisionTreeFactor));
283 
284  // Check that the pruned HybridGaussianConditional has 2 conditionals
285  EXPECT_LONGS_EQUAL(2, pruned->nrComponents());
286 
287  // Check that the minimum negLogConstant is set correctly
289  hgc->conditionals()({{M(1), 0}, {M(2), 1}})->negLogConstant(),
290  pruned->negLogConstant(), 1e-9);
291  }
292  {
293  const std::vector<double> potentials{0.2, 0, 0.3, 0, //
294  0, 0, 0.5, 0};
295  const DecisionTreeFactor decisionTreeFactor(keys, potentials);
296 
297  const auto pruned =
298  hgc->prune(DiscreteConditional(keys.size(), decisionTreeFactor));
299 
300  // Check that the pruned HybridGaussianConditional has 3 conditionals
301  EXPECT_LONGS_EQUAL(3, pruned->nrComponents());
302 
303  // Check that the minimum negLogConstant is correct
304  EXPECT_DOUBLES_EQUAL(hgc->negLogConstant(), pruned->negLogConstant(), 1e-9);
305  }
306 }
307 
308 /* *************************************************************************
309  * This test verifies the behavior of the restrict method in different
310  * scenarios:
311  * - When no restrictions are applied.
312  * - When one parent is restricted.
313  * - When two parents are restricted.
314  * - When the restriction results in a Gaussian conditional.
315  */
317  // Create a HybridConditional with two discrete parents P(z0|m0,m1)
318  const auto hc =
319  std::make_shared<HybridConditional>(two_mode_measurement::hgc);
320 
321  const auto same =
322  std::dynamic_pointer_cast<HybridConditional>(hc->restrict({}));
323  CHECK(same);
324  EXPECT(same->isHybrid());
325  EXPECT(same->asHybrid()->nrComponents() == 4);
326 
327  const auto oneParent =
328  std::dynamic_pointer_cast<HybridConditional>(hc->restrict({{M(1), 0}}));
329  CHECK(oneParent);
330  EXPECT(oneParent->isHybrid());
331  EXPECT(oneParent->asHybrid()->nrComponents() == 2);
332 
333  const auto oneParent2 = std::dynamic_pointer_cast<HybridConditional>(
334  hc->restrict({{M(7), 0}, {M(1), 0}}));
335  CHECK(oneParent2);
336  EXPECT(oneParent2->isHybrid());
337  EXPECT(oneParent2->asHybrid()->nrComponents() == 2);
338 
339  const auto gaussian = std::dynamic_pointer_cast<HybridConditional>(
340  hc->restrict({{M(1), 0}, {M(2), 1}}));
341  CHECK(gaussian);
342  EXPECT(gaussian->asGaussian());
343 }
344 
345 /* ************************************************************************* */
346 int main() {
347  TestResult tr;
348  return TestRegistry::runAllTests(tr);
349 }
350 /* *************************************************************************
351  */
TestRegistry::runAllTests
static int runAllTests(TestResult &result)
Definition: TestRegistry.cpp:27
gtsam::Vector1
Eigen::Matrix< double, 1, 1 > Vector1
Definition: Vector.h:42
gtsam::DecisionTreeFactor
Definition: DecisionTreeFactor.h:45
gtsam::HybridValues
Definition: HybridValues.h:37
GaussianConditional.h
Conditional Gaussian Base class.
equal_constants::commonSigma
const double commonSigma
Definition: testHybridGaussianConditional.cpp:53
HybridGaussianConditional.h
A hybrid conditional in the Conditional Linear Gaussian scheme.
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
gtsam::HybridGaussianFactor::errorTree
AlgebraicDecisionTree< Key > errorTree(const VectorValues &continuousValues) const override
Compute error of the HybridGaussianFactor as a tree.
Definition: HybridGaussianFactor.cpp:186
EXPECT_LONGS_EQUAL
#define EXPECT_LONGS_EQUAL(expected, actual)
Definition: Test.h:154
EXPECT
#define EXPECT(condition)
Definition: Test.h:150
TestHarness.h
keys
const KeyVector keys
Definition: testRegularImplicitSchurFactor.cpp:40
gtsam::symbol_shorthand::M
Key M(std::uint64_t j)
Definition: inference/Symbol.h:160
mode_dependent_constants::hybrid_conditional
const HybridGaussianConditional hybrid_conditional(mode, conditionals)
assignment0
static const DiscreteValues assignment0
Definition: testHybridGaussianConditional.cpp:46
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
vv
static const VectorValues vv
Definition: testHybridGaussianConditional.cpp:45
exp
const EIGEN_DEVICE_FUNC ExpReturnType exp() const
Definition: ArrayCwiseUnaryOps.h:97
modeKey
static const Key modeKey
Definition: testHybridGaussianConditional.cpp:43
gtsam::KeyVector
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:92
HybridGaussianFactor.h
A set of GaussianFactors, indexed by a set of discrete keys.
assignment1
static const DiscreteValues assignment1
Definition: testHybridGaussianConditional.cpp:46
hc
Vector3d hc
Definition: Tridiagonalization_householderCoefficients.cpp:5
gtsam::AlgebraicDecisionTree< Key >
gtsam::symbol_shorthand::X
Key X(std::uint64_t j)
Definition: inference/Symbol.h:171
two_mode_measurement::gcs
const std::vector< GaussianConditional::shared_ptr > gcs
Definition: testHybridGaussianConditional.cpp:246
gtsam::HybridGaussianConditional::evaluate
double evaluate(const HybridValues &values) const override
Calculate probability density for given values.
Definition: HybridGaussianConditional.cpp:360
mode_dependent_constants
Definition: testHybridGaussianConditional.cpp:145
gtsam::HybridGaussianConditional::logProbability
double logProbability(const HybridValues &values) const override
Compute the logProbability of this hybrid Gaussian conditional.
Definition: HybridGaussianConditional.cpp:352
gtsam::VectorValues
Definition: VectorValues.h:74
gtsam::symbol_shorthand::Z
Key Z(std::uint64_t j)
Definition: inference/Symbol.h:173
mode
static const DiscreteKey mode(modeKey, 2)
DecisionTree.h
Decision Tree for use in DiscreteFactors.
gtsam::Conditional< HybridGaussianFactor, HybridGaussianConditional >::CheckInvariants
static bool CheckInvariants(const HybridGaussianConditional &conditional, const VALUES &x)
Definition: Conditional-inst.h:69
two_mode_measurement
Definition: testHybridGaussianConditional.cpp:243
cholesky::expected
Matrix expected
Definition: testMatrix.cpp:916
gtsam::HybridGaussianConditional
A conditional of gaussian conditionals indexed by discrete variables, as part of a Bayes Network....
Definition: HybridGaussianConditional.h:55
Symbol.h
gtsam::HybridGaussianConditional::continuousParents
KeyVector continuousParents() const
Returns the continuous keys among the parents.
Definition: HybridGaussianConditional.cpp:254
gtsam::HybridGaussianConditional::likelihood
std::shared_ptr< HybridGaussianFactor > likelihood(const VectorValues &given) const
Definition: HybridGaussianConditional.cpp:281
EXPECT_DOUBLES_EQUAL
#define EXPECT_DOUBLES_EQUAL(expected, actual, threshold)
Definition: Test.h:161
TestResult
Definition: TestResult.h:26
DiscreteKey.h
specialized key for discrete variables
gtsam::DecisionTree
a decision tree is a function from assignments to values.
Definition: DecisionTree.h:62
gtsam::DiscreteConditional
Definition: DiscreteConditional.h:37
two_mode_measurement::modes
const DiscreteKeys modes
Definition: testHybridGaussianConditional.cpp:245
gtsam
traits
Definition: SFMdata.h:40
gtsam::TEST
TEST(SmartFactorBase, Pinhole)
Definition: testSmartFactorBase.cpp:38
DiscreteValues.h
error
static double error
Definition: testRot3.cpp:37
K
#define K
Definition: igam.h:8
gtsam::DiscreteValues
Definition: DiscreteValues.h:34
CHECK
#define CHECK(condition)
Definition: Test.h:108
gtsam::DiscreteKey
std::pair< Key, size_t > DiscreteKey
Definition: DiscreteKey.h:38
two_mode_measurement::hgc
const auto hgc
Definition: testHybridGaussianConditional.cpp:252
main
int main()
Definition: testHybridGaussianConditional.cpp:346
two_mode_measurement::conditionals
const HybridGaussianConditional::Conditionals conditionals(modes, gcs)
equal_constants
Definition: testHybridGaussianConditional.cpp:51
ratio
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size ratio
Definition: gnuplot_common_settings.hh:44
gtsam::assert_equal
bool assert_equal(const Matrix &expected, const Matrix &actual, double tol)
Definition: Matrix.cpp:41
min
#define min(a, b)
Definition: datatypes.h:19
gtsam::HybridGaussianConditional::negLogConstant
double negLogConstant() const override
Return log normalization constant in negative log space.
Definition: HybridGaussianConditional.h:202
hv0
static const HybridValues hv0
Definition: testHybridGaussianConditional.cpp:47
gtsam::HybridGaussianFactor::error
double error(const HybridValues &values) const override
Compute the log-likelihood, including the log-normalizing constant.
Definition: HybridGaussianFactor.cpp:196
gtsam::Key
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:97
hv1
static const HybridValues hv1
Definition: testHybridGaussianConditional.cpp:48
_
constexpr descr< N - 1 > _(char const (&text)[N])
Definition: descr.h:109
Z
#define Z
Definition: icosphere.cpp:21
HybridValues.h
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
HybridConditional.h
gtsam::GaussianConditional::sharedMeanAndStddev
static shared_ptr sharedMeanAndStddev(Args &&... args)
Create shared pointer by forwarding arguments to fromMeanAndStddev.
Definition: GaussianConditional.h:126
M
Matrix< RealScalar, Dynamic, Dynamic > M
Definition: bench_gemm.cpp:51


gtsam
Author(s):
autogenerated on Wed Mar 19 2025 03:06:50