diff --git a/gtsam/discrete/DiscreteConditional.cpp b/gtsam/discrete/DiscreteConditional.cpp index 2a891feb0..7ed962188 100644 --- a/gtsam/discrete/DiscreteConditional.cpp +++ b/gtsam/discrete/DiscreteConditional.cpp @@ -227,41 +227,66 @@ std::string DiscreteConditional::_repr_markdown_( const KeyFormatter& keyFormatter) const { std::stringstream ss; + // Print out signature. + ss << " $P("; + for(Key key: frontals()) + ss << keyFormatter(key); + if (nrParents() > 0) + ss << "|"; + bool first = true; + for (Key parent : parents()) { + if (!first) ss << ","; + ss << keyFormatter(parent); + first = false; + } + ss << ")$:" << std::endl; + // Print out header and construct argument for `cartesianProduct`. - // TODO(dellaert): examine why we can't use "for (auto key: frontals())" std::vector> pairs; ss << "|"; const_iterator it; - for (it = beginParents(); it != endParents(); ++it) { - auto key = *it; - ss << keyFormatter(key) << "|"; - pairs.emplace_back(key, cardinalities_.at(key)); + for(Key parent: parents()) { + ss << keyFormatter(parent) << "|"; + pairs.emplace_back(parent, cardinalities_.at(parent)); } - for (it = beginFrontals(); it != endFrontals(); ++it) { - auto key = *it; - ss << keyFormatter(key) << "|"; - pairs.emplace_back(key, cardinalities_.at(key)); + + size_t n = 1; + for(Key key: frontals()) { + size_t k = cardinalities_.at(key); + pairs.emplace_back(key, k); + n *= k; } - ss << "value|\n"; + size_t nrParents = size() - nrFrontals_; + std::vector> slatnorf(pairs.rbegin(), + pairs.rend() - nrParents); + const auto frontal_assignments = cartesianProduct(slatnorf); + for (const auto& a : frontal_assignments) { + for (it = beginFrontals(); it != endFrontals(); ++it) ss << a.at(*it); + ss << "|"; + } + ss << "\n"; // Print out separator with alignment hints. ss << "|"; - for (size_t j = 0; j < size(); j++) ss << ":-:|"; - ss << ":-:|\n"; + for (size_t j = 0; j < nrParents + n; j++) ss << ":-:|"; + ss << "\n"; // Print out all rows. std::vector> rpairs(pairs.rbegin(), pairs.rend()); const auto assignments = cartesianProduct(rpairs); + size_t count = 0; for (const auto& a : assignments) { - ss << "|"; - for (it = beginParents(); it != endParents(); ++it) ss << a.at(*it) << "|"; - for (it = beginFrontals(); it != endFrontals(); ++it) - ss << "*" << a.at(*it) << "*|"; - ss << operator()(a) << "|\n"; + if (count == 0) { + ss << "|"; + for (it = beginParents(); it != endParents(); ++it) + ss << a.at(*it) << "|"; + } + ss << operator()(a) << "|"; + count = (count + 1) % n; + if (count == 0) ss << "\n"; } return ss.str(); } -/* ******************************************************************************** - */ +/* ************************************************************************* */ -}// namespace +} // namespace gtsam diff --git a/gtsam/discrete/tests/testDiscreteConditional.cpp b/gtsam/discrete/tests/testDiscreteConditional.cpp index d031882c1..698268e84 100644 --- a/gtsam/discrete/tests/testDiscreteConditional.cpp +++ b/gtsam/discrete/tests/testDiscreteConditional.cpp @@ -24,6 +24,7 @@ using namespace boost::assign; #include #include #include +#include using namespace std; using namespace gtsam; @@ -107,40 +108,53 @@ TEST(DiscreteConditional, Combine) { } /* ************************************************************************* */ -// TEST(DiscreteConditional, Combine2) { -// DiscreteKey A(0, 3), B(1, 2), C(2, 2); -// vector c; -// auto P = {B, C}; -// c.push_back(boost::make_shared(A, P, "1/2 2/1 1/2 2/1")); -// c.push_back(boost::make_shared(B | C = "1/2")); -// auto actual = DiscreteConditional::Combine(c.begin(), c.end()); -// GTSAM_PRINT(*actual); -// } +// Check markdown representation looks as expected, no parents. +TEST(DiscreteConditional, markdown_prior) { + DiscreteKey A(Symbol('x', 1), 2); + DiscreteConditional conditional(A % "1/3"); + string expected = + " $P(x1)$:\n" + "|0|1|\n" + "|:-:|:-:|\n" + "|0.25|0.75|\n"; + string actual = conditional._repr_markdown_(); + EXPECT(actual == expected); +} /* ************************************************************************* */ -// Check markdown representation looks as expected. +// Check markdown representation looks as expected, multivalued. +TEST(DiscreteConditional, markdown_multivalued) { + DiscreteKey A(Symbol('a', 1), 3), B(Symbol('b', 1), 5); + DiscreteConditional conditional( + A | B = "2/88/10 2/20/78 33/33/34 33/33/34 95/2/3"); + string expected = + " $P(a1|b1)$:\n" + "|b1|0|1|2|\n" + "|:-:|:-:|:-:|:-:|\n" + "|0|0.02|0.88|0.1|\n" + "|1|0.02|0.2|0.78|\n" + "|2|0.33|0.33|0.34|\n" + "|3|0.33|0.33|0.34|\n" + "|4|0.95|0.02|0.03|\n"; + string actual = conditional._repr_markdown_(); + EXPECT(actual == expected); +} + +/* ************************************************************************* */ +// Check markdown representation looks as expected, two parents. TEST(DiscreteConditional, markdown) { DiscreteKey A(2, 2), B(1, 2), C(0, 3); DiscreteConditional conditional(A, {B, C}, "0/1 1/3 1/1 3/1 0/1 1/0"); - EXPECT_LONGS_EQUAL(A.first, *(conditional.beginFrontals())); - EXPECT_LONGS_EQUAL(B.first, *(conditional.beginParents())); - EXPECT(conditional.endParents() == conditional.end()); - EXPECT(conditional.endFrontals() == conditional.beginParents()); string expected = - "|B|C|A|value|\n" + " $P(A|B,C)$:\n" + "|B|C|0|1|\n" "|:-:|:-:|:-:|:-:|\n" - "|0|0|*0*|0|\n" - "|0|0|*1*|1|\n" - "|0|1|*0*|0.25|\n" - "|0|1|*1*|0.75|\n" - "|0|2|*0*|0.5|\n" - "|0|2|*1*|0.5|\n" - "|1|0|*0*|0.75|\n" - "|1|0|*1*|0.25|\n" - "|1|1|*0*|0|\n" - "|1|1|*1*|1|\n" - "|1|2|*0*|1|\n" - "|1|2|*1*|0|\n"; + "|0|0|0|1|\n" + "|0|1|0.25|0.75|\n" + "|0|2|0.5|0.5|\n" + "|1|0|0.75|0.25|\n" + "|1|1|0|1|\n" + "|1|2|1|0|\n"; vector names{"C", "B", "A"}; auto formatter = [names](Key key) { return names[key]; }; string actual = conditional._repr_markdown_(formatter);