/* ---------------------------------------------------------------------------- * GTSAM Copyright 2010, Georgia Tech Research Corporation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) * See LICENSE for the license information * -------------------------------------------------------------------------- */ /** * @file Group.h * * @brief Concept check class for variable types with Group properties * @date November, 2011 * @author Alex Cunningham * @author Frank Dellaert */ #pragma once #include #include #include #include #include #include namespace gtsam { /// tag to assert a type is a group struct group_tag {}; /// Group operator syntax flavors struct multiplicative_group_tag {}; struct additive_group_tag {}; template struct traits; /** * Group Concept */ template class IsGroup { public: typedef typename traits::structure_category structure_category_tag; typedef typename traits::group_flavor flavor_tag; //typedef typename traits::identity::value_type identity_value_type; BOOST_CONCEPT_USAGE(IsGroup) { BOOST_STATIC_ASSERT_MSG( (boost::is_base_of::value), "This type's structure_category trait does not assert it as a group (or derived)"); e = traits::Identity(); e = traits::Compose(g, h); e = traits::Between(g, h); e = traits::Inverse(g); operator_usage(flavor); // todo: how do we test the act concept? or do we even need to? } private: void operator_usage(multiplicative_group_tag) { e = g * h; //e = -g; // todo this should work, but it is failing for Quaternions } void operator_usage(additive_group_tag) { e = g + h; e = h - g; e = -g; } flavor_tag flavor; G e, g, h; bool b; }; /// Check invariants template BOOST_CONCEPT_REQUIRES(((IsGroup)),(bool)) // check_group_invariants(const G& a, const G& b, double tol = 1e-9) { G e = traits::Identity(); return traits::Equals(traits::Compose(a, traits::Inverse(a)), e, tol) && traits::Equals(traits::Between(a, b), traits::Compose(traits::Inverse(a), b), tol) && traits::Equals(traits::Compose(a, traits::Between(a, b)), b, tol); } namespace internal { /// A helper class that implements the traits interface for multiplicative groups. /// Assumes existence of identity, operator* and inverse method template struct MultiplicativeGroupTraits { typedef group_tag structure_category; typedef multiplicative_group_tag group_flavor; static Class Identity() { return Class::identity(); } static Class Compose(const Class &g, const Class & h) { return g * h;} static Class Between(const Class &g, const Class & h) { return g.inverse() * h;} static Class Inverse(const Class &g) { return g.inverse();} }; /// Both multiplicative group traits and Testable template struct MultiplicativeGroup : MultiplicativeGroupTraits, Testable {}; /// A helper class that implements the traits interface for additive groups. /// Assumes existence of identity and three additive operators template struct AdditiveGroupTraits { typedef group_tag structure_category; typedef additive_group_tag group_flavor; static Class Identity() { return Class::identity(); } static Class Compose(const Class &g, const Class & h) { return g + h;} static Class Between(const Class &g, const Class & h) { return h - g;} static Class Inverse(const Class &g) { return -g;} }; /// Both additive group traits and Testable template struct AdditiveGroup : AdditiveGroupTraits, Testable {}; } // namespace internal /// compose multiple times template BOOST_CONCEPT_REQUIRES(((IsGroup)),(G)) // compose_pow(const G& g, size_t n) { if (n == 0) return traits::Identity(); else if (n == 1) return g; else return traits::Compose(compose_pow(g, n - 1), g); } /// Template to construct the direct product of two arbitrary groups /// Assumes nothing except group structure and Testable from G and H template class DirectProduct: public std::pair { BOOST_CONCEPT_ASSERT((IsGroup)); BOOST_CONCEPT_ASSERT((IsGroup)); public: /// Default constructor yields identity DirectProduct():std::pair(traits::Identity(),traits::Identity()) {} // Construct from two subgroup elements DirectProduct(const G& g, const H& h):std::pair(g,h) {} // identity static DirectProduct identity() { return DirectProduct(); } DirectProduct operator*(const DirectProduct& other) const { return DirectProduct(traits::Compose(this->first, other.first), traits::Compose(this->second, other.second)); } DirectProduct inverse() const { return DirectProduct(this->first.inverse(), this->second.inverse()); } }; // Define any direct product group to be a model of the multiplicative Group concept template struct traits > : internal::MultiplicativeGroupTraits > {}; /// Template to construct the direct sum of two additive groups /// Assumes existence of three additive operators for both groups template class DirectSum: public std::pair { BOOST_CONCEPT_ASSERT((IsGroup)); // TODO(frank): check additive BOOST_CONCEPT_ASSERT((IsGroup)); // TODO(frank): check additive const G& g() const { return this->first; } const H& h() const { return this->second;} public: /// Default constructor yields identity DirectSum():std::pair(traits::Identity(),traits::Identity()) {} // Construct from two subgroup elements DirectSum(const G& g, const H& h):std::pair(g,h) {} // identity static DirectSum identity() { return DirectSum(); } DirectSum operator+(const DirectSum& other) const { return DirectSum(g()+other.g(), h()+other.h()); } DirectSum operator-(const DirectSum& other) const { return DirectSum(g()-other.g(), h()-other.h()); } DirectSum operator-() const { return DirectSum(- g(), - h()); } }; // Define direct sums to be a model of the Additive Group concept template struct traits > : internal::AdditiveGroupTraits > {}; } // namespace gtsam /** * Macros for using the IsGroup * - An instantiation for use inside unit tests * - A typedef for use inside generic algorithms * * NOTE: intentionally not in the gtsam namespace to allow for classes not in * the gtsam namespace to be more easily enforced as testable */ #define GTSAM_CONCEPT_GROUP_INST(T) template class gtsam::IsGroup; #define GTSAM_CONCEPT_GROUP_TYPE(T) typedef gtsam::IsGroup _gtsam_IsGroup_##T;