Skip to content

Commit

Permalink
Merge pull request #1041 from borglab/release/4.2a3
Browse files Browse the repository at this point in the history
  • Loading branch information
dellaert authored Jan 17, 2022
2 parents d6f3468 + 91de3cb commit 76c7419
Show file tree
Hide file tree
Showing 22 changed files with 527 additions and 175 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
BOOST_VERSION: 1.67.0

strategy:
fail-fast: false
fail-fast: true
matrix:
# Github Actions requires a single row to be added to the build matrix.
# See https://help.github.com/en/articles/workflow-syntax-for-github-actions.
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ endif()
set (GTSAM_VERSION_MAJOR 4)
set (GTSAM_VERSION_MINOR 2)
set (GTSAM_VERSION_PATCH 0)
set (GTSAM_PRERELEASE_VERSION "a2")
set (GTSAM_PRERELEASE_VERSION "a3")
math (EXPR GTSAM_VERSION_NUMERIC "10000 * ${GTSAM_VERSION_MAJOR} + 100 * ${GTSAM_VERSION_MINOR} + ${GTSAM_VERSION_PATCH}")

if (${GTSAM_VERSION_PATCH} EQUAL 0)
Expand Down
8 changes: 4 additions & 4 deletions gtsam/discrete/DecisionTreeFactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace gtsam {
/** Default constructor for I/O */
DecisionTreeFactor();

/** Constructor from Indices, Ordering, and AlgebraicDecisionDiagram */
/** Constructor from DiscreteKeys and AlgebraicDecisionTree */
DecisionTreeFactor(const DiscreteKeys& keys, const ADT& potentials);

/** Constructor from doubles */
Expand Down Expand Up @@ -139,22 +139,22 @@ namespace gtsam {
/**
* Apply binary operator (*this) "op" f
* @param f the second argument for op
* @param op a binary operator that operates on AlgebraicDecisionDiagram potentials
* @param op a binary operator that operates on AlgebraicDecisionTree
*/
DecisionTreeFactor apply(const DecisionTreeFactor& f, ADT::Binary op) const;

/**
* Combine frontal variables using binary operator "op"
* @param nrFrontals nr. of frontal to combine variables in this factor
* @param op a binary operator that operates on AlgebraicDecisionDiagram potentials
* @param op a binary operator that operates on AlgebraicDecisionTree
* @return shared pointer to newly created DecisionTreeFactor
*/
shared_ptr combine(size_t nrFrontals, ADT::Binary op) const;

/**
* Combine frontal variables in an Ordering using binary operator "op"
* @param nrFrontals nr. of frontal to combine variables in this factor
* @param op a binary operator that operates on AlgebraicDecisionDiagram potentials
* @param op a binary operator that operates on AlgebraicDecisionTree
* @return shared pointer to newly created DecisionTreeFactor
*/
shared_ptr combine(const Ordering& keys, ADT::Binary op) const;
Expand Down
6 changes: 3 additions & 3 deletions gtsam/discrete/DiscreteBayesNet.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#pragma once

#include <gtsam/discrete/DiscreteConditional.h>
#include <gtsam/discrete/DiscretePrior.h>
#include <gtsam/discrete/DiscreteDistribution.h>
#include <gtsam/inference/BayesNet.h>
#include <gtsam/inference/FactorGraph.h>

Expand Down Expand Up @@ -79,9 +79,9 @@ namespace gtsam {
// Add inherited versions of add.
using Base::add;

/** Add a DiscretePrior using a table or a string */
/** Add a DiscreteDistribution using a table or a string */
void add(const DiscreteKey& key, const std::string& spec) {
emplace_shared<DiscretePrior>(key, spec);
emplace_shared<DiscreteDistribution>(key, spec);
}

/** Add a DiscreteCondtional */
Expand Down
98 changes: 79 additions & 19 deletions gtsam/discrete/DiscreteConditional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <string>
#include <vector>
#include <utility>
#include <set>

using namespace std;
using std::stringstream;
Expand All @@ -38,38 +39,97 @@ using std::pair;
namespace gtsam {

// Instantiate base class
template class GTSAM_EXPORT Conditional<DecisionTreeFactor, DiscreteConditional> ;
template class GTSAM_EXPORT
Conditional<DecisionTreeFactor, DiscreteConditional>;

/* ******************************************************************************** */
/* ************************************************************************** */
DiscreteConditional::DiscreteConditional(const size_t nrFrontals,
const DecisionTreeFactor& f) :
BaseFactor(f / (*f.sum(nrFrontals))), BaseConditional(nrFrontals) {
}
const DecisionTreeFactor& f)
: BaseFactor(f / (*f.sum(nrFrontals))), BaseConditional(nrFrontals) {}

/* ******************************************************************************** */
/* ************************************************************************** */
DiscreteConditional::DiscreteConditional(size_t nrFrontals,
const DiscreteKeys& keys,
const ADT& potentials)
: BaseFactor(keys, potentials), BaseConditional(nrFrontals) {}

/* ************************************************************************** */
DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal) :
BaseFactor(
ISDEBUG("DiscreteConditional::COUNT") ? joint : joint / marginal), BaseConditional(
joint.size()-marginal.size()) {
if (ISDEBUG("DiscreteConditional::DiscreteConditional"))
cout << (firstFrontalKey()) << endl; //TODO Print all keys
}
const DecisionTreeFactor& marginal)
: BaseFactor(joint / marginal),
BaseConditional(joint.size() - marginal.size()) {}

/* ******************************************************************************** */
/* ************************************************************************** */
DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal, const Ordering& orderedKeys) :
DiscreteConditional(joint, marginal) {
const DecisionTreeFactor& marginal,
const Ordering& orderedKeys)
: DiscreteConditional(joint, marginal) {
keys_.clear();
keys_.insert(keys_.end(), orderedKeys.begin(), orderedKeys.end());
}

