factor_graph_from_bayes_net

release/4.3a0
Frank Dellaert 2022-12-30 13:08:38 -05:00
parent 078e6b0b62
commit 23eec0bc6a
1 changed files with 41 additions and 33 deletions

View File

@ -6,7 +6,7 @@ All Rights Reserved
See LICENSE for the license information
Unit tests for Hybrid Factor Graphs.
Author: Fan Jiang
Author: Fan Jiang, Varun Agrawal, Frank Dellaert
"""
# pylint: disable=invalid-name, no-name-in-module, no-member
@ -25,6 +25,7 @@ from gtsam import (DiscreteConditional, DiscreteKeys, GaussianConditional,
class TestHybridGaussianFactorGraph(GtsamTestCase):
"""Unit tests for HybridGaussianFactorGraph."""
def test_create(self):
"""Test construction of hybrid factor graph."""
model = noiseModel.Unit.Create(3)
@ -117,23 +118,23 @@ class TestHybridGaussianFactorGraph(GtsamTestCase):
return bayesNet
def test_tiny(self):
"""Test a tiny two variable hybrid model."""
bayesNet = self.tiny()
sample = bayesNet.sample()
# print(sample)
# Create a factor graph from the Bayes net with sampled measurements.
@staticmethod
def factor_graph_from_bayes_net(bayesNet: gtsam.HybridBayesNet, sample: gtsam.HybridValues):
"""Create a factor graph from the Bayes net with sampled measurements.
The factor graph is `P(x)P(n) ϕ(x, n; z0) ϕ(x, n; z1) ...`
and thus represents the same joint probability as the Bayes net.
"""
fg = HybridGaussianFactorGraph()
conditional = bayesNet.atMixture(0)
measurement = gtsam.VectorValues()
measurement.insert(Z(0), sample.at(Z(0)))
factor = conditional.likelihood(measurement)
fg.push_back(factor)
fg.push_back(bayesNet.atGaussian(1))
fg.push_back(bayesNet.atDiscrete(2))
self.assertEqual(fg.size(), 3)
num_measurements = bayesNet.size() - 2
for i in range(num_measurements):
conditional = bayesNet.atMixture(i)
measurement = gtsam.VectorValues()
measurement.insert(Z(i), sample.at(Z(i)))
factor = conditional.likelihood(measurement)
fg.push_back(factor)
fg.push_back(bayesNet.atGaussian(num_measurements))
fg.push_back(bayesNet.atDiscrete(num_measurements+1))
return fg
@staticmethod
def calculate_ratio(bayesNet, fg, sample):
@ -143,6 +144,26 @@ class TestHybridGaussianFactorGraph(GtsamTestCase):
return bayesNet.evaluate(sample) / fg.probPrime(
continuous, sample.discrete())
def test_tiny(self):
"""Test a tiny two variable hybrid model."""
bayesNet = self.tiny()
sample = bayesNet.sample()
# print(sample)
# TODO(dellaert): do importance sampling to get an estimate P(mode)
prior = self.tiny(num_measurements=0) # just P(x0)P(mode)
for s in range(100):
proposed = prior.sample()
print(proposed)
for i in range(2):
proposed.insert(Z(i), sample.at(Z(i)))
print(proposed)
weight = bayesNet.evaluate(proposed) / prior.evaluate(proposed)
print(weight)
fg = self.factor_graph_from_bayes_net(bayesNet, sample)
self.assertEqual(fg.size(), 3)
def test_ratio(self):
"""
Given a tiny two variable hybrid model, with 2 measurements,
@ -156,20 +177,7 @@ class TestHybridGaussianFactorGraph(GtsamTestCase):
sample: gtsam.HybridValues = bayesNet.sample()
# print(sample)
# Create a factor graph from the Bayes net with sampled measurements.
# The factor graph is `P(x)P(n) ϕ(x, n; z1) ϕ(x, n; z2)`
# and thus represents the same joint probability as the Bayes net.
fg = HybridGaussianFactorGraph()
for i in range(2):
conditional = bayesNet.atMixture(i)
measurement = gtsam.VectorValues()
measurement.insert(Z(i), sample.at(Z(i)))
factor = conditional.likelihood(measurement)
fg.push_back(factor)
fg.push_back(bayesNet.atGaussian(2))
fg.push_back(bayesNet.atDiscrete(3))
# print(fg)
fg = self.factor_graph_from_bayes_net(bayesNet, sample)
self.assertEqual(fg.size(), 4)
# Calculate ratio between Bayes net probability and the factor graph:
@ -186,9 +194,9 @@ class TestHybridGaussianFactorGraph(GtsamTestCase):
other = bayesNet.sample()
other.update(measurements)
# print(other)
# ratio = self.calculate_ratio(bayesNet, fg, other)
ratio = self.calculate_ratio(bayesNet, fg, other)
# print(f"Ratio: {ratio}\n")
# self.assertAlmostEqual(ratio, expected_ratio)
self.assertAlmostEqual(ratio, expected_ratio)
if __name__ == "__main__":