diff --git a/gtsam/discrete/DecisionTreeFactor.cpp b/gtsam/discrete/DecisionTreeFactor.cpp index 2607a80ef..e9c393c7d 100644 --- a/gtsam/discrete/DecisionTreeFactor.cpp +++ b/gtsam/discrete/DecisionTreeFactor.cpp @@ -187,12 +187,13 @@ namespace gtsam { return ADT::dot(keyFormatter, valueFormatter, showZero); } + // Print out header. /* ************************************************************************* */ string DecisionTreeFactor::markdown(const KeyFormatter& keyFormatter, const Names& names) const { stringstream ss; - // Print out header and construct argument for `cartesianProduct`. + // Print out header. ss << "|"; for (auto& key : keys()) { ss << keyFormatter(key) << "|"; @@ -218,11 +219,63 @@ namespace gtsam { return ss.str(); } + /* ************************************************************************ */ + string DecisionTreeFactor::html(const KeyFormatter& keyFormatter, + const Names& names) const { + const string style = + "\n"; + + stringstream ss; + + // Print out preamble. + ss << "
\n" + << style + << "\n" + " \n"; + + // Print out header row. + ss << " "; + for (auto& key : keys()) { + ss << ""; + } + ss << "\n"; + + // Finish header and start body. + ss << " \n \n"; + + // Print out all rows. + auto rows = enumerate(); + for (const auto& kv : rows) { + ss << " "; + auto assignment = kv.first; + for (auto& key : keys()) { + size_t index = assignment.at(key); + ss << ""; + } + ss << ""; // value + ss << "\n"; + } + ss << " \n
" << keyFormatter(key) << "value
" << Translate(names, key, index) << "" << kv.second << "
\n
"; + return ss.str(); + } + + /* ************************************************************************* */ DecisionTreeFactor::DecisionTreeFactor(const DiscreteKeys &keys, const vector &table) : DiscreteFactor(keys.indices()), AlgebraicDecisionTree(keys, table), cardinalities_(keys.cardinalities()) { } + /* ************************************************************************* */ DecisionTreeFactor::DecisionTreeFactor(const DiscreteKeys &keys, const string &table) : DiscreteFactor(keys.indices()), AlgebraicDecisionTree(keys, table), cardinalities_(keys.cardinalities()) { diff --git a/gtsam/discrete/DecisionTreeFactor.h b/gtsam/discrete/DecisionTreeFactor.h index f7c50d5b5..b5f6c0c4a 100644 --- a/gtsam/discrete/DecisionTreeFactor.h +++ b/gtsam/discrete/DecisionTreeFactor.h @@ -211,6 +211,16 @@ namespace gtsam { std::string markdown(const KeyFormatter& keyFormatter = DefaultKeyFormatter, const Names& names = {}) const override; + /** + * @brief Render as html table + * + * @param keyFormatter GTSAM-style Key formatter. + * @param names optional, category names corresponding to choices. + * @return std::string a html string. + */ + std::string html(const KeyFormatter& keyFormatter = DefaultKeyFormatter, + const Names& names = {}) const override; + /// @} }; diff --git a/gtsam/discrete/DiscreteFactor.h b/gtsam/discrete/DiscreteFactor.h index e30c0a6fe..43486c5ae 100644 --- a/gtsam/discrete/DiscreteFactor.h +++ b/gtsam/discrete/DiscreteFactor.h @@ -106,6 +106,17 @@ public: const KeyFormatter& keyFormatter = DefaultKeyFormatter, const Names& names = {}) const = 0; + /** + * @brief Render as html table + * + * @param keyFormatter GTSAM-style Key formatter. + * @param names optional, category names corresponding to choices. + * @return std::string a html string. + */ + virtual std::string html( + const KeyFormatter& keyFormatter = DefaultKeyFormatter, + const Names& names = {}) const = 0; + /// @} }; // DiscreteFactor diff --git a/gtsam/discrete/discrete.i b/gtsam/discrete/discrete.i index d17401e44..3e8013ce8 100644 --- a/gtsam/discrete/discrete.i +++ b/gtsam/discrete/discrete.i @@ -54,6 +54,10 @@ virtual class DecisionTreeFactor : gtsam::DiscreteFactor { gtsam::DefaultKeyFormatter) const; string markdown(const gtsam::KeyFormatter& keyFormatter, std::map> names) const; + string html(const gtsam::KeyFormatter& keyFormatter = + gtsam::DefaultKeyFormatter) const; + string html(const gtsam::KeyFormatter& keyFormatter, + std::map> names) const; }; #include @@ -93,6 +97,10 @@ virtual class DiscreteConditional : gtsam::DecisionTreeFactor { gtsam::DefaultKeyFormatter) const; string markdown(const gtsam::KeyFormatter& keyFormatter, std::map> names) const; + string html(const gtsam::KeyFormatter& keyFormatter = + gtsam::DefaultKeyFormatter) const; + string html(const gtsam::KeyFormatter& keyFormatter, + std::map> names) const; }; #include diff --git a/gtsam/discrete/tests/testDecisionTreeFactor.cpp b/gtsam/discrete/tests/testDecisionTreeFactor.cpp index 716a77127..c9f692497 100644 --- a/gtsam/discrete/tests/testDecisionTreeFactor.cpp +++ b/gtsam/discrete/tests/testDecisionTreeFactor.cpp @@ -154,6 +154,51 @@ TEST(DecisionTreeFactor, markdownWithValueFormatter) { EXPECT(actual == expected); } +/* ************************************************************************* */ +// Check html representation with a value formatter. +TEST(DecisionTreeFactor, htmlWithValueFormatter) { + DiscreteKey A(12, 3), B(5, 2); + DecisionTreeFactor f(A & B, "1 2 3 4 5 6"); + string expected = + "
\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
ABvalue
Zero-1
Zero+2
One-3
One+4
Two-5
Two+6
\n" + "
"; + auto keyFormatter = [](Key key) { return key == 12 ? "A" : "B"; }; + DecisionTreeFactor::Names names{{12, {"Zero", "One", "Two"}}, + {5, {"-", "+"}}}; + string actual = f.html(keyFormatter, names); + cout << expected << endl; + cout << actual << endl; + ofstream ef("expected=html.txt"), af("actual-html.txt"); + ef << expected << endl; + af << actual << endl; + EXPECT(actual == expected); +} + /* ************************************************************************* */ int main() { TestResult tr; diff --git a/gtsam_unstable/discrete/Constraint.h b/gtsam_unstable/discrete/Constraint.h index 85748f054..4ee7b85eb 100644 --- a/gtsam_unstable/discrete/Constraint.h +++ b/gtsam_unstable/discrete/Constraint.h @@ -91,6 +91,12 @@ class GTSAM_EXPORT Constraint : public DiscreteFactor { return (boost::format("`Constraint` on %1% variables\n") % (size())).str(); } + /// Render as html table. + std::string html(const KeyFormatter& keyFormatter = DefaultKeyFormatter, + const Names& names = {}) const override { + return (boost::format("

Constraint on %1% variables

") % (size())).str(); + } + /// @} }; // DiscreteFactor