/* ******************************************************************************** */
/* ************************************************************************** */
DiscreteConditional::DiscreteConditional(const Signature& signature)
: BaseFactor(signature.discreteKeys(), signature.cpt()),
BaseConditional(1) {}

/* ******************************************************************************** */
/* ************************************************************************** */
DiscreteConditional DiscreteConditional::operator*(
const DiscreteConditional& other) const {
// Take union of frontal keys
std::set<Key> newFrontals;
for (auto&& key : this->frontals()) newFrontals.insert(key);
for (auto&& key : other.frontals()) newFrontals.insert(key);

// Check if frontals overlapped
if (nrFrontals() + other.nrFrontals() > newFrontals.size())
throw std::invalid_argument(
"DiscreteConditional::operator* called with overlapping frontal keys.");

// Now, add cardinalities.
DiscreteKeys discreteKeys;
for (auto&& key : frontals())
discreteKeys.emplace_back(key, cardinality(key));
for (auto&& key : other.frontals())
discreteKeys.emplace_back(key, other.cardinality(key));

// Sort
std::sort(discreteKeys.begin(), discreteKeys.end());

// Add parents to set, to make them unique
std::set<DiscreteKey> parents;
for (auto&& key : this->parents())
if (!newFrontals.count(key)) parents.emplace(key, cardinality(key));
for (auto&& key : other.parents())
if (!newFrontals.count(key)) parents.emplace(key, other.cardinality(key));

// Finally, add parents to keys, in order
for (auto&& dk : parents) discreteKeys.push_back(dk);

ADT product = ADT::apply(other, ADT::Ring::mul);
return DiscreteConditional(newFrontals.size(), discreteKeys, product);
}

/* ************************************************************************** */
DiscreteConditional DiscreteConditional::marginal(Key key) const {
if (nrParents() > 0)
throw std::invalid_argument(
"DiscreteConditional::marginal: single argument version only valid for "
"fully specified joint distributions (i.e., no parents).");

// Calculate the keys as the frontal keys without the given key.
DiscreteKeys discreteKeys{{key, cardinality(key)}};

// Calculate sum
ADT adt(*this);
for (auto&& k : frontals())
if (k != key) adt = adt.sum(k, cardinality(k));

// Return new factor
return DiscreteConditional(1, discreteKeys, adt);
}

/* ************************************************************************** */
void DiscreteConditional::print(const string& s,
const KeyFormatter& formatter) const {
cout << s << " P( ";
Expand All @@ -82,7 +142,7 @@ void DiscreteConditional::print(const string& s,
cout << formatter(*it) << " ";
}
}
cout << ")";
cout << "):\n";
ADT::print("");
cout << endl;
}
Expand Down
79 changes: 38 additions & 41 deletions gtsam/discrete/DiscreteConditional.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,21 @@ class GTSAM_EXPORT DiscreteConditional
/// @name Standard Constructors
/// @{

/** default constructor needed for serialization */
/// Default constructor needed for serialization.
DiscreteConditional() {}

/** constructor from factor */
/// Construct from factor, taking the first `nFrontals` keys as frontals.
DiscreteConditional(size_t nFrontals, const DecisionTreeFactor& f);

/**
* Construct from DiscreteKeys and AlgebraicDecisionTree, taking the first
* `nFrontals` keys as frontals, in the order given.
*/
DiscreteConditional(size_t nFrontals, const DiscreteKeys& keys,
const ADT& potentials);

/** Construct from signature */
DiscreteConditional(const Signature& signature);
explicit DiscreteConditional(const Signature& signature);

/**
* Construct from key, parents, and a Signature::Table specifying the
Expand All @@ -82,31 +89,45 @@ class GTSAM_EXPORT DiscreteConditional
const std::string& spec)
: DiscreteConditional(Signature(key, parents, spec)) {}

/// No-parent specialization; can also use DiscretePrior.
/// No-parent specialization; can also use DiscreteDistribution.
DiscreteConditional(const DiscreteKey& key, const std::string& spec)
: DiscreteConditional(Signature(key, {}, spec)) {}

/** construct P(X|Y)=P(X,Y)/P(Y) from P(X,Y) and P(Y) */
/**
* @brief construct P(X|Y) = f(X,Y)/f(Y) from f(X,Y) and f(Y)
* Assumes but *does not check* that f(Y)=sum_X f(X,Y).
*/
DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal);

