2014-12-06 17:17:35 +08:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
* 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
|
|
|
|
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
2014-12-06 17:58:16 +08:00
|
|
|
* @file Cyclic.h
|
2014-12-06 18:17:54 +08:00
|
|
|
* @brief Cyclic group, i.e., the integers modulo N
|
2014-12-06 17:17:35 +08:00
|
|
|
* @author Frank Dellaert
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <gtsam/base/concepts.h>
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
|
|
namespace gtsam {
|
|
|
|
|
|
|
|
template<size_t N>
|
|
|
|
class Cyclic {
|
2014-12-06 17:58:16 +08:00
|
|
|
size_t i_; ///< we just use an unsigned int
|
2014-12-06 17:17:35 +08:00
|
|
|
public:
|
2014-12-06 17:58:16 +08:00
|
|
|
/// Constructor
|
2014-12-06 17:17:35 +08:00
|
|
|
Cyclic(size_t i) :
|
|
|
|
i_(i) {
|
|
|
|
}
|
2014-12-06 17:58:16 +08:00
|
|
|
/// Cast to size_t
|
|
|
|
operator size_t() const {
|
|
|
|
return i_;
|
|
|
|
}
|
2014-12-06 19:50:40 +08:00
|
|
|
/// Addition modulo N
|
|
|
|
Cyclic operator+(const Cyclic& h) const {
|
|
|
|
return (i_+h.i_) % N;
|
|
|
|
}
|
2014-12-06 19:59:35 +08:00
|
|
|
/// Subtraction modulo N
|
|
|
|
Cyclic operator-(const Cyclic& h) const {
|
|
|
|
return (N+i_-h.i_) % N;
|
|
|
|
}
|
|
|
|
/// Inverse
|
|
|
|
Cyclic operator-() const {
|
|
|
|
return (N-i_) % N;
|
|
|
|
}
|
2014-12-06 17:17:35 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace traits {
|
2014-12-06 18:37:14 +08:00
|
|
|
/// Define Cyclic to be a model of the Group concept
|
2014-12-06 18:17:54 +08:00
|
|
|
template<size_t N> struct structure_category<Cyclic<N> > {
|
|
|
|
typedef group_tag type;
|
|
|
|
};
|
2014-12-06 18:37:14 +08:00
|
|
|
} // \namespace traits
|
|
|
|
|
|
|
|
namespace group {
|
2014-12-06 19:50:40 +08:00
|
|
|
|
2014-12-06 18:37:14 +08:00
|
|
|
template<size_t N>
|
2014-12-06 19:50:40 +08:00
|
|
|
Cyclic<N> compose(const Cyclic<N>&g, const Cyclic<N>& h) {
|
|
|
|
return g + h;
|
|
|
|
}
|
2014-12-06 18:37:14 +08:00
|
|
|
|
2014-12-06 18:51:44 +08:00
|
|
|
template<size_t N>
|
2014-12-06 19:50:40 +08:00
|
|
|
Cyclic<N> between(const Cyclic<N>&g, const Cyclic<N>& h) {
|
|
|
|
return h - g;
|
|
|
|
}
|
2014-12-06 18:51:44 +08:00
|
|
|
|
|
|
|
template<size_t N>
|
2014-12-06 19:50:40 +08:00
|
|
|
Cyclic<N> inverse(const Cyclic<N>&g) {
|
|
|
|
return -g;
|
|
|
|
}
|
2014-12-06 18:51:44 +08:00
|
|
|
|
2014-12-06 18:37:14 +08:00
|
|
|
namespace traits {
|
|
|
|
/// Define the trait that specifies Cyclic's identity element
|
2014-12-06 17:17:35 +08:00
|
|
|
template<size_t N> struct identity<Cyclic<N> > {
|
2014-12-06 17:58:16 +08:00
|
|
|
static const Cyclic<N> value;
|
2014-12-06 17:17:35 +08:00
|
|
|
typedef Cyclic<N> value_type;
|
|
|
|
};
|
2014-12-06 18:37:14 +08:00
|
|
|
/// Define the trait that asserts Cyclic is an additive group
|
|
|
|
template<size_t N> struct flavor<Cyclic<N> > {
|
|
|
|
typedef additive_tag type;
|
2014-12-06 17:17:35 +08:00
|
|
|
};
|
|
|
|
} // \namespace traits
|
2014-12-06 18:37:14 +08:00
|
|
|
} // \namespace group
|
2014-12-06 17:17:35 +08:00
|
|
|
|
|
|
|
} // \namespace gtsam
|
|
|
|
|
2014-12-06 17:58:16 +08:00
|
|
|
/**
|
|
|
|
* @file Cyclic.cpp
|
|
|
|
* @brief Cyclic group implementation
|
|
|
|
* @author Frank Dellaert
|
|
|
|
**/
|
|
|
|
|
|
|
|
namespace gtsam {
|
|
|
|
|
2014-12-06 18:37:14 +08:00
|
|
|
namespace group {
|
2014-12-06 17:58:16 +08:00
|
|
|
namespace traits {
|
|
|
|
template<size_t N>
|
|
|
|
const Cyclic<N> identity<Cyclic<N> >::value = Cyclic<N>(0);
|
|
|
|
} // \namespace traits
|
2014-12-06 18:37:14 +08:00
|
|
|
} // \namespace group
|
2014-12-06 17:58:16 +08:00
|
|
|
|
|
|
|
} // \namespace gtsam
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file testCyclic.cpp
|
|
|
|
* @brief Unit tests for cyclic group
|
|
|
|
* @author Frank Dellaert
|
|
|
|
**/
|
|
|
|
|
2014-12-06 17:17:35 +08:00
|
|
|
//#include <gtsam/geometry/Cyclic.h>
|
|
|
|
#include <gtsam/base/Testable.h>
|
|
|
|
#include <CppUnitLite/TestHarness.h>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace gtsam;
|
|
|
|
|
2014-12-06 18:17:54 +08:00
|
|
|
typedef Cyclic<6> G; // Let's use the cyclic group of order 6
|
2014-12-06 17:58:16 +08:00
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
TEST(Cyclic, Concept) {
|
2014-12-06 18:17:54 +08:00
|
|
|
BOOST_CONCEPT_ASSERT((Group<G>));
|
2014-12-06 19:50:40 +08:00
|
|
|
EXPECT_LONGS_EQUAL(0, group::traits::identity<G>::value);
|
|
|
|
G g(2), h(3);
|
|
|
|
// EXPECT(Group<G>().check_invariants(g,h))
|
2014-12-06 17:58:16 +08:00
|
|
|
}
|
2014-12-06 17:17:35 +08:00
|
|
|
|
2014-12-06 17:58:16 +08:00
|
|
|
//******************************************************************************
|
2014-12-06 17:17:35 +08:00
|
|
|
TEST(Cyclic, Constructor) {
|
2014-12-06 17:58:16 +08:00
|
|
|
G g(0);
|
2014-12-06 17:17:35 +08:00
|
|
|
}
|
|
|
|
|
2014-12-06 19:50:40 +08:00
|
|
|
//******************************************************************************
|
|
|
|
TEST(Cyclic, Compose) {
|
2014-12-06 19:59:35 +08:00
|
|
|
EXPECT_LONGS_EQUAL(0, group::compose(G(0),G(0)));
|
|
|
|
EXPECT_LONGS_EQUAL(1, group::compose(G(0),G(1)));
|
|
|
|
EXPECT_LONGS_EQUAL(2, group::compose(G(0),G(2)));
|
|
|
|
EXPECT_LONGS_EQUAL(3, group::compose(G(0),G(3)));
|
|
|
|
EXPECT_LONGS_EQUAL(4, group::compose(G(0),G(4)));
|
|
|
|
EXPECT_LONGS_EQUAL(5, group::compose(G(0),G(5)));
|
|
|
|
|
|
|
|
EXPECT_LONGS_EQUAL(2, group::compose(G(2),G(0)));
|
|
|
|
EXPECT_LONGS_EQUAL(3, group::compose(G(2),G(1)));
|
|
|
|
EXPECT_LONGS_EQUAL(4, group::compose(G(2),G(2)));
|
|
|
|
EXPECT_LONGS_EQUAL(5, group::compose(G(2),G(3)));
|
|
|
|
EXPECT_LONGS_EQUAL(0, group::compose(G(2),G(4)));
|
|
|
|
EXPECT_LONGS_EQUAL(1, group::compose(G(2),G(5)));
|
2014-12-06 19:50:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
TEST(Cyclic, Between) {
|
2014-12-06 19:59:35 +08:00
|
|
|
EXPECT_LONGS_EQUAL(0, group::between(G(0),G(0)));
|
|
|
|
EXPECT_LONGS_EQUAL(1, group::between(G(0),G(1)));
|
|
|
|
EXPECT_LONGS_EQUAL(2, group::between(G(0),G(2)));
|
|
|
|
EXPECT_LONGS_EQUAL(3, group::between(G(0),G(3)));
|
|
|
|
EXPECT_LONGS_EQUAL(4, group::between(G(0),G(4)));
|
|
|
|
EXPECT_LONGS_EQUAL(5, group::between(G(0),G(5)));
|
|
|
|
|
|
|
|
EXPECT_LONGS_EQUAL(4, group::between(G(2),G(0)));
|
|
|
|
EXPECT_LONGS_EQUAL(5, group::between(G(2),G(1)));
|
|
|
|
EXPECT_LONGS_EQUAL(0, group::between(G(2),G(2)));
|
|
|
|
EXPECT_LONGS_EQUAL(1, group::between(G(2),G(3)));
|
|
|
|
EXPECT_LONGS_EQUAL(2, group::between(G(2),G(4)));
|
|
|
|
EXPECT_LONGS_EQUAL(3, group::between(G(2),G(5)));
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
TEST(Cyclic, Ivnverse) {
|
|
|
|
EXPECT_LONGS_EQUAL(0, group::inverse(G(0)));
|
|
|
|
EXPECT_LONGS_EQUAL(5, group::inverse(G(1)));
|
|
|
|
EXPECT_LONGS_EQUAL(4, group::inverse(G(2)));
|
|
|
|
EXPECT_LONGS_EQUAL(3, group::inverse(G(3)));
|
|
|
|
EXPECT_LONGS_EQUAL(2, group::inverse(G(4)));
|
|
|
|
EXPECT_LONGS_EQUAL(1, group::inverse(G(5)));
|
2014-12-06 19:50:40 +08:00
|
|
|
}
|
|
|
|
|
2014-12-06 17:58:16 +08:00
|
|
|
//******************************************************************************
|
2014-12-06 17:17:35 +08:00
|
|
|
int main() {
|
2014-12-06 17:58:16 +08:00
|
|
|
TestResult tr;
|
|
|
|
return TestRegistry::runAllTests(tr);
|
2014-12-06 17:17:35 +08:00
|
|
|
}
|
2014-12-06 17:58:16 +08:00
|
|
|
//******************************************************************************
|
2014-12-06 17:17:35 +08:00
|
|
|
|