Fixed discreteEimination
parent
0f48efb0a9
commit
524161403a
|
@ -229,12 +229,12 @@ static std::pair<HybridConditional::shared_ptr, std::shared_ptr<Factor>> discret
|
||||||
// In this case, compute discrete probabilities.
|
// In this case, compute discrete probabilities.
|
||||||
// TODO(frank): What about the scalar!?
|
// TODO(frank): What about the scalar!?
|
||||||
auto potential = [&](const auto& pair) -> double {
|
auto potential = [&](const auto& pair) -> double {
|
||||||
auto [factor, _] = pair;
|
auto [factor, scalar] = pair;
|
||||||
// If the factor is null, it has been pruned, hence return potential of zero
|
// If the factor is null, it has been pruned, hence return potential of zero
|
||||||
if (!factor)
|
if (!factor)
|
||||||
return 0;
|
return 0.0;
|
||||||
else
|
else
|
||||||
return exp(-factor->error(kEmpty));
|
return exp(-scalar - factor->error(kEmpty));
|
||||||
};
|
};
|
||||||
DecisionTree<Key, double> potentials(gmf->factors(), potential);
|
DecisionTree<Key, double> potentials(gmf->factors(), potential);
|
||||||
dfg.emplace_shared<DecisionTreeFactor>(gmf->discreteKeys(), potentials);
|
dfg.emplace_shared<DecisionTreeFactor>(gmf->discreteKeys(), potentials);
|
||||||
|
|
|
@ -40,8 +40,7 @@ const DiscreteKey m(M(0), 2);
|
||||||
const DiscreteValues m1Assignment{{M(0), 1}};
|
const DiscreteValues m1Assignment{{M(0), 1}};
|
||||||
|
|
||||||
// Define a 50/50 prior on the mode
|
// Define a 50/50 prior on the mode
|
||||||
DiscreteConditional::shared_ptr mixing =
|
DiscreteConditional::shared_ptr mixing = std::make_shared<DiscreteConditional>(m, "60/40");
|
||||||
std::make_shared<DiscreteConditional>(m, "60/40");
|
|
||||||
|
|
||||||
/// Gaussian density function
|
/// Gaussian density function
|
||||||
double Gaussian(double mu, double sigma, double z) {
|
double Gaussian(double mu, double sigma, double z) {
|
||||||
|
@ -53,24 +52,12 @@ double Gaussian(double mu, double sigma, double z) {
|
||||||
* If sigma0 == sigma1, it simplifies to a sigmoid function.
|
* If sigma0 == sigma1, it simplifies to a sigmoid function.
|
||||||
* Hardcodes 60/40 prior on mode.
|
* Hardcodes 60/40 prior on mode.
|
||||||
*/
|
*/
|
||||||
double prob_m_z(double mu0, double mu1, double sigma0, double sigma1,
|
double prob_m_z(double mu0, double mu1, double sigma0, double sigma1, double z) {
|
||||||
double z) {
|
|
||||||
const double p0 = 0.6 * Gaussian(mu0, sigma0, z);
|
const double p0 = 0.6 * Gaussian(mu0, sigma0, z);
|
||||||
const double p1 = 0.4 * Gaussian(mu1, sigma1, z);
|
const double p1 = 0.4 * Gaussian(mu1, sigma1, z);
|
||||||
return p1 / (p0 + p1);
|
return p1 / (p0 + p1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given \phi(m;z)\phi(m) use eliminate to obtain P(m|z).
|
|
||||||
DiscreteConditional SolveHFG(const HybridGaussianFactorGraph &hfg) {
|
|
||||||
return *hfg.eliminateSequential()->at(0)->asDiscrete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given p(z,m) and z, convert to HFG and solve.
|
|
||||||
DiscreteConditional SolveHBN(const HybridBayesNet &hbn, double z) {
|
|
||||||
VectorValues given{{Z(0), Vector1(z)}};
|
|
||||||
return SolveHFG(hbn.toFactorGraph(given));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test a Gaussian Mixture Model P(m)p(z|m) with same sigma.
|
* Test a Gaussian Mixture Model P(m)p(z|m) with same sigma.
|
||||||
* The posterior, as a function of z, should be a sigmoid function.
|
* The posterior, as a function of z, should be a sigmoid function.
|
||||||
|
@ -81,14 +68,14 @@ TEST(GaussianMixture, GaussianMixtureModel) {
|
||||||
|
|
||||||
// Create a Gaussian mixture model p(z|m) with same sigma.
|
// Create a Gaussian mixture model p(z|m) with same sigma.
|
||||||
HybridBayesNet gmm;
|
HybridBayesNet gmm;
|
||||||
std::vector<std::pair<Vector, double>> parameters{{Vector1(mu0), sigma},
|
std::vector<std::pair<Vector, double>> parameters{{Vector1(mu0), sigma}, {Vector1(mu1), sigma}};
|
||||||
{Vector1(mu1), sigma}};
|
|
||||||
gmm.emplace_shared<HybridGaussianConditional>(m, Z(0), parameters);
|
gmm.emplace_shared<HybridGaussianConditional>(m, Z(0), parameters);
|
||||||
gmm.push_back(mixing);
|
gmm.push_back(mixing);
|
||||||
|
|
||||||
// At the halfway point between the means, we should get P(m|z)=0.5
|
// At the halfway point between the means, we should get P(m|z)=0.5
|
||||||
double midway = mu1 - mu0;
|
double midway = mu1 - mu0;
|
||||||
auto pMid = SolveHBN(gmm, midway);
|
auto eliminationResult = gmm.toFactorGraph({{Z(0), Vector1(midway)}}).eliminateSequential();
|
||||||
|
auto pMid = *eliminationResult->at(0)->asDiscrete();
|
||||||
EXPECT(assert_equal(DiscreteConditional(m, "60/40"), pMid));
|
EXPECT(assert_equal(DiscreteConditional(m, "60/40"), pMid));
|
||||||
|
|
||||||
// Everywhere else, the result should be a sigmoid.
|
// Everywhere else, the result should be a sigmoid.
|
||||||
|
@ -97,7 +84,8 @@ TEST(GaussianMixture, GaussianMixtureModel) {
|
||||||
const double expected = prob_m_z(mu0, mu1, sigma, sigma, z);
|
const double expected = prob_m_z(mu0, mu1, sigma, sigma, z);
|
||||||
|
|
||||||
// Workflow 1: convert HBN to HFG and solve
|
// Workflow 1: convert HBN to HFG and solve
|
||||||
auto posterior1 = SolveHBN(gmm, z);
|
auto eliminationResult1 = gmm.toFactorGraph({{Z(0), Vector1(z)}}).eliminateSequential();
|
||||||
|
auto posterior1 = *eliminationResult1->at(0)->asDiscrete();
|
||||||
EXPECT_DOUBLES_EQUAL(expected, posterior1(m1Assignment), 1e-8);
|
EXPECT_DOUBLES_EQUAL(expected, posterior1(m1Assignment), 1e-8);
|
||||||
|
|
||||||
// Workflow 2: directly specify HFG and solve
|
// Workflow 2: directly specify HFG and solve
|
||||||
|
@ -105,7 +93,8 @@ TEST(GaussianMixture, GaussianMixtureModel) {
|
||||||
hfg1.emplace_shared<DecisionTreeFactor>(
|
hfg1.emplace_shared<DecisionTreeFactor>(
|
||||||
m, std::vector{Gaussian(mu0, sigma, z), Gaussian(mu1, sigma, z)});
|
m, std::vector{Gaussian(mu0, sigma, z), Gaussian(mu1, sigma, z)});
|
||||||
hfg1.push_back(mixing);
|
hfg1.push_back(mixing);
|
||||||
auto posterior2 = SolveHFG(hfg1);
|
auto eliminationResult2 = hfg1.eliminateSequential();
|
||||||
|
auto posterior2 = *eliminationResult2->at(0)->asDiscrete();
|
||||||
EXPECT_DOUBLES_EQUAL(expected, posterior2(m1Assignment), 1e-8);
|
EXPECT_DOUBLES_EQUAL(expected, posterior2(m1Assignment), 1e-8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,15 +109,27 @@ TEST(GaussianMixture, GaussianMixtureModel2) {
|
||||||
|
|
||||||
// Create a Gaussian mixture model p(z|m) with same sigma.
|
// Create a Gaussian mixture model p(z|m) with same sigma.
|
||||||
HybridBayesNet gmm;
|
HybridBayesNet gmm;
|
||||||
std::vector<std::pair<Vector, double>> parameters{{Vector1(mu0), sigma0},
|
std::vector<std::pair<Vector, double>> parameters{{Vector1(mu0), sigma0}, {Vector1(mu1), sigma1}};
|
||||||
{Vector1(mu1), sigma1}};
|
|
||||||
gmm.emplace_shared<HybridGaussianConditional>(m, Z(0), parameters);
|
gmm.emplace_shared<HybridGaussianConditional>(m, Z(0), parameters);
|
||||||
gmm.push_back(mixing);
|
gmm.push_back(mixing);
|
||||||
|
|
||||||
// We get zMax=3.1333 by finding the maximum value of the function, at which
|
// We get zMax=3.1333 by finding the maximum value of the function, at which
|
||||||
// point the mode m==1 is about twice as probable as m==0.
|
// point the mode m==1 is about twice as probable as m==0.
|
||||||
double zMax = 3.133;
|
double zMax = 3.133;
|
||||||
auto pMax = SolveHBN(gmm, zMax);
|
const VectorValues vv{{Z(0), Vector1(zMax)}};
|
||||||
|
auto gfg = gmm.toFactorGraph(vv);
|
||||||
|
|
||||||
|
// Equality of posteriors asserts that the elimination is correct (same ratios for all modes)
|
||||||
|
const auto& expectedDiscretePosterior = gmm.discretePosterior(vv);
|
||||||
|
EXPECT(assert_equal(expectedDiscretePosterior, gfg.discretePosterior(vv)));
|
||||||
|
|
||||||
|
// Eliminate the graph!
|
||||||
|
auto eliminationResultMax = gfg.eliminateSequential();
|
||||||
|
|
||||||
|
// Equality of posteriors asserts that the elimination is correct (same ratios for all modes)
|
||||||
|
EXPECT(assert_equal(expectedDiscretePosterior, eliminationResultMax->discretePosterior(vv)));
|
||||||
|
|
||||||
|
auto pMax = *eliminationResultMax->at(0)->asDiscrete();
|
||||||
EXPECT(assert_equal(DiscreteConditional(m, "42/58"), pMax, 1e-4));
|
EXPECT(assert_equal(DiscreteConditional(m, "42/58"), pMax, 1e-4));
|
||||||
|
|
||||||
// Everywhere else, the result should be a bell curve like function.
|
// Everywhere else, the result should be a bell curve like function.
|
||||||
|
@ -137,7 +138,8 @@ TEST(GaussianMixture, GaussianMixtureModel2) {
|
||||||
const double expected = prob_m_z(mu0, mu1, sigma0, sigma1, z);
|
const double expected = prob_m_z(mu0, mu1, sigma0, sigma1, z);
|
||||||
|
|
||||||
// Workflow 1: convert HBN to HFG and solve
|
// Workflow 1: convert HBN to HFG and solve
|
||||||
auto posterior1 = SolveHBN(gmm, z);
|
auto eliminationResult1 = gmm.toFactorGraph({{Z(0), Vector1(z)}}).eliminateSequential();
|
||||||
|
auto posterior1 = *eliminationResult1->at(0)->asDiscrete();
|
||||||
EXPECT_DOUBLES_EQUAL(expected, posterior1(m1Assignment), 1e-8);
|
EXPECT_DOUBLES_EQUAL(expected, posterior1(m1Assignment), 1e-8);
|
||||||
|
|
||||||
// Workflow 2: directly specify HFG and solve
|
// Workflow 2: directly specify HFG and solve
|
||||||
|
@ -145,11 +147,11 @@ TEST(GaussianMixture, GaussianMixtureModel2) {
|
||||||
hfg.emplace_shared<DecisionTreeFactor>(
|
hfg.emplace_shared<DecisionTreeFactor>(
|
||||||
m, std::vector{Gaussian(mu0, sigma0, z), Gaussian(mu1, sigma1, z)});
|
m, std::vector{Gaussian(mu0, sigma0, z), Gaussian(mu1, sigma1, z)});
|
||||||
hfg.push_back(mixing);
|
hfg.push_back(mixing);
|
||||||
auto posterior2 = SolveHFG(hfg);
|
auto eliminationResult2 = hfg.eliminateSequential();
|
||||||
|
auto posterior2 = *eliminationResult2->at(0)->asDiscrete();
|
||||||
EXPECT_DOUBLES_EQUAL(expected, posterior2(m1Assignment), 1e-8);
|
EXPECT_DOUBLES_EQUAL(expected, posterior2(m1Assignment), 1e-8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
int main() {
|
int main() {
|
||||||
TestResult tr;
|
TestResult tr;
|
||||||
|
|
|
@ -518,8 +518,6 @@ TEST(HybridEstimation, CorrectnessViaSampling) {
|
||||||
// the normalizing term computed via the Bayes net determinant.
|
// the normalizing term computed via the Bayes net determinant.
|
||||||
const HybridValues sample = bn->sample(&rng);
|
const HybridValues sample = bn->sample(&rng);
|
||||||
double expected_ratio = compute_ratio(sample);
|
double expected_ratio = compute_ratio(sample);
|
||||||
// regression
|
|
||||||
EXPECT_DOUBLES_EQUAL(0.728588, expected_ratio, 1e-6);
|
|
||||||
|
|
||||||
// 3. Do sampling
|
// 3. Do sampling
|
||||||
constexpr int num_samples = 10;
|
constexpr int num_samples = 10;
|
||||||
|
|
Loading…
Reference in New Issue