From 58362579bb6d22ca9b94d4c0a3daf63bda0508a2 Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 12:27:10 -0400 Subject: [PATCH 1/9] Resurrecting DiscreteBayesTree tests --- gtsam/discrete/DiscreteBayesNet.h | 3 +- gtsam/discrete/DiscreteBayesTree.cpp | 13 +- gtsam/discrete/DiscreteBayesTree.h | 3 + .../discrete/tests/testDiscreteBayesTree.cpp | 499 +++++++++--------- 4 files changed, 257 insertions(+), 261 deletions(-) diff --git a/gtsam/discrete/DiscreteBayesNet.h b/gtsam/discrete/DiscreteBayesNet.h index dcc336f89..237caf745 100644 --- a/gtsam/discrete/DiscreteBayesNet.h +++ b/gtsam/discrete/DiscreteBayesNet.h @@ -20,13 +20,14 @@ #include #include #include +#include #include #include namespace gtsam { /** A Bayes net made from linear-Discrete densities */ - class GTSAM_EXPORT DiscreteBayesNet: public FactorGraph + class GTSAM_EXPORT DiscreteBayesNet: public BayesNet { public: diff --git a/gtsam/discrete/DiscreteBayesTree.cpp b/gtsam/discrete/DiscreteBayesTree.cpp index bed50a470..8fcc34e25 100644 --- a/gtsam/discrete/DiscreteBayesTree.cpp +++ b/gtsam/discrete/DiscreteBayesTree.cpp @@ -29,10 +29,19 @@ namespace gtsam { template class BayesTreeCliqueBase; template class BayesTree; + /* ************************************************************************* */ + double DiscreteBayesTreeClique::evaluate( + const DiscreteConditional::Values& values) const { + // evaluate all conditionals and multiply + double result = (*conditional_)(values); + for (const auto& child : children) { + result *= child->evaluate(values); + } + return result; + } /* ************************************************************************* */ - bool DiscreteBayesTree::equals(const This& other, double tol) const - { + bool DiscreteBayesTree::equals(const This& other, double tol) const { return Base::equals(other, tol); } diff --git a/gtsam/discrete/DiscreteBayesTree.h b/gtsam/discrete/DiscreteBayesTree.h index 0df6ab476..aa8f4657c 100644 --- a/gtsam/discrete/DiscreteBayesTree.h +++ b/gtsam/discrete/DiscreteBayesTree.h @@ -42,6 +42,9 @@ namespace gtsam { typedef boost::weak_ptr weak_ptr; DiscreteBayesTreeClique() {} DiscreteBayesTreeClique(const boost::shared_ptr& conditional) : Base(conditional) {} + + //** evaluate conditional probability of subtree for given Values */ + double evaluate(const DiscreteConditional::Values & values) const; }; /* ************************************************************************* */ diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.cpp b/gtsam/discrete/tests/testDiscreteBayesTree.cpp index 93126f642..f58fd2b19 100644 --- a/gtsam/discrete/tests/testDiscreteBayesTree.cpp +++ b/gtsam/discrete/tests/testDiscreteBayesTree.cpp @@ -1,261 +1,245 @@ -///* ---------------------------------------------------------------------------- -// -// * 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 testDiscreteBayesTree.cpp -// * @date sept 15, 2012 -// * @author Frank Dellaert -// */ -// -//#include -//#include -//#include -// -//#include -//using namespace boost::assign; -// +/* ---------------------------------------------------------------------------- + +* GTSAM Copyright 2010-2020, 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 testDiscreteBayesTree.cpp + * @date sept 15, 2012 + * @author Frank Dellaert + */ + +#include +#include +#include +#include +#include + +#include +using namespace boost::assign; + #include -// -//using namespace std; -//using namespace gtsam; -// -//static bool debug = false; -// -///** -// * Custom clique class to debug shortcuts -// */ -////class Clique: public BayesTreeCliqueBaseOrdered { -//// -////protected: -//// -////public: -//// -//// typedef BayesTreeCliqueBaseOrdered Base; -//// typedef boost::shared_ptr shared_ptr; -//// -//// // Constructors -//// Clique() { -//// } -//// Clique(const DiscreteConditional::shared_ptr& conditional) : -//// Base(conditional) { -//// } -//// Clique( -//// const std::pair& result) : -//// Base(result) { -//// } -//// -//// /// print index signature only -//// void printSignature(const std::string& s = "Clique: ", -//// const KeyFormatter& indexFormatter = DefaultKeyFormatter) const { -//// ((IndexConditionalOrdered::shared_ptr) conditional_)->print(s, indexFormatter); -//// } -//// -//// /// evaluate value of sub-tree -//// double evaluate(const DiscreteConditional::Values & values) { -//// double result = (*(this->conditional_))(values); -//// // evaluate all children and multiply into result -//// for(boost::shared_ptr c: children_) -//// result *= c->evaluate(values); -//// return result; -//// } -//// -////}; -// -////typedef BayesTreeOrdered DiscreteBayesTree; -//// -/////* ************************************************************************* */ -////double evaluate(const DiscreteBayesTree& tree, -//// const DiscreteConditional::Values & values) { -//// return tree.root()->evaluate(values); -////} -// -///* ************************************************************************* */ -// -//TEST_UNSAFE( DiscreteBayesTree, thinTree ) { -// -// const int nrNodes = 15; -// const size_t nrStates = 2; -// -// // define variables -// vector key; -// for (int i = 0; i < nrNodes; i++) { -// DiscreteKey key_i(i, nrStates); -// key.push_back(key_i); -// } -// -// // create a thin-tree Bayesnet, a la Jean-Guillaume -// DiscreteBayesNet bayesNet; -// bayesNet.add(key[14] % "1/3"); -// -// bayesNet.add(key[13] | key[14] = "1/3 3/1"); -// bayesNet.add(key[12] | key[14] = "3/1 3/1"); -// -// bayesNet.add((key[11] | key[13], key[14]) = "1/4 2/3 3/2 4/1"); -// bayesNet.add((key[10] | key[13], key[14]) = "1/4 3/2 2/3 4/1"); -// bayesNet.add((key[9] | key[12], key[14]) = "4/1 2/3 F 1/4"); -// bayesNet.add((key[8] | key[12], key[14]) = "T 1/4 3/2 4/1"); -// -// bayesNet.add((key[7] | key[11], key[13]) = "1/4 2/3 3/2 4/1"); -// bayesNet.add((key[6] | key[11], key[13]) = "1/4 3/2 2/3 4/1"); -// bayesNet.add((key[5] | key[10], key[13]) = "4/1 2/3 3/2 1/4"); -// bayesNet.add((key[4] | key[10], key[13]) = "2/3 1/4 3/2 4/1"); -// -// bayesNet.add((key[3] | key[9], key[12]) = "1/4 2/3 3/2 4/1"); -// bayesNet.add((key[2] | key[9], key[12]) = "1/4 8/2 2/3 4/1"); -// bayesNet.add((key[1] | key[8], key[12]) = "4/1 2/3 3/2 1/4"); -// bayesNet.add((key[0] | key[8], key[12]) = "2/3 1/4 3/2 4/1"); -// -//// if (debug) { -//// GTSAM_PRINT(bayesNet); -//// bayesNet.saveGraph("/tmp/discreteBayesNet.dot"); -//// } -// -// // create a BayesTree out of a Bayes net -// DiscreteBayesTree bayesTree(bayesNet); -// if (debug) { -// GTSAM_PRINT(bayesTree); -// bayesTree.saveGraph("/tmp/discreteBayesTree.dot"); -// } -// -// // Check whether BN and BT give the same answer on all configurations -// // Also calculate all some marginals -// Vector marginals = zero(15); -// double joint_12_14 = 0, joint_9_12_14 = 0, joint_8_12_14 = 0, joint_8_12 = 0, -// joint82 = 0, joint12 = 0, joint24 = 0, joint45 = 0, joint46 = 0, -// joint_4_11 = 0; -// vector allPosbValues = cartesianProduct( -// key[0] & key[1] & key[2] & key[3] & key[4] & key[5] & key[6] & key[7] -// & key[8] & key[9] & key[10] & key[11] & key[12] & key[13] & key[14]); -// for (size_t i = 0; i < allPosbValues.size(); ++i) { -// DiscreteFactor::Values x = allPosbValues[i]; -// double expected = evaluate(bayesNet, x); -// double actual = evaluate(bayesTree, x); -// DOUBLES_EQUAL(expected, actual, 1e-9); -// // collect marginals -// for (size_t i = 0; i < 15; i++) -// if (x[i]) -// marginals[i] += actual; -// // calculate shortcut 8 and 0 -// if (x[12] && x[14]) -// joint_12_14 += actual; -// if (x[9] && x[12] & x[14]) -// joint_9_12_14 += actual; -// if (x[8] && x[12] & x[14]) -// joint_8_12_14 += actual; -// if (x[8] && x[12]) -// joint_8_12 += actual; -// if (x[8] && x[2]) -// joint82 += actual; -// if (x[1] && x[2]) -// joint12 += actual; -// if (x[2] && x[4]) -// joint24 += actual; -// if (x[4] && x[5]) -// joint45 += actual; -// if (x[4] && x[6]) -// joint46 += actual; -// if (x[4] && x[11]) -// joint_4_11 += actual; -// } -// DiscreteFactor::Values all1 = allPosbValues.back(); -// -// Clique::shared_ptr R = bayesTree.root(); -// -// // check separator marginal P(S0) -// Clique::shared_ptr c = bayesTree[0]; -// DiscreteFactorGraph separatorMarginal0 = c->separatorMarginal(R, -// EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9); -// -// // check separator marginal P(S9), should be P(14) -// c = bayesTree[9]; -// DiscreteFactorGraph separatorMarginal9 = c->separatorMarginal(R, -// EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(marginals[14], separatorMarginal9(all1), 1e-9); -// -// // check separator marginal of root, should be empty -// c = bayesTree[11]; -// DiscreteFactorGraph separatorMarginal11 = c->separatorMarginal(R, -// EliminateDiscrete); -// EXPECT_LONGS_EQUAL(0, separatorMarginal11.size()); -// -// // check shortcut P(S9||R) to root -// c = bayesTree[9]; -// DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); -// EXPECT_LONGS_EQUAL(0, shortcut.size()); -// -// // check shortcut P(S8||R) to root -// c = bayesTree[8]; -// shortcut = c->shortcut(R, EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint_12_14/marginals[14], evaluate(shortcut,all1), -// 1e-9); -// -// // check shortcut P(S2||R) to root -// c = bayesTree[2]; -// shortcut = c->shortcut(R, EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint_9_12_14/marginals[14], evaluate(shortcut,all1), -// 1e-9); -// -// // check shortcut P(S0||R) to root -// c = bayesTree[0]; -// shortcut = c->shortcut(R, EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint_8_12_14/marginals[14], evaluate(shortcut,all1), -// 1e-9); -// -// // calculate all shortcuts to root -// DiscreteBayesTree::Nodes cliques = bayesTree.nodes(); -// for(Clique::shared_ptr c: cliques) { -// DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); -// if (debug) { -// c->printSignature(); -// shortcut.print("shortcut:"); -// } -// } -// -// // Check all marginals -// DiscreteFactor::shared_ptr marginalFactor; -// for (size_t i = 0; i < 15; i++) { -// marginalFactor = bayesTree.marginalFactor(i, EliminateDiscrete); -// double actual = (*marginalFactor)(all1); -// EXPECT_DOUBLES_EQUAL(marginals[i], actual, 1e-9); -// } -// -// DiscreteBayesNet::shared_ptr actualJoint; -// -// // Check joint P(8,2) TODO: not disjoint ! -//// actualJoint = bayesTree.jointBayesNet(8, 2, EliminateDiscrete); -//// EXPECT_DOUBLES_EQUAL(joint82, evaluate(*actualJoint,all1), 1e-9); -// -// // Check joint P(1,2) TODO: not disjoint ! -//// actualJoint = bayesTree.jointBayesNet(1, 2, EliminateDiscrete); -//// EXPECT_DOUBLES_EQUAL(joint12, evaluate(*actualJoint,all1), 1e-9); -// -// // Check joint P(2,4) -// actualJoint = bayesTree.jointBayesNet(2, 4, EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint24, evaluate(*actualJoint,all1), 1e-9); -// -// // Check joint P(4,5) TODO: not disjoint ! -//// actualJoint = bayesTree.jointBayesNet(4, 5, EliminateDiscrete); -//// EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); -// -// // Check joint P(4,6) TODO: not disjoint ! -//// actualJoint = bayesTree.jointBayesNet(4, 6, EliminateDiscrete); -//// EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); -// -// // Check joint P(4,11) -// actualJoint = bayesTree.jointBayesNet(4, 11, EliminateDiscrete); -// EXPECT_DOUBLES_EQUAL(joint_4_11, evaluate(*actualJoint,all1), 1e-9); -// -//} + +#include + +using namespace std; +using namespace gtsam; + +static bool debug = false; + +// /** +// * Custom clique class to debug shortcuts +// */ +// struct Clique : public BayesTreeCliqueBase { +// typedef BayesTreeCliqueBase Base; +// typedef boost::shared_ptr shared_ptr; + +// // Constructors +// Clique() {} +// explicit Clique(const DiscreteConditional::shared_ptr& conditional) +// : Base(conditional) {} +// Clique(const std::pair& +// result) +// : Base(result) {} + +// /// print index signature only +// void printSignature( +// const std::string& s = "Clique: ", +// const KeyFormatter& indexFormatter = DefaultKeyFormatter) const { +// ((IndexConditionalOrdered::shared_ptr)conditional_) +// ->print(s, indexFormatter); +// } + +// /// evaluate value of sub-tree +// double evaluate(const DiscreteConditional::Values& values) { +// double result = (*(this->conditional_))(values); +// // evaluate all children and multiply into result +// for (boost::shared_ptr c : children_) result *= +// c->evaluate(values); return result; +// } +// }; + +// typedef BayesTreeOrdered DiscreteBayesTree; + +/* ************************************************************************* */ + +TEST_UNSAFE(DiscreteBayesTree, thinTree) { + const int nrNodes = 15; + const size_t nrStates = 2; + + // define variables + vector key; + for (int i = 0; i < nrNodes; i++) { + DiscreteKey key_i(i, nrStates); + key.push_back(key_i); + } + + // create a thin-tree Bayesnet, a la Jean-Guillaume + DiscreteBayesNet bayesNet; + bayesNet.add(key[14] % "1/3"); + + bayesNet.add(key[13] | key[14] = "1/3 3/1"); + bayesNet.add(key[12] | key[14] = "3/1 3/1"); + + bayesNet.add((key[11] | key[13], key[14]) = "1/4 2/3 3/2 4/1"); + bayesNet.add((key[10] | key[13], key[14]) = "1/4 3/2 2/3 4/1"); + bayesNet.add((key[9] | key[12], key[14]) = "4/1 2/3 F 1/4"); + bayesNet.add((key[8] | key[12], key[14]) = "T 1/4 3/2 4/1"); + + bayesNet.add((key[7] | key[11], key[13]) = "1/4 2/3 3/2 4/1"); + bayesNet.add((key[6] | key[11], key[13]) = "1/4 3/2 2/3 4/1"); + bayesNet.add((key[5] | key[10], key[13]) = "4/1 2/3 3/2 1/4"); + bayesNet.add((key[4] | key[10], key[13]) = "2/3 1/4 3/2 4/1"); + + bayesNet.add((key[3] | key[9], key[12]) = "1/4 2/3 3/2 4/1"); + bayesNet.add((key[2] | key[9], key[12]) = "1/4 8/2 2/3 4/1"); + bayesNet.add((key[1] | key[8], key[12]) = "4/1 2/3 3/2 1/4"); + bayesNet.add((key[0] | key[8], key[12]) = "2/3 1/4 3/2 4/1"); + + if (debug) { + GTSAM_PRINT(bayesNet); + bayesNet.saveGraph("/tmp/discreteBayesNet.dot"); + } + + // create a BayesTree out of a Bayes net + auto bayesTree = DiscreteFactorGraph(bayesNet).eliminateMultifrontal(); + if (debug) { + GTSAM_PRINT(*bayesTree); + bayesTree->saveGraph("/tmp/discreteBayesTree.dot"); + } + + auto R = bayesTree->roots().front(); + + // Check whether BN and BT give the same answer on all configurations + vector allPosbValues = cartesianProduct( + key[0] & key[1] & key[2] & key[3] & key[4] & key[5] & key[6] & key[7] & + key[8] & key[9] & key[10] & key[11] & key[12] & key[13] & key[14]); + for (size_t i = 0; i < allPosbValues.size(); ++i) { + DiscreteFactor::Values x = allPosbValues[i]; + double expected = bayesNet.evaluate(x); + double actual = R->evaluate(x); + DOUBLES_EQUAL(expected, actual, 1e-9); + } + + // Calculate all some marginals + Vector marginals = zero(15); + double joint_12_14 = 0, joint_9_12_14 = 0, joint_8_12_14 = 0, joint_8_12 = 0, + joint82 = 0, joint12 = 0, joint24 = 0, joint45 = 0, joint46 = 0, + joint_4_11 = 0; + for (size_t i = 0; i < allPosbValues.size(); ++i) { + DiscreteFactor::Values x = allPosbValues[i]; + double px = R->evaluate(x); + for (size_t i = 0; i < 15; i++) + if (x[i]) marginals[i] += px; + // calculate shortcut 8 and 0 + if (x[12] && x[14]) joint_12_14 += px; + if (x[9] && x[12] & x[14]) joint_9_12_14 += px; + if (x[8] && x[12] & x[14]) joint_8_12_14 += px; + if (x[8] && x[12]) joint_8_12 += px; + if (x[8] && x[2]) joint82 += px; + if (x[1] && x[2]) joint12 += px; + if (x[2] && x[4]) joint24 += px; + if (x[4] && x[5]) joint45 += px; + if (x[4] && x[6]) joint46 += px; + if (x[4] && x[11]) joint_4_11 += px; + } + DiscreteFactor::Values all1 = allPosbValues.back(); + + + // check separator marginal P(S0) + auto c = (*bayesTree)[0]; + DiscreteFactorGraph separatorMarginal0 = + c->separatorMarginal(EliminateDiscrete); + EXPECT_DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9); + + // // check separator marginal P(S9), should be P(14) + // c = (*bayesTree)[9]; + // DiscreteFactorGraph separatorMarginal9 = + // c->separatorMarginal(EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(marginals[14], separatorMarginal9(all1), 1e-9); + + // // check separator marginal of root, should be empty + // c = (*bayesTree)[11]; + // DiscreteFactorGraph separatorMarginal11 = + // c->separatorMarginal(EliminateDiscrete); + // EXPECT_LONGS_EQUAL(0, separatorMarginal11.size()); + + // // check shortcut P(S9||R) to root + // c = (*bayesTree)[9]; + // DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); + // EXPECT_LONGS_EQUAL(0, shortcut.size()); + + // // check shortcut P(S8||R) to root + // c = (*bayesTree)[8]; + // shortcut = c->shortcut(R, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint_12_14 / marginals[14], evaluate(shortcut, all1), + // 1e-9); + + // // check shortcut P(S2||R) to root + // c = (*bayesTree)[2]; + // shortcut = c->shortcut(R, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint_9_12_14 / marginals[14], evaluate(shortcut, + // all1), + // 1e-9); + + // // check shortcut P(S0||R) to root + // c = (*bayesTree)[0]; + // shortcut = c->shortcut(R, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint_8_12_14 / marginals[14], evaluate(shortcut, + // all1), + // 1e-9); + + // // calculate all shortcuts to root + // DiscreteBayesTree::Nodes cliques = bayesTree->nodes(); + // for (auto c : cliques) { + // DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); + // if (debug) { + // c->printSignature(); + // shortcut.print("shortcut:"); + // } + // } + + // // Check all marginals + // DiscreteFactor::shared_ptr marginalFactor; + // for (size_t i = 0; i < 15; i++) { + // marginalFactor = bayesTree->marginalFactor(i, EliminateDiscrete); + // double actual = (*marginalFactor)(all1); + // EXPECT_DOUBLES_EQUAL(marginals[i], actual, 1e-9); + // } + + // DiscreteBayesNet::shared_ptr actualJoint; + + // Check joint P(8,2) TODO: not disjoint ! + // actualJoint = bayesTree->jointBayesNet(8, 2, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint82, evaluate(*actualJoint,all1), 1e-9); + + // Check joint P(1,2) TODO: not disjoint ! + // actualJoint = bayesTree->jointBayesNet(1, 2, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint12, evaluate(*actualJoint,all1), 1e-9); + + // Check joint P(2,4) + // actualJoint = bayesTree->jointBayesNet(2, 4, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint24, evaluate(*actualJoint, all1), 1e-9); + + // Check joint P(4,5) TODO: not disjoint ! + // actualJoint = bayesTree->jointBayesNet(4, 5, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); + + // Check joint P(4,6) TODO: not disjoint ! + // actualJoint = bayesTree->jointBayesNet(4, 6, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); + + // Check joint P(4,11) + // actualJoint = bayesTree->jointBayesNet(4, 11, EliminateDiscrete); + // EXPECT_DOUBLES_EQUAL(joint_4_11, evaluate(*actualJoint, all1), 1e-9); +} /* ************************************************************************* */ int main() { @@ -263,4 +247,3 @@ int main() { return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ - From 3f4bf163e73a5f04cb8291e40fc1892ab80bb83e Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 14:59:17 -0400 Subject: [PATCH 2/9] Checked in pdf for easy reference --- gtsam/discrete/tests/testDiscreteBayesTree.pdf | Bin 0 -> 10622 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gtsam/discrete/tests/testDiscreteBayesTree.pdf diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.pdf b/gtsam/discrete/tests/testDiscreteBayesTree.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e8167d455477f97aadb2101d26120a6c145891f5 GIT binary patch literal 10622 zcma)i2RK~a^S>5?=p|~bPPEvu87l@l5hq-FA~Taz0X!;D zXB&5006&7Hg#!Qpc;xIH-Jx*A(-Gnhy$iL3SwV5c#c|x+;ZTSZ&i#ym6xG-nfg2&) z-^s*TB<~T)Dken$La#-jq59a?RRcmTBJ!>$$b6K!d|;-Pw=p{v+e6>N@FAQ%os>(Q zfqj%}cROMy(b81iEU78^rDfB%`o=TH61qzh+iwJxu-#)j@8bv2^d%3uNhi(p3b-6+ zCPpTBv|k#nq)v=g58W;`G8yd*a7*kPO@rfd6~<}dHtf8siRb}(rJ>!5%~!9Yc_D0^ zwaiD@AJCzTKbJZ2X|wA4X^rV8&L=Wape4sriH;|NALi@}9r87N)yF2&dHRY7?(N<# zc{AsyKi80*JZ4&Uaj~<9({y{3d-5CH_w@Vn=HBQ)<0}<0_ZnFmk8$I*w~k`%cwo~Z zGo2FkHACiGURroYJ$)qtm}4t;$y#qZcy*QPG>xD6y_4-&jVz=U`xZgQ*%;VLivU&`1}PK||UGDx>Q9u{jm6CK^L<*ef=hu#&~d?MMFK0N61HO}zUJ&=~I zQ(c27RxUr^!&h|0#L@BZ9bSE#;C(jPl;qa1&OH9OoWFy~TICU0^n>N0_8!tDb(^^L zQ6<`>wqX%AqIE!!!LCCYu$Rb&C@!u|JFlUyBY<_)m~dE`QT0%8~vExZX+ zAFzh4`VJ?)w<`oW7Mt@pqw+*QdO}0Is1w1+QhG&*zoQ(QF&duh}O4`A5 ziXXedCD!QVCdr})CAW2IhEbzb1s}PZ8E>wvc60;DQ=ZAmwcTvG$?COS#J1uQ3@563b2~v#|h8Mf<{^7lySTh6}mgo7&Asw zs$HAGxO`q7B{vzGdlEi^7uls`En=nPtHkrkQrLkeXnNT^3Xy4Z4}AwbsvdfBalZYSCHT-%@((y{Wv=^{RXZJEnRT-GHFC zFMCL-xfmV0*>V;h_B84436?Jh>hv!w5GO7$3~TM#T=!^GYdW+F%1=a04rkZrd1+OjkJTJz=V{Ag-9U zbuKC(D@nkP#MCPx`jEme7{;V;Z|KTTt&#h}B;iQW)^&W$GuMu$a!rB5r_bNDD(FS> zeqga(y~`HCuJos@(mYjQ|O03%skp*OOSb`dMX?iL1lGln~KStlaEifwy{h@mK{Ayf{@b_qBR#0a1=YcrdLu@KKix(-Z>@-tJTOci==dV7S zGgCyl)$nx_;qAplsAw#@$x^8ndsf=`2%%}tD#zjKDeH?<8(^nl0l1{1jF*_hQk|0l z)MY*(W*(N3+h5#r4FetDX$H=ajozs_CF^?jKnnZzr$USl)}|7g!IWDQ!Xt0URVl?v z{LE9~4_;S8Pp!YG9~yZom%nF!t$Of1Y93zT)j(=5!p(i6h$-Cc+OrpKJD-pb6)*TxgamkH{R26h_y?62XO`SK0`}BFIfCQa!+#Qz{sV?y6xJ?HsQsao% zj!!I$p3rp?Tc6SZ4ylxT8^k1)<#uo5IXs%JlqIiZj*SBtuu3uJF6tOZzZ2{os+~UE zTi=t&oqBd12kLC~GglzKA+roJwIH8}*LlMJ+e)Z*1g<9D`q+#~~MhFrRz|SuX z-~;jjOs=?P5TYR1-2lkc`Xi6Z!(kpSe-rP=99Ps|>(fTe42L+oxgh7V^!`Ow1h~UJ zpubu&2(G(OPdiJfmb^5Q_;dAIP&b$d+!E>rKx$I!Zz~f*wEvafg@23nU+EpGsvo}t zKmZ|LKB0f)`%OV_KW*K2pM;O+90!~d1niQy71LNuM);g$3?uRzg7YN%w6e`P$PK6M z*`LhfNE^r{X<6O1BGK#%qvpUUCtTR}hdTGj8vs{Ylu7^d`lV{FQp$;Fnk-a}Ptz0AV|(XcI|yT1{=~&Zd6bo52_@i%jbQV&UM+Ha~VdEc=|28@(@y?G_-3UQh|g1 zBCbePE;kqqNqBg-czHl>G}4OlLyu)1YRICL6bq&i`m^VJOW2(W*!M6?;yIkXq{KPx zA29`~J+tEb@D18tO1%uv>sx&AB6g5Pn;bvO#1z_Fp)vr#9Wxetap8IKm_~qERnHxF z-{k@1mB3OBo3H-?M?s5@khR$}C;Se+n2gRDqE$=HgLBB=`l( zeutzc*r&eCf0<`&e}cz7&=dNirw9!5?U3pE(yD;d2+xxGgAS#D6W z;@@v-Oi-vLLSIcV#S5|!<>Z3#gUCOm*Ju9;-O%jWn)hSKF}ho2vQzbAzh`p`!XYy z(d^Yqe5rN?PQEmrQgDJLWj`?1TqXNS*@_5rI94nCTq;_OpXLQl7#4G2CM1lDG03eS;$(Jl?PSu}Qci zi^zHONH12}fc@-73U7_N#%D-_xk)EsOmewW?~Y`50!Eh2bprbkUDTG9J8DVubNMWF zF)u09^7Voh)3P6b>-9TgOsarr9n`C`bo)S~HiUEoFvr*$SxiYU?c0_@Mp~3LOk>g~ zpK6(?*lW6s1(A`pyp_8l&0NlU<}My2^L1$Io4aAVWFrOtdUBJW)ecjgM_Gh{m($W& z_o&shkK*^P=MS0EQ*7w*`FC;I`Q+&*mnatcDK5`4PHJdkA_dd?Uu;a0`&E13*FBQeCdOwQ*1vV!8}i53D_fN}D?Ge8Fj1FQ(D$-&qQnsgHnfR}Hb1+PKS_I_ERB zb*~67116)k;BBCsW$n=y%Nzw9)^EX3pS8>$uL4Jvxs(d|I$m%2Uerz8DT()u*$r{D z&t3r2RhBuaWhl4@H~7Nwg55@5-zS#fp37VDaAV0@$D|#GRM70Td)S26&i8Z}Q-(1s zojyuo#4A9(fytNkq}x`VJsD&)Vj>LY+K$){0%LL1hU}AgSl83(OyNkx+m%x(k%ClR z%s6h7yU~qaOJwM=p~n>K$h?7$&5NnoVIdFJ4UCOxRPX5BniBFoeZI+h`KHG5urQ`e z*Qw>{_-0X6%&R2G7P<{)%y9ey*Q+Xnuh&0*s@^P(;;7ipoQjpF5jI#S? zR1B?=`ZiATHQcl}J)R;G2Iq>q0fE%>2J{D=TB$LNN_*Lt*q5vss4#gi^ zGP6|Pj%hEXz~qeTdCi+Xuk$!@73#Ji9Q2?`7R9$BZFQo-mfVeCz$s}54VB9~roGDFS$m<7J5XKdqO2}qTGfUSg6 z;agHCg`GtQeVx}Q>Mu~4k6NEwFj~?nE|VB+2da+NJ9~Yh6BIk_`y?w6CrHgou1{`! zUL60LiA&w-VOjqD^1V@+ug4p)8IiBMi|)yPN70I6{+u<^#cvUn-y%T&jdCyej6`hz z_64RmY5~fHG4}hYd)+>xH79dSS)Qz6nwHugM(r=l4JsBW9L>?IEha}#&-wNTqo$sgMW+LK%f?xHmSZVdQdrsz(qe*F&pJ@%ab(%FsYbUZ%HzOiOu(-J+ zmUQ&w-1WU>W2uePF>3c|kyC*WeeuGUc(%3tC0x zD6f>HJKGRJxAo|{4EYqs4b3g@^E!ij1`g!ukUie02wiBJx0@WhNULs|H?CltXdAd~ za`3I&=CY@9ojSF~i7`veI0X}7@{q&QypNmrz|6tdRpaihfr6=(YxIM#lytZb=oreg z8!@*-AOqvO(LQprH&oR|(P!2p7%c2v=vizU?pxBEOGvw4dmCo_j{9OJL4@j}MYro7Ow8Zve63*b-G^HJfCt6{#UaKg z_vqbZz;nb0m}q<-yH`gKLxifdEZ^Ajr!iyq^dwn1mK%FIr;y^C>1QN|wR0{S=%qk()0_Q_nguVMAd)WnNpc{r zRyM9@Zgt&f^qqxGPF!&o=m&|Y(j)?i=nUG69Gol`%WNzbX>9kn_&BKt*JKGFhkn5r z)W^q-drQ34mb?$SPk)9JL)J1%7*a$bTzKE?r409RGy3r85N=Z_$FTqK`xdPA_<6qr zuagJHLHao4e#sa)wB*DDCRDT6p*3^P_ff?Gio;-FGmtG9Wd`4A2z4JqJ8v4ezayY1 z={^H9)3 zHX(DNsDvHgFZ3U^g+=F2vN@J*ru4`A%+8E>k#@W)({=P%dxczhdwdZKXop9bHmT8rbD>Tzm)#lzAxAH>mQcw$`3a!%0 z9;YPsdoMdJ%PhlQ2b=Vkm|q5q^_iOUls~jCg&T4|OYc-oPPJmLP@8%%MSp61TDgZi z6f5um-{b5{DP_`V<^i?7Y?pb~mqyixYF*D+-*wYh&~Y77bZ!DUw=IdvNX<1Nr`Xd# zEZpm<+%_SMv(A+T`2|cy{Vcm{$tl^R_VeBz8A^q5eLIE9*o&C7Pov+)6@l8{(O7o* zv^VBrW2HR+4pCHm(O8PLlYT1~-hX7Ngvt&(7g3^@V>f=mWN5_x#0Tyq70Pv>*9^f; zG-8>A_$oJR!f^2vHnFvQi^i7AovIfwjE2U@%YqehxhP(3IId$0V8+dYP@@a>7A;(| z`RDI;(o@Wijay3tv@m4Ix}X7xOU0M;4lv1&YTo_qslj7=uld2z2df<7v4e%UrMvGliZ|xhoi-& ziG(=Xg{$z5-jhkn3u883>?({7h4mLUpjl|Ue?1J7ywDK2ky<+r(U=%JB-$H21BRCn z$N&y0vcUbXQ^N*{+aPKvHkMdC`EgGzyY$pbiiz_}NWWRHmmfwstd{FePY->0tsNL< zyIFYr{Eqhevbl+o4FUFH&t!V>;UQyOtkGhdlAq67yv#XasAo7jnBwm9nHhV&_@V-5 zxQVSQK$r<*ZJ3Edg4JP7nsqqh@K9l?mYcn`M7V%Hbzj3;9bcdx#H}5VRq=9rHT;m~ zXs9PEYw;F{z~UP)poxw!1hW+YYSzF`p$0@vA>82$1^IBVw&fA^-c5zFW+w&pO?FXV>m>ZnU zT_@w(kE)6E=97b;#V0jeUYE!B$3F4+d@o=>!d%2P-g^;T{2Xf~xnEBpdbY1Peo2vI zr|kO8IrawBH~P+KahIl^IG@lkayz1hSIPN$&BlmTx!5I=Rc{qCOJ7rO?C3ewa!Rx> z)zMlvwbx5vnOFN;ak(ruMFr|NjA zIu{jQCv)L>yWMd_)k{xm#)9i&g&M=z9DhxywUu*Y{4-7^Q%qtRYsnqOwI$0^8sAf` z_mM^3X*K|Xj=F^ zoDjAkQMP;2@uETCK~=PblzZ+E@ur0&(p$5;1#$s|OA z-z$7c)II?kc<5BBR_dZFIo_J8&W!uN_$BF;6Qy2r~YxZcDS4WGQQ zoC~Zu2nnWrtH=Z(;Uw6b=Qfm`eUPGUqOS1dMr7<{=`k0Rm30Sql4s& z)8hsb>Vc_qFp~|EdtsG>vN4;r;}h02bBwmHy=yxr3g;FkdgeMN6w9A>USk4IoCoF& zPNJE`+ZXQ?7|JI#KpWT}r5zY4x37MifRuOO?lT?Y^mZD}zP#l-mZoiFuG+;M{<&PO z&O}^UT-B8GxNm=nyH-1kMg8eI88%KagK3W5OH!O*m6qE;XRLm-ib4$yG=?x zJa)DgXIB4)hVfavdSHO%qBhZ(Z4X;NRg)AystgjjcA9#Uh;DUP zlx=YZ4cavB-2g`#9GW0QA^@Es#uNkHjVXq3NA0NoNaHw809yP8@qK16PXkkY19QTm zhYc3G|I`#Qb~4s1v7%ryYeII5Wy05mG0A6>9GZpFOlAopW@HHz`ASiK;!N!O;Y|L) z;!G?1WJjlSf;)!jIaM)_iea5|)Y-=oE0i&kbQ^dR z6Nj5*hUnjTA5)Gj?GJ@;MFvV3I*cAxkvr9*R&p^^%FY{72MS7J$sS<37H8M!X&5^M zl}Q;Yk8ugvti5CwJmG3sh)GpW>VJHRLa)1w`zJ7fJe2+k4DbsA1%4gOgOJDT|2n@0 z{dEriUkBKTBk|w(w8`**^J4%Z%4ZREP}e4eaqT-xXWo>l=mBe$Kg#1_=0eFhv6CZO z^Ga184RLDy%wXXb=hDF^%(^U>9%Rkq;=rHasK<9@5?g;gSKcc6K}I!^4>S#9J5$I zW*~!!$a>RGa6SE&d16Q_{qzXxtY{bevB+l=*&H470 z%|%Lhy|?;;!p-<)Le^|N@vUBin?)o0xEk2uqFn+yDtAOmqxfZEyEB7hsjFjrl)-Jwo;0HGfpkPU@j4dmJo-UI~$kci3O5fmhd z^veT(;5JC!AH#WAxL=_~ItYvg`Rkjb`@$#aV2S{5dCCP;(NluZ1ii&fi95$wbQ_yHR^!Li!w!?1n|Hs0k?r#dkVe7s+OHtnYN6 z;fISji)bju;f!tzrN1?vJIwUNqjqtFJS zll{lMzuXOBZIICKX_2tyKb`O&hQDiPZ4E`@h6n`E2ngUo+#r*`p@5*jU_cz?+beq^ zph+GO0)|Bl{SRCI3dMh0A{gm5KcLM2WlNJdRp)lVjo{;q*1lB>jGjBvuL{yR&vFaI zP+C}I(@@~u4AngJxjJiTR{L`{Vw|vV%5;91r!B+yPg+hNsVEyy5l8Wz0@BEbK3=S> zIoTvW=G-acN?jJOVS9(aXhW3TPi>q9iaB6Hk!<88J_oieoeR*Yx226_TH{bY8KR0a zraZPENl(SL3N95RpZ&UNSSHamnRI=6T2P*eIzGvYvmBcwT#X$s)6Gz$`JtgNVQ!^F zi24f|leK~|rK(qOf-Z5$a5MP9a!61Z1en88}5mX`Wa62UOj7)T0MU^f%>QGK z-&ixEWDMzI2uJ-#Z1@2$|Ann1<@=}WBC&P1t5qx8Ss}yKRebx6o_ipn_P;qV`0pbi zR$}F0iKt0qvxL~eVE_;}NPrs%V6%01cX7MJgQyHZP;KB47h5|^H*Of*hW$svkwH|f zx!b{8Sfk5`ZPx@#2lYt;o5X|OE@T(>KEC~2( zsrTVfYaAc|%!>p3eE|gc`FZ&P)_|WhVIe+**^n2&`4iq_&+86lq_i&uhV8?f@j?&&a6gYz+fkIqOw8b#sTn-LE_XF`giz+>%*VT@L5} E0IK=vy8r+H literal 0 HcmV?d00001 From 968b207135bede702bcedd1f6398642fcc7547f6 Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 14:59:43 -0400 Subject: [PATCH 3/9] added printSignature and evaluate --- gtsam/discrete/DiscreteBayesTree.cpp | 10 ++++ gtsam/discrete/DiscreteBayesTree.h | 85 ++++++++++++++++------------ gtsam/discrete/DiscreteConditional.h | 9 +++ gtsam/inference/Conditional.h | 3 +- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/gtsam/discrete/DiscreteBayesTree.cpp b/gtsam/discrete/DiscreteBayesTree.cpp index 8fcc34e25..990d10dbe 100644 --- a/gtsam/discrete/DiscreteBayesTree.cpp +++ b/gtsam/discrete/DiscreteBayesTree.cpp @@ -45,6 +45,16 @@ namespace gtsam { return Base::equals(other, tol); } + /* ************************************************************************* */ + double DiscreteBayesTree::evaluate( + const DiscreteConditional::Values& values) const { + double result = 1.0; + for (const auto& root : roots_) { + result *= root->evaluate(values); + } + return result; + } + } // \namespace gtsam diff --git a/gtsam/discrete/DiscreteBayesTree.h b/gtsam/discrete/DiscreteBayesTree.h index aa8f4657c..3d6e016fd 100644 --- a/gtsam/discrete/DiscreteBayesTree.h +++ b/gtsam/discrete/DiscreteBayesTree.h @@ -11,7 +11,8 @@ /** * @file DiscreteBayesTree.h - * @brief Discrete Bayes Tree, the result of eliminating a DiscreteJunctionTree + * @brief Discrete Bayes Tree, the result of eliminating a + * DiscreteJunctionTree * @brief DiscreteBayesTree * @author Frank Dellaert * @author Richard Roberts @@ -22,48 +23,62 @@ #include #include #include +#include #include +#include + namespace gtsam { - // Forward declarations - class DiscreteConditional; - class VectorValues; +// Forward declarations +class DiscreteConditional; +class VectorValues; - /* ************************************************************************* */ - /** A clique in a DiscreteBayesTree */ - class GTSAM_EXPORT DiscreteBayesTreeClique : - public BayesTreeCliqueBase - { - public: - typedef DiscreteBayesTreeClique This; - typedef BayesTreeCliqueBase Base; - typedef boost::shared_ptr shared_ptr; - typedef boost::weak_ptr weak_ptr; - DiscreteBayesTreeClique() {} - DiscreteBayesTreeClique(const boost::shared_ptr& conditional) : Base(conditional) {} +/* ************************************************************************* */ +/** A clique in a DiscreteBayesTree */ +class GTSAM_EXPORT DiscreteBayesTreeClique + : public BayesTreeCliqueBase { + public: + typedef DiscreteBayesTreeClique This; + typedef BayesTreeCliqueBase + Base; + typedef boost::shared_ptr shared_ptr; + typedef boost::weak_ptr weak_ptr; + DiscreteBayesTreeClique() {} + DiscreteBayesTreeClique( + const boost::shared_ptr& conditional) + : Base(conditional) {} - //** evaluate conditional probability of subtree for given Values */ - double evaluate(const DiscreteConditional::Values & values) const; - }; + /// print index signature only + void printSignature( + const std::string& s = "Clique: ", + const KeyFormatter& formatter = DefaultKeyFormatter) const { + conditional_->printSignature(s, formatter); + } - /* ************************************************************************* */ - /** A Bayes tree representing a Discrete density */ - class GTSAM_EXPORT DiscreteBayesTree : - public BayesTree - { - private: - typedef BayesTree Base; + //** evaluate conditional probability of subtree for given Values */ + double evaluate(const DiscreteConditional::Values& values) const; +}; - public: - typedef DiscreteBayesTree This; - typedef boost::shared_ptr shared_ptr; +/* ************************************************************************* */ +/** A Bayes tree representing a Discrete density */ +class GTSAM_EXPORT DiscreteBayesTree + : public BayesTree { + private: + typedef BayesTree Base; - /** Default constructor, creates an empty Bayes tree */ - DiscreteBayesTree() {} + public: + typedef DiscreteBayesTree This; + typedef boost::shared_ptr shared_ptr; - /** Check equality */ - bool equals(const This& other, double tol = 1e-9) const; - }; + /** Default constructor, creates an empty Bayes tree */ + DiscreteBayesTree() {} -} + /** Check equality */ + bool equals(const This& other, double tol = 1e-9) const; + + //** evaluate probability for given Values */ + double evaluate(const DiscreteConditional::Values& values) const; +}; + +} // namespace gtsam diff --git a/gtsam/discrete/DiscreteConditional.h b/gtsam/discrete/DiscreteConditional.h index 3da8d0a82..225e6e1d3 100644 --- a/gtsam/discrete/DiscreteConditional.h +++ b/gtsam/discrete/DiscreteConditional.h @@ -24,6 +24,8 @@ #include #include +#include + namespace gtsam { /** @@ -92,6 +94,13 @@ public: /// @name Standard Interface /// @{ + /// print index signature only + void printSignature( + const std::string& s = "Discrete Conditional: ", + const KeyFormatter& formatter = DefaultKeyFormatter) const { + static_cast(this)->print(s, formatter); + } + /// Evaluate, just look up in AlgebraicDecisonTree virtual double operator()(const Values& values) const { return Potentials::operator()(values); diff --git a/gtsam/inference/Conditional.h b/gtsam/inference/Conditional.h index 1d486030c..295122879 100644 --- a/gtsam/inference/Conditional.h +++ b/gtsam/inference/Conditional.h @@ -65,6 +65,8 @@ namespace gtsam { Conditional(size_t nrFrontals) : nrFrontals_(nrFrontals) {} /// @} + + public: /// @name Testable /// @{ @@ -76,7 +78,6 @@ namespace gtsam { /// @} - public: /// @name Standard Interface /// @{ From ae808d039cda45df8334d1857773c9c06c2943a0 Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 15:00:34 -0400 Subject: [PATCH 4/9] Fixed link issue --- gtsam/discrete/tests/testDiscreteFactorGraph.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gtsam/discrete/tests/testDiscreteFactorGraph.cpp b/gtsam/discrete/tests/testDiscreteFactorGraph.cpp index 0fbf44097..7a0e1eaf7 100644 --- a/gtsam/discrete/tests/testDiscreteFactorGraph.cpp +++ b/gtsam/discrete/tests/testDiscreteFactorGraph.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include From d456dddc6f1860f76b3ff8a7be555d55a430fb6d Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 15:00:54 -0400 Subject: [PATCH 5/9] Cleaned up formatting --- gtsam/inference/BayesTreeCliqueBase-inst.h | 54 ++++++++++++---------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/gtsam/inference/BayesTreeCliqueBase-inst.h b/gtsam/inference/BayesTreeCliqueBase-inst.h index e762786f5..a02fe274e 100644 --- a/gtsam/inference/BayesTreeCliqueBase-inst.h +++ b/gtsam/inference/BayesTreeCliqueBase-inst.h @@ -136,57 +136,61 @@ namespace gtsam { } } - /* ************************************************************************* */ + /* *********************************************************************** */ // separator marginal, uses separator marginal of parent recursively // P(C) = P(F|S) P(S) - /* ************************************************************************* */ - template + /* *********************************************************************** */ + template typename BayesTreeCliqueBase::FactorGraphType - BayesTreeCliqueBase::separatorMarginal(Eliminate function) const - { + BayesTreeCliqueBase::separatorMarginal( + Eliminate function) const { gttic(BayesTreeCliqueBase_separatorMarginal); // Check if the Separator marginal was already calculated - if (!cachedSeparatorMarginal_) - { + if (!cachedSeparatorMarginal_) { gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss); + // If this is the root, there is no separator - if (parent_.expired() /*(if we're the root)*/) - { + if (parent_.expired() /*(if we're the root)*/) { // we are root, return empty FactorGraphType empty; cachedSeparatorMarginal_ = empty; - } - else - { + } else { + // Flatten recursion in timing outline + gttoc(BayesTreeCliqueBase_separatorMarginal_cachemiss); + gttoc(BayesTreeCliqueBase_separatorMarginal); + // Obtain P(S) = \int P(Cp) = \int P(Fp|Sp) P(Sp) // initialize P(Cp) with the parent separator marginal derived_ptr parent(parent_.lock()); - gttoc(BayesTreeCliqueBase_separatorMarginal_cachemiss); // Flatten recursion in timing outline - gttoc(BayesTreeCliqueBase_separatorMarginal); - FactorGraphType p_Cp(parent->separatorMarginal(function)); // P(Sp) + FactorGraphType p_Cp(parent->separatorMarginal(function)); // P(Sp) + gttic(BayesTreeCliqueBase_separatorMarginal); gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss); + // now add the parent conditional - p_Cp += parent->conditional_; // P(Fp|Sp) + p_Cp += parent->conditional_; // P(Fp|Sp) // The variables we want to keepSet are exactly the ones in S - KeyVector indicesS(this->conditional()->beginParents(), this->conditional()->endParents()); - cachedSeparatorMarginal_ = *p_Cp.marginalMultifrontalBayesNet(Ordering(indicesS), function); + KeyVector indicesS(this->conditional()->beginParents(), + this->conditional()->endParents()); + auto separatorMarginal = + p_Cp.marginalMultifrontalBayesNet(Ordering(indicesS), function); + cachedSeparatorMarginal_.reset(*separatorMarginal); } } // return the shortcut P(S||B) - return *cachedSeparatorMarginal_; // return the cached version + return *cachedSeparatorMarginal_; // return the cached version } - /* ************************************************************************* */ - // marginal2, uses separator marginal of parent recursively + /* *********************************************************************** */ + // marginal2, uses separator marginal of parent // P(C) = P(F|S) P(S) - /* ************************************************************************* */ - template + /* *********************************************************************** */ + template typename BayesTreeCliqueBase::FactorGraphType - BayesTreeCliqueBase::marginal2(Eliminate function) const - { + BayesTreeCliqueBase::marginal2( + Eliminate function) const { gttic(BayesTreeCliqueBase_marginal2); // initialize with separator marginal P(S) FactorGraphType p_C = this->separatorMarginal(function); From 468c7aee0cd9b5933178b7304a6acce34eeb8692 Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Sun, 12 Jul 2020 15:01:00 -0400 Subject: [PATCH 6/9] Fixed tests --- .../discrete/tests/testDiscreteBayesTree.cpp | 191 ++++++++---------- 1 file changed, 81 insertions(+), 110 deletions(-) diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.cpp b/gtsam/discrete/tests/testDiscreteBayesTree.cpp index f58fd2b19..150a41c24 100644 --- a/gtsam/discrete/tests/testDiscreteBayesTree.cpp +++ b/gtsam/discrete/tests/testDiscreteBayesTree.cpp @@ -33,41 +33,6 @@ using namespace gtsam; static bool debug = false; -// /** -// * Custom clique class to debug shortcuts -// */ -// struct Clique : public BayesTreeCliqueBase { -// typedef BayesTreeCliqueBase Base; -// typedef boost::shared_ptr shared_ptr; - -// // Constructors -// Clique() {} -// explicit Clique(const DiscreteConditional::shared_ptr& conditional) -// : Base(conditional) {} -// Clique(const std::pair& -// result) -// : Base(result) {} - -// /// print index signature only -// void printSignature( -// const std::string& s = "Clique: ", -// const KeyFormatter& indexFormatter = DefaultKeyFormatter) const { -// ((IndexConditionalOrdered::shared_ptr)conditional_) -// ->print(s, indexFormatter); -// } - -// /// evaluate value of sub-tree -// double evaluate(const DiscreteConditional::Values& values) { -// double result = (*(this->conditional_))(values); -// // evaluate all children and multiply into result -// for (boost::shared_ptr c : children_) result *= -// c->evaluate(values); return result; -// } -// }; - -// typedef BayesTreeOrdered DiscreteBayesTree; - /* ************************************************************************* */ TEST_UNSAFE(DiscreteBayesTree, thinTree) { @@ -124,24 +89,24 @@ TEST_UNSAFE(DiscreteBayesTree, thinTree) { for (size_t i = 0; i < allPosbValues.size(); ++i) { DiscreteFactor::Values x = allPosbValues[i]; double expected = bayesNet.evaluate(x); - double actual = R->evaluate(x); + double actual = bayesTree->evaluate(x); DOUBLES_EQUAL(expected, actual, 1e-9); } - // Calculate all some marginals + // Calculate all some marginals for Values==all1 Vector marginals = zero(15); double joint_12_14 = 0, joint_9_12_14 = 0, joint_8_12_14 = 0, joint_8_12 = 0, joint82 = 0, joint12 = 0, joint24 = 0, joint45 = 0, joint46 = 0, - joint_4_11 = 0; + joint_4_11 = 0, joint_11_13 = 0, joint_11_13_14 = 0, + joint_11_12_13_14 = 0, joint_9_11_12_13 = 0, joint_8_11_12_13 = 0; for (size_t i = 0; i < allPosbValues.size(); ++i) { DiscreteFactor::Values x = allPosbValues[i]; - double px = R->evaluate(x); + double px = bayesTree->evaluate(x); for (size_t i = 0; i < 15; i++) if (x[i]) marginals[i] += px; - // calculate shortcut 8 and 0 if (x[12] && x[14]) joint_12_14 += px; - if (x[9] && x[12] & x[14]) joint_9_12_14 += px; - if (x[8] && x[12] & x[14]) joint_8_12_14 += px; + if (x[9] && x[12] && x[14]) joint_9_12_14 += px; + if (x[8] && x[12] && x[14]) joint_8_12_14 += px; if (x[8] && x[12]) joint_8_12 += px; if (x[8] && x[2]) joint82 += px; if (x[1] && x[2]) joint12 += px; @@ -149,96 +114,102 @@ TEST_UNSAFE(DiscreteBayesTree, thinTree) { if (x[4] && x[5]) joint45 += px; if (x[4] && x[6]) joint46 += px; if (x[4] && x[11]) joint_4_11 += px; + if (x[11] && x[13]) { + joint_11_13 += px; + if (x[8] && x[12]) joint_8_11_12_13 += px; + if (x[9] && x[12]) joint_9_11_12_13 += px; + if (x[14]) { + joint_11_13_14 += px; + if (x[12]) { + joint_11_12_13_14 += px; + } + } + } } DiscreteFactor::Values all1 = allPosbValues.back(); - // check separator marginal P(S0) auto c = (*bayesTree)[0]; DiscreteFactorGraph separatorMarginal0 = c->separatorMarginal(EliminateDiscrete); - EXPECT_DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9); + DOUBLES_EQUAL(joint_8_12, separatorMarginal0(all1), 1e-9); - // // check separator marginal P(S9), should be P(14) - // c = (*bayesTree)[9]; - // DiscreteFactorGraph separatorMarginal9 = - // c->separatorMarginal(EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(marginals[14], separatorMarginal9(all1), 1e-9); + // check separator marginal P(S9), should be P(14) + c = (*bayesTree)[9]; + DiscreteFactorGraph separatorMarginal9 = + c->separatorMarginal(EliminateDiscrete); + DOUBLES_EQUAL(marginals[14], separatorMarginal9(all1), 1e-9); - // // check separator marginal of root, should be empty - // c = (*bayesTree)[11]; - // DiscreteFactorGraph separatorMarginal11 = - // c->separatorMarginal(EliminateDiscrete); - // EXPECT_LONGS_EQUAL(0, separatorMarginal11.size()); + // check separator marginal of root, should be empty + c = (*bayesTree)[11]; + DiscreteFactorGraph separatorMarginal11 = + c->separatorMarginal(EliminateDiscrete); + LONGS_EQUAL(0, separatorMarginal11.size()); - // // check shortcut P(S9||R) to root - // c = (*bayesTree)[9]; - // DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); - // EXPECT_LONGS_EQUAL(0, shortcut.size()); + // check shortcut P(S9||R) to root + c = (*bayesTree)[9]; + DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); + LONGS_EQUAL(1, shortcut.size()); + DOUBLES_EQUAL(joint_11_13_14 / joint_11_13, shortcut.evaluate(all1), 1e-9); - // // check shortcut P(S8||R) to root - // c = (*bayesTree)[8]; - // shortcut = c->shortcut(R, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint_12_14 / marginals[14], evaluate(shortcut, all1), - // 1e-9); + // check shortcut P(S8||R) to root + c = (*bayesTree)[8]; + shortcut = c->shortcut(R, EliminateDiscrete); + DOUBLES_EQUAL(joint_11_12_13_14 / joint_11_13, shortcut.evaluate(all1), 1e-9); - // // check shortcut P(S2||R) to root - // c = (*bayesTree)[2]; - // shortcut = c->shortcut(R, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint_9_12_14 / marginals[14], evaluate(shortcut, - // all1), - // 1e-9); + // check shortcut P(S2||R) to root + c = (*bayesTree)[2]; + shortcut = c->shortcut(R, EliminateDiscrete); + DOUBLES_EQUAL(joint_9_11_12_13 / joint_11_13, shortcut.evaluate(all1), 1e-9); - // // check shortcut P(S0||R) to root - // c = (*bayesTree)[0]; - // shortcut = c->shortcut(R, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint_8_12_14 / marginals[14], evaluate(shortcut, - // all1), - // 1e-9); + // check shortcut P(S0||R) to root + c = (*bayesTree)[0]; + shortcut = c->shortcut(R, EliminateDiscrete); + DOUBLES_EQUAL(joint_8_11_12_13 / joint_11_13, shortcut.evaluate(all1), 1e-9); - // // calculate all shortcuts to root - // DiscreteBayesTree::Nodes cliques = bayesTree->nodes(); - // for (auto c : cliques) { - // DiscreteBayesNet shortcut = c->shortcut(R, EliminateDiscrete); - // if (debug) { - // c->printSignature(); - // shortcut.print("shortcut:"); - // } - // } + // calculate all shortcuts to root + DiscreteBayesTree::Nodes cliques = bayesTree->nodes(); + for (auto c : cliques) { + DiscreteBayesNet shortcut = c.second->shortcut(R, EliminateDiscrete); + if (debug) { + c.second->conditional_->printSignature(); + shortcut.print("shortcut:"); + } + } - // // Check all marginals - // DiscreteFactor::shared_ptr marginalFactor; - // for (size_t i = 0; i < 15; i++) { - // marginalFactor = bayesTree->marginalFactor(i, EliminateDiscrete); - // double actual = (*marginalFactor)(all1); - // EXPECT_DOUBLES_EQUAL(marginals[i], actual, 1e-9); - // } + // Check all marginals + DiscreteFactor::shared_ptr marginalFactor; + for (size_t i = 0; i < 15; i++) { + marginalFactor = bayesTree->marginalFactor(i, EliminateDiscrete); + double actual = (*marginalFactor)(all1); + DOUBLES_EQUAL(marginals[i], actual, 1e-9); + } - // DiscreteBayesNet::shared_ptr actualJoint; + DiscreteBayesNet::shared_ptr actualJoint; - // Check joint P(8,2) TODO: not disjoint ! - // actualJoint = bayesTree->jointBayesNet(8, 2, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint82, evaluate(*actualJoint,all1), 1e-9); + // Check joint P(8, 2) + actualJoint = bayesTree->jointBayesNet(8, 2, EliminateDiscrete); + DOUBLES_EQUAL(joint82, actualJoint->evaluate(all1), 1e-9); - // Check joint P(1,2) TODO: not disjoint ! - // actualJoint = bayesTree->jointBayesNet(1, 2, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint12, evaluate(*actualJoint,all1), 1e-9); + // Check joint P(1, 2) + actualJoint = bayesTree->jointBayesNet(1, 2, EliminateDiscrete); + DOUBLES_EQUAL(joint12, actualJoint->evaluate(all1), 1e-9); - // Check joint P(2,4) - // actualJoint = bayesTree->jointBayesNet(2, 4, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint24, evaluate(*actualJoint, all1), 1e-9); + // Check joint P(2, 4) + actualJoint = bayesTree->jointBayesNet(2, 4, EliminateDiscrete); + DOUBLES_EQUAL(joint24, actualJoint->evaluate(all1), 1e-9); - // Check joint P(4,5) TODO: not disjoint ! - // actualJoint = bayesTree->jointBayesNet(4, 5, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); + // Check joint P(4, 5) + actualJoint = bayesTree->jointBayesNet(4, 5, EliminateDiscrete); + DOUBLES_EQUAL(joint45, actualJoint->evaluate(all1), 1e-9); - // Check joint P(4,6) TODO: not disjoint ! - // actualJoint = bayesTree->jointBayesNet(4, 6, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint46, evaluate(*actualJoint,all1), 1e-9); + // Check joint P(4, 6) + actualJoint = bayesTree->jointBayesNet(4, 6, EliminateDiscrete); + DOUBLES_EQUAL(joint46, actualJoint->evaluate(all1), 1e-9); - // Check joint P(4,11) - // actualJoint = bayesTree->jointBayesNet(4, 11, EliminateDiscrete); - // EXPECT_DOUBLES_EQUAL(joint_4_11, evaluate(*actualJoint, all1), 1e-9); + // Check joint P(4, 11) + actualJoint = bayesTree->jointBayesNet(4, 11, EliminateDiscrete); + DOUBLES_EQUAL(joint_4_11, actualJoint->evaluate(all1), 1e-9); } /* ************************************************************************* */ From c68ab6b3bedf9576416b816089482c1a2e14ce50 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sun, 12 Jul 2020 19:54:23 -0400 Subject: [PATCH 7/9] correct vector init --- gtsam/discrete/tests/testDiscreteBayesTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.cpp b/gtsam/discrete/tests/testDiscreteBayesTree.cpp index 150a41c24..9950c014e 100644 --- a/gtsam/discrete/tests/testDiscreteBayesTree.cpp +++ b/gtsam/discrete/tests/testDiscreteBayesTree.cpp @@ -35,7 +35,7 @@ static bool debug = false; /* ************************************************************************* */ -TEST_UNSAFE(DiscreteBayesTree, thinTree) { +TEST_UNSAFE(DiscreteBayesTree, ThinTree) { const int nrNodes = 15; const size_t nrStates = 2; @@ -94,7 +94,7 @@ TEST_UNSAFE(DiscreteBayesTree, thinTree) { } // Calculate all some marginals for Values==all1 - Vector marginals = zero(15); + Vector marginals = Vector::Zero(15); double joint_12_14 = 0, joint_9_12_14 = 0, joint_8_12_14 = 0, joint_8_12 = 0, joint82 = 0, joint12 = 0, joint24 = 0, joint45 = 0, joint46 = 0, joint_4_11 = 0, joint_11_13 = 0, joint_11_13_14 = 0, From c67779fdce5f0897ce36c85b1b2ea65896513862 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sun, 12 Jul 2020 19:54:42 -0400 Subject: [PATCH 8/9] delete extra pdf file --- gtsam/discrete/tests/testDiscreteBayesTree.pdf | Bin 10622 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 gtsam/discrete/tests/testDiscreteBayesTree.pdf diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.pdf b/gtsam/discrete/tests/testDiscreteBayesTree.pdf deleted file mode 100644 index e8167d455477f97aadb2101d26120a6c145891f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10622 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 E0IK=vy8r+H From 80b42dcbefeae96b53a5598b3a470734c5e5df68 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sun, 12 Jul 2020 20:55:13 -0400 Subject: [PATCH 9/9] Revert "delete extra pdf file" This reverts commit c67779fdce5f0897ce36c85b1b2ea65896513862. --- gtsam/discrete/tests/testDiscreteBayesTree.pdf | Bin 0 -> 10622 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gtsam/discrete/tests/testDiscreteBayesTree.pdf diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.pdf b/gtsam/discrete/tests/testDiscreteBayesTree.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e8167d455477f97aadb2101d26120a6c145891f5 GIT binary patch literal 10622 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 E0IK=vy8r+H literal 0 HcmV?d00001