Skip to content

Commit

Permalink
merge in develop with #1930 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
dellaert committed Dec 16, 2024
2 parents e32ddd6 + bb7b6b3 commit 63982b1
Show file tree
Hide file tree
Showing 51 changed files with 406 additions and 323 deletions.
2 changes: 1 addition & 1 deletion GTSAM-Concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ In GTSAM, all properties and operations needed to use a type must be defined thr
In detail, we ask that the following items are defined in the traits object (although, not all are needed for optimization):

* values:
* `enum { dimension = D};`, an enum that indicates the dimensionality *n* of the manifold. In Eigen-fashion, we also support manifolds whose dimensionality is only defined at runtime, by specifying the value -1.
* `inline constexpr static auto dimension = D;`, a constexpr that indicates the dimensionality *n* of the manifold. In Eigen-fashion, we also support manifolds whose dimensionality is only defined at runtime, by specifying the value -1.
* types:
* `TangentVector`, type that lives in tangent space. This will almost always be an `Eigen::Matrix<double,n,1>`.
* `ChartJacobian`, a typedef for `OptionalJacobian<dimension, dimension>`.
Expand Down
3 changes: 1 addition & 2 deletions gtsam/base/GenericValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,8 @@ class GenericValue: public Value {
}
#endif


// Alignment, see https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html
enum { NeedsToAlign = (sizeof(T) % 16) == 0 };
constexpr static const bool NeedsToAlign = (sizeof(T) % 16) == 0;
public:
GTSAM_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
};
Expand Down
4 changes: 2 additions & 2 deletions gtsam/base/Lie.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace gtsam {
template <class Class, int N>
struct LieGroup {

enum { dimension = N };
inline constexpr static auto dimension = N;
typedef OptionalJacobian<N, N> ChartJacobian;
typedef Eigen::Matrix<double, N, N> Jacobian;
typedef Eigen::Matrix<double, N, 1> TangentVector;
Expand Down Expand Up @@ -183,7 +183,7 @@ struct LieGroupTraits: GetDimensionImpl<Class, Class::dimension> {
/// @name Manifold
/// @{
typedef Class ManifoldType;
enum { dimension = Class::dimension };
inline constexpr static auto dimension = Class::dimension;
typedef Eigen::Matrix<double, dimension, 1> TangentVector;
typedef OptionalJacobian<dimension, dimension> ChartJacobian;

Expand Down
4 changes: 2 additions & 2 deletions gtsam/base/Manifold.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ namespace internal {
template<class Class>
struct HasManifoldPrereqs {

enum { dim = Class::dimension };
inline constexpr static auto dim = Class::dimension;

Class p, q;
Eigen::Matrix<double, dim, 1> v;
Expand Down Expand Up @@ -95,7 +95,7 @@ struct ManifoldTraits: GetDimensionImpl<Class, Class::dimension> {
GTSAM_CONCEPT_ASSERT(HasManifoldPrereqs<Class>);

// Dimension of the manifold
enum { dimension = Class::dimension };
inline constexpr static auto dimension = Class::dimension;

// Typedefs required by all manifold types.
typedef Class ManifoldType;
Expand Down
2 changes: 1 addition & 1 deletion gtsam/base/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ struct MultiplyWithInverse {
*/
template <typename T, int N>
struct MultiplyWithInverseFunction {
enum { M = traits<T>::dimension };
inline constexpr static auto M = traits<T>::dimension;
typedef Eigen::Matrix<double, N, 1> VectorN;
typedef Eigen::Matrix<double, N, N> MatrixN;

Expand Down
10 changes: 5 additions & 5 deletions gtsam/base/ProductLieGroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class ProductLieGroup: public std::pair<G, H> {
typedef std::pair<G, H> Base;

protected:
enum {dimension1 = traits<G>::dimension};
enum {dimension2 = traits<H>::dimension};
constexpr static const size_t dimension1 = traits<G>::dimension;
constexpr static const size_t dimension2 = traits<H>::dimension;

public:
/// Default constructor yields identity
Expand Down Expand Up @@ -67,9 +67,9 @@ class ProductLieGroup: public std::pair<G, H> {

/// @name Manifold
/// @{
enum {dimension = dimension1 + dimension2};
inline static size_t Dim() {return dimension;}
inline size_t dim() const {return dimension;}
inline constexpr static auto dimension = dimension1 + dimension2;
inline static size_t Dim() { return dimension; }
inline size_t dim() const { return dimension; }

typedef Eigen::Matrix<double, dimension, 1> TangentVector;
typedef OptionalJacobian<dimension, dimension> ChartJacobian;
Expand Down
10 changes: 5 additions & 5 deletions gtsam/base/VectorSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ struct VectorSpaceImpl<Class,Eigen::Dynamic> {
template<class Class>
struct HasVectorSpacePrereqs {

enum { dim = Class::dimension };
inline constexpr static auto dim = Class::dimension;

Class p, q;
Vector v;
Expand Down Expand Up @@ -197,7 +197,7 @@ GTSAM_CONCEPT_ASSERT(HasVectorSpacePrereqs<Class>);

/// @name Manifold
/// @{
enum { dimension = Class::dimension};
inline constexpr static auto dimension = Class::dimension;
typedef Class ManifoldType;
/// @}
};
Expand Down Expand Up @@ -232,7 +232,7 @@ struct ScalarTraits : VectorSpaceImpl<Scalar, 1> {
/// @name Manifold
/// @{
typedef Scalar ManifoldType;
enum { dimension = 1 };
inline constexpr static auto dimension = 1;
typedef Eigen::Matrix<double, 1, 1> TangentVector;
typedef OptionalJacobian<1, 1> ChartJacobian;

Expand Down Expand Up @@ -305,7 +305,7 @@ struct traits<Eigen::Matrix<double, M, N, Options, MaxRows, MaxCols> > :

/// @name Manifold
/// @{
enum { dimension = M*N};
inline constexpr static auto dimension = M * N;
typedef Fixed ManifoldType;
typedef Eigen::Matrix<double, dimension, 1> TangentVector;
typedef Eigen::Matrix<double, dimension, dimension> Jacobian;
Expand Down Expand Up @@ -377,7 +377,7 @@ struct DynamicTraits {

/// @name Manifold
/// @{
enum { dimension = Eigen::Dynamic };
inline constexpr static auto dimension = Eigen::Dynamic;
typedef Eigen::VectorXd TangentVector;
typedef Eigen::MatrixXd Jacobian;
typedef OptionalJacobian<dimension, dimension> ChartJacobian;
Expand Down
2 changes: 1 addition & 1 deletion gtsam/basis/Basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ class Basis {
*/
template <class T>
class ManifoldEvaluationFunctor : public VectorEvaluationFunctor {
enum { M = traits<T>::dimension };
inline constexpr static auto M = traits<T>::dimension;
using Base = VectorEvaluationFunctor;

public:
Expand Down
2 changes: 1 addition & 1 deletion gtsam/discrete/DecisionTreeFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace gtsam {
return false;
} else {
const auto& f(static_cast<const DecisionTreeFactor&>(other));
return ADT::equals(f, tol);
return Base::equals(other, tol) && ADT::equals(f, tol);
}
}

Expand Down
5 changes: 5 additions & 0 deletions gtsam/discrete/DiscreteFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ using namespace std;

namespace gtsam {

/* ************************************************************************* */
bool DiscreteFactor::equals(const DiscreteFactor& lf, double tol) const {
return Base::equals(lf, tol) && cardinalities_ == lf.cardinalities_;
}

/* ************************************************************************ */
DiscreteKeys DiscreteFactor::discreteKeys() const {
DiscreteKeys result;
Expand Down
2 changes: 1 addition & 1 deletion gtsam/discrete/DiscreteFactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class GTSAM_EXPORT DiscreteFactor : public Factor {
/// @{

/// equals
virtual bool equals(const DiscreteFactor& lf, double tol = 1e-9) const = 0;
virtual bool equals(const DiscreteFactor& lf, double tol = 1e-9) const;

/// print
void print(
Expand Down
119 changes: 98 additions & 21 deletions gtsam/discrete/TableFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,43 +62,117 @@ TableFactor::TableFactor(const DiscreteKeys& dkeys,
: TableFactor(dkeys, DecisionTreeFactor(dkeys, dtree)) {}

/**
* @brief Compute the correct ordering of the leaves in the decision tree.
* @brief Compute the indexing of the leaves in the decision tree based on the
* assignment and add the (index, leaf) pair to a SparseVector.
*
* This is done by first taking all the values which have modulo 0 value with
* the cardinality of the innermost key `n`, and we go up to modulo n.
* We visit each leaf in the tree, and using the cardinalities of the keys,
* compute the correct index to add the leaf to a SparseVector which
* is then used to create the TableFactor.
*
* @param dt The DecisionTree
* @return std::vector<double>
* @return Eigen::SparseVector<double>
*/
std::vector<double> ComputeLeafOrdering(const DiscreteKeys& dkeys,
const DecisionTreeFactor& dt) {
std::vector<double> probs = dt.probabilities();
std::vector<double> ordered;
static Eigen::SparseVector<double> ComputeSparseTable(
const DiscreteKeys& dkeys, const DecisionTreeFactor& dt) {
// SparseVector needs to know the maximum possible index,
// so we compute the product of cardinalities.
size_t cardinalityProduct = 1;
for (auto&& [_, c] : dt.cardinalities()) {
cardinalityProduct *= c;
}
Eigen::SparseVector<double> sparseTable(cardinalityProduct);
size_t nrValues = 0;
dt.visit([&nrValues](double x) {
if (x > 0) nrValues += 1;
});
sparseTable.reserve(nrValues);

std::set<Key> allKeys(dt.keys().begin(), dt.keys().end());

/**
* @brief Functor which is called by the DecisionTree for each leaf.
* For each leaf value, we use the corresponding assignment to compute a
* corresponding index into a SparseVector. We then populate sparseTable with
* the value at the computed index.
*
* Takes advantage of the sparsity of the DecisionTree to be efficient. When
* merged branches are encountered, we enumerate over the missing keys.
*
*/
auto op = [&](const Assignment<Key>& assignment, double p) {
if (p > 0) {
// Get all the keys involved in this assignment
std::set<Key> assignmentKeys;
for (auto&& [k, _] : assignment) {
assignmentKeys.insert(k);
}

size_t n = dkeys[0].second;
// Find the keys missing in the assignment
std::vector<Key> diff;
std::set_difference(allKeys.begin(), allKeys.end(),
assignmentKeys.begin(), assignmentKeys.end(),
std::back_inserter(diff));

for (size_t k = 0; k < n; ++k) {
for (size_t idx = 0; idx < probs.size(); ++idx) {
if (idx % n == k) {
ordered.push_back(probs[idx]);
// Generate all assignments using the missing keys
DiscreteKeys extras;
for (auto&& key : diff) {
extras.push_back({key, dt.cardinality(key)});
}
auto&& extraAssignments = DiscreteValues::CartesianProduct(extras);

for (auto&& extra : extraAssignments) {
// Create new assignment using the extra assignment
DiscreteValues updatedAssignment(assignment);
updatedAssignment.insert(extra);

// Generate index and add to the sparse vector.
Eigen::Index idx = 0;
size_t previousCardinality = 1;
// We go in reverse since a DecisionTree has the highest label first
for (auto&& it = updatedAssignment.rbegin();
it != updatedAssignment.rend(); it++) {
idx += previousCardinality * it->second;
previousCardinality *= dt.cardinality(it->first);
}
sparseTable.coeffRef(idx) = p;
}
}
}
return ordered;
};

// Visit each leaf in `dt` to get the Assignment and leaf value
// to populate the sparseTable.
dt.visitWith(op);

return sparseTable;
}

/* ************************************************************************ */
TableFactor::TableFactor(const DiscreteKeys& dkeys,
const DecisionTreeFactor& dtf)
: TableFactor(dkeys, ComputeLeafOrdering(dkeys, dtf)) {}
: TableFactor(dkeys, ComputeSparseTable(dkeys, dtf)) {}

/* ************************************************************************ */
TableFactor::TableFactor(const DecisionTreeFactor& dtf)
: TableFactor(dtf.discreteKeys(),
ComputeSparseTable(dtf.discreteKeys(), dtf)) {}

/* ************************************************************************ */
TableFactor::TableFactor(const DiscreteConditional& c)
: TableFactor(c.discreteKeys(), c) {}

/* ************************************************************************ */
Eigen::SparseVector<double> TableFactor::Convert(
const std::vector<double>& table) {
const DiscreteKeys& keys, const std::vector<double>& table) {
size_t max_size = 1;
for (auto&& [_, cardinality] : keys.cardinalities()) {
max_size *= cardinality;
}
if (table.size() != max_size) {
throw std::runtime_error(
"The cardinalities of the keys don't match the number of values in the "
"input.");
}

Eigen::SparseVector<double> sparse_table(table.size());
// Count number of nonzero elements in table and reserve the space.
const uint64_t nnz = std::count_if(table.begin(), table.end(),
Expand All @@ -113,13 +187,14 @@ Eigen::SparseVector<double> TableFactor::Convert(
}

/* ************************************************************************ */
Eigen::SparseVector<double> TableFactor::Convert(const std::string& table) {
Eigen::SparseVector<double> TableFactor::Convert(const DiscreteKeys& keys,
const std::string& table) {
// Convert string to doubles.
std::vector<double> ys;
std::istringstream iss(table);
std::copy(std::istream_iterator<double>(iss), std::istream_iterator<double>(),
std::back_inserter(ys));
return Convert(ys);
return Convert(keys, ys);
}

/* ************************************************************************ */
Expand All @@ -128,7 +203,8 @@ bool TableFactor::equals(const DiscreteFactor& other, double tol) const {
return false;
} else {
const auto& f(static_cast<const TableFactor&>(other));
return sparse_table_.isApprox(f.sparse_table_, tol);
return Base::equals(other, tol) &&
sparse_table_.isApprox(f.sparse_table_, tol);
}
}

Expand Down Expand Up @@ -250,7 +326,8 @@ void TableFactor::print(const string& s, const KeyFormatter& formatter) const {
for (auto&& kv : assignment) {
cout << "(" << formatter(kv.first) << ", " << kv.second << ")";
}
cout << " | " << it.value() << " | " << it.index() << endl;
cout << " | " << std::setw(10) << std::left << it.value() << " | "
<< it.index() << endl;
}
cout << "number of nnzs: " << sparse_table_.nonZeros() << endl;
}
Expand Down
17 changes: 11 additions & 6 deletions gtsam/discrete/TableFactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,16 @@ class GTSAM_EXPORT TableFactor : public DiscreteFactor {
return DiscreteKey(keys_[i], cardinalities_.at(keys_[i]));
}

/// Convert probability table given as doubles to SparseVector.
/// Example) {0, 1, 1, 0, 0, 1, 0} -> values: {1, 1, 1}, indices: {1, 2, 5}
static Eigen::SparseVector<double> Convert(const std::vector<double>& table);
/**
* Convert probability table given as doubles to SparseVector.
* Example: {0, 1, 1, 0, 0, 1, 0} -> values: {1, 1, 1}, indices: {1, 2, 5}
*/
static Eigen::SparseVector<double> Convert(const DiscreteKeys& keys,
const std::vector<double>& table);

/// Convert probability table given as string to SparseVector.
static Eigen::SparseVector<double> Convert(const std::string& table);
static Eigen::SparseVector<double> Convert(const DiscreteKeys& keys,
const std::string& table);

public:
// typedefs needed to play nice with gtsam
Expand All @@ -111,11 +115,11 @@ class GTSAM_EXPORT TableFactor : public DiscreteFactor {

/** Constructor from doubles */
TableFactor(const DiscreteKeys& keys, const std::vector<double>& table)
: TableFactor(keys, Convert(table)) {}
: TableFactor(keys, Convert(keys, table)) {}

/** Constructor from string */
TableFactor(const DiscreteKeys& keys, const std::string& table)
: TableFactor(keys, Convert(table)) {}
: TableFactor(keys, Convert(keys, table)) {}

/// Single-key specialization
template <class SOURCE>
Expand All @@ -128,6 +132,7 @@ class GTSAM_EXPORT TableFactor : public DiscreteFactor {

/// Constructor from DecisionTreeFactor
TableFactor(const DiscreteKeys& keys, const DecisionTreeFactor& dtf);
TableFactor(const DecisionTreeFactor& dtf);

/// Constructor from DecisionTree<Key, double>/AlgebraicDecisionTree
TableFactor(const DiscreteKeys& keys, const DecisionTree<Key, double>& dtree);
Expand Down
Loading

0 comments on commit 63982b1

Please sign in to comment.