Working html for conditionals

release/4.3a0
Frank Dellaert 2022-01-09 10:16:25 -05:00
parent e8127792f2
commit a7b7a8b0fa
5 changed files with 65 additions and 29 deletions

View File

@ -348,18 +348,14 @@ std::string DiscreteConditional::markdown(const KeyFormatter& keyFormatter,
return ss.str();
}
// Print out header and construct argument for `cartesianProduct`.
// Print out header.
ss << "|";
for (Key parent : parents()) {
ss << "*" << keyFormatter(parent) << "*|";
}
size_t n = 1;
for (Key key : frontals()) {
size_t k = cardinalities_.at(key);
n *= k;
}
for (const auto& a : frontalAssignments()) {
auto frontalAssignments = this->frontalAssignments();
for (const auto& a : frontalAssignments) {
for (auto&& it = beginFrontals(); it != endFrontals(); ++it) {
size_t index = a.at(*it);
ss << Translate(names, *it, index);
@ -370,6 +366,7 @@ std::string DiscreteConditional::markdown(const KeyFormatter& keyFormatter,
// Print out separator with alignment hints.
ss << "|";
size_t n = frontalAssignments.size();
for (size_t j = 0; j < nrParents() + n; j++) ss << ":-:|";
ss << "\n";
@ -408,28 +405,37 @@ string DiscreteConditional::html(const KeyFormatter& keyFormatter,
// Print out header row.
ss << " <tr>";
for (auto& key : keys()) {
ss << "<th>" << keyFormatter(key) << "</th>";
for (Key parent : parents()) {
ss << "<th><i>" << keyFormatter(parent) << "</i></th>";
}
ss << "<th>value</th></tr>\n";
auto frontalAssignments = this->frontalAssignments();
for (const auto& a : frontalAssignments) {
for (auto&& it = beginFrontals(); it != endFrontals(); ++it) {
size_t index = a.at(*it);
ss << "<th>" << Translate(names, *it, index) << "</th>";
}
}
ss << "</tr>\n";
// Finish header and start body.
ss << " </thead>\n <tbody>\n";
// Print out all rows.
auto rows = enumerate();
for (const auto& kv : rows) {
size_t count = 0, n = frontalAssignments.size();
for (const auto& a : allAssignments()) {
if (count == 0) {
ss << " <tr>";
auto assignment = kv.first;
for (auto& key : keys()) {
size_t index = assignment.at(key);
ss << "<th>" << Translate(names, key, index) << "</th>";
for (auto&& it = beginParents(); it != endParents(); ++it) {
size_t index = a.at(*it);
ss << "<th>" << Translate(names, *it, index) << "</th>";
}
ss << "<td>" << kv.second << "</td>"; // value
ss << "</tr>\n";
}
ss << " </tbody>\n</table>\n</div>";
ss << "<td>" << operator()(a) << "</td>"; // value
count = (count + 1) % n;
if (count == 0) ss << "</tr>\n";
}
// Finish up
ss << " </tbody>\n</table>\n</div>";
return ss.str();
}

View File

@ -182,13 +182,13 @@ TEST(DiscreteBayesNet, markdown) {
string expected =
"`DiscreteBayesNet` of size 2\n"
"\n"
" *P(Asia)*:\n\n"
" *P(Asia):*\n\n"
"|Asia|value|\n"
"|:-:|:-:|\n"
"|0|0.99|\n"
"|1|0.01|\n"
"\n"
" *P(Smoking|Asia)*:\n\n"
" *P(Smoking|Asia):*\n\n"
"|*Asia*|0|1|\n"
"|:-:|:-:|:-:|\n"
"|0|0.8|0.2|\n"

View File

@ -125,7 +125,7 @@ TEST(DiscreteConditional, markdown_prior) {
DiscreteKey A(Symbol('x', 1), 3);
DiscreteConditional conditional(A % "1/2/2");
string expected =
" *P(x1)*:\n\n"
" *P(x1):*\n\n"
"|x1|value|\n"
"|:-:|:-:|\n"
"|0|0.2|\n"
@ -142,7 +142,7 @@ TEST(DiscreteConditional, markdown_prior_names) {
DiscreteKey A(x1, 3);
DiscreteConditional conditional(A % "1/2/2");
string expected =
" *P(x1)*:\n\n"
" *P(x1):*\n\n"
"|x1|value|\n"
"|:-:|:-:|\n"
"|A0|0.2|\n"
@ -160,7 +160,7 @@ TEST(DiscreteConditional, markdown_multivalued) {
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\n"
" *P(a1|b1):*\n\n"
"|*b1*|0|1|2|\n"
"|:-:|:-:|:-:|:-:|\n"
"|0|0.02|0.88|0.1|\n"
@ -178,7 +178,7 @@ 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");
string expected =
" *P(A|B,C)*:\n\n"
" *P(A|B,C):*\n\n"
"|*B*|*C*|T|F|\n"
"|:-:|:-:|:-:|:-:|\n"
"|-|Zero|0|1|\n"
@ -195,6 +195,36 @@ TEST(DiscreteConditional, markdown) {
EXPECT(actual == expected);
}
/* ************************************************************************* */
// Check html representation looks as expected, two parents + names.
TEST(DiscreteConditional, html) {
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");
string expected =
"<div>\n"
"<p> <i>P(A|B,C):</i></p>\n"
"<table class='DiscreteConditional'>\n"
" <thead>\n"
" <tr><th><i>B</i></th><th><i>C</i></th><th>T</th><th>F</th></tr>\n"
" </thead>\n"
" <tbody>\n"
" <tr><th>-</th><th>Zero</th><td>0</td><td>1</td></tr>\n"
" <tr><th>-</th><th>One</th><td>0.25</td><td>0.75</td></tr>\n"
" <tr><th>-</th><th>Two</th><td>0.5</td><td>0.5</td></tr>\n"
" <tr><th>+</th><th>Zero</th><td>0.75</td><td>0.25</td></tr>\n"
" <tr><th>+</th><th>One</th><td>0</td><td>1</td></tr>\n"
" <tr><th>+</th><th>Two</th><td>1</td><td>0</td></tr>\n"
" </tbody>\n"
"</table>\n"
"</div>";
vector<string> keyNames{"C", "B", "A"};
auto formatter = [keyNames](Key key) { return keyNames[key]; };
DecisionTreeFactor::Names names{
{0, {"Zero", "One", "Two"}}, {1, {"-", "+"}}, {2, {"T", "F"}}};
string actual = conditional.html(formatter, names);
EXPECT(actual == expected);
}
/* ************************************************************************* */
int main() {
TestResult tr;

View File

@ -49,7 +49,7 @@ class TestDiscreteConditional(GtsamTestCase):
conditional = DiscreteConditional(A, parents,
"0/1 1/3 1/1 3/1 0/1 1/0")
expected = \
" *P(A|B,C)*:\n\n" \
" *P(A|B,C):*\n\n" \
"|*B*|*C*|0|1|\n" \
"|:-:|:-:|:-:|:-:|\n" \
"|0|0|0|1|\n" \

View File

@ -51,7 +51,7 @@ class TestDiscretePrior(GtsamTestCase):
"""Test the _repr_markdown_ method."""
prior = DiscretePrior(X, "2/3")
expected = " *P(0)*:\n\n" \
expected = " *P(0):*\n\n" \
"|0|value|\n" \
"|:-:|:-:|\n" \
"|0|0.4|\n" \