/** construct P(X|Y)=P(X,Y)/P(Y) from P(X,Y) and P(Y) */
/**
* @brief construct P(X|Y) = f(X,Y)/f(Y) from f(X,Y) and f(Y)
* Assumes but *does not check* that f(Y)=sum_X f(X,Y).
* Makes sure the keys are ordered as given. Does not check orderedKeys.
*/
DiscreteConditional(const DecisionTreeFactor& joint,
const DecisionTreeFactor& marginal,
const Ordering& orderedKeys);

/**
* Combine several conditional into a single one.
* The conditionals must be given in increasing order, meaning that the
* parents of any conditional may not include a conditional coming before it.
* @param firstConditional Iterator to the first conditional to combine, must
* dereference to a shared_ptr<DiscreteConditional>.
* @param lastConditional Iterator to after the last conditional to combine,
* must dereference to a shared_ptr<DiscreteConditional>.
* */
template <typename ITERATOR>
static shared_ptr Combine(ITERATOR firstConditional,
ITERATOR lastConditional);
* @brief Combine two conditionals, yielding a new conditional with the union
* of the frontal keys, ordered by gtsam::Key.
*
* The two conditionals must make a valid Bayes net fragment, i.e.,
* the frontal variables cannot overlap, and must be acyclic:
* Example of correct use:
* P(A,B) = P(A|B) * P(B)
* P(A,B|C) = P(A|B) * P(B|C)
* P(A,B,C) = P(A,B|C) * P(C)
* Example of incorrect use:
* P(A|B) * P(A|C) = ?
* P(A|B) * P(B|A) = ?
* We check for overlapping frontals, but do *not* check for cyclic.
*/
DiscreteConditional operator*(const DiscreteConditional& other) const;

/** Calculate marginal on given key, no parent case. */
DiscreteConditional marginal(Key key) const;

/// @}
/// @name Testable
Expand Down Expand Up @@ -136,11 +157,6 @@ class GTSAM_EXPORT DiscreteConditional
return ADT::operator()(values);
}

/** Convert to a factor */
DecisionTreeFactor::shared_ptr toFactor() const {
return DecisionTreeFactor::shared_ptr(new DecisionTreeFactor(*this));
}

/** Restrict to given parent values, returns DecisionTreeFactor */
DecisionTreeFactor::shared_ptr choose(
const DiscreteValues& parentsValues) const;
Expand Down Expand Up @@ -208,23 +224,4 @@ class GTSAM_EXPORT DiscreteConditional
template <>
struct traits<DiscreteConditional> : public Testable<DiscreteConditional> {};

/* ************************************************************************* */
template <typename ITERATOR>
DiscreteConditional::shared_ptr DiscreteConditional::Combine(
ITERATOR firstConditional, ITERATOR lastConditional) {
// TODO: check for being a clique

// multiply all the potentials of the given conditionals
size_t nrFrontals = 0;
DecisionTreeFactor product;
for (ITERATOR it = firstConditional; it != lastConditional;
++it, ++nrFrontals) {
DiscreteConditional::shared_ptr c = *it;
DecisionTreeFactor::shared_ptr factor = c->toFactor();
product = (*factor) * product;
}
// and then create a new multi-frontal conditional
return boost::make_shared<DiscreteConditional>(nrFrontals, product);
}

} // namespace gtsam
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,23 @@
* -------------------------------------------------------------------------- */

/**
* @file DiscretePrior.cpp
* @file DiscreteDistribution.cpp
* @date December 2021
* @author Frank Dellaert
*/

#include <gtsam/discrete/DiscretePrior.h>
#include <gtsam/discrete/DiscreteDistribution.h>

#include <vector>

namespace gtsam {

void DiscretePrior::print(const std::string& s,
const KeyFormatter& formatter) const {
void DiscreteDistribution::print(const std::string& s,
const KeyFormatter& formatter) const {
Base::print(s, formatter);
}

double DiscretePrior::operator()(size_t value) const {
double DiscreteDistribution::operator()(size_t value) const {
if (nrFrontals() != 1)
throw std::invalid_argument(
"Single value operator can only be invoked on single-variable "
Expand All @@ -34,10 +36,10 @@ double DiscretePrior::operator()(size_t value) const {
return Base::operator()(values);
}

std::vector<double> DiscretePrior::pmf() const {
std::vector<double> DiscreteDistribution::pmf() const {
if (nrFrontals() != 1)
throw std::invalid_argument(
"DiscretePrior::pmf only defined for single-variable priors");
"DiscreteDistribution::pmf only defined for single-variable priors");
const size_t nrValues = cardinalities_.at(keys_[0]);
std::vector<double> array;
array.reserve(nrValues);
Expand Down
Loading

0 comments on commit 76c7419

Please sign in to comment.