mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Merged with default.
This commit is contained in:
@@ -4,6 +4,7 @@ set(Eigen_HEADERS
|
||||
ArpackSupport
|
||||
AutoDiff
|
||||
BVH
|
||||
EulerAngles
|
||||
FFT
|
||||
IterativeSolvers
|
||||
KroneckerProduct
|
||||
@@ -26,5 +27,6 @@ install(FILES
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(CXX11)
|
||||
install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel FILES_MATCHING PATTERN "*.h")
|
||||
|
||||
add_subdirectory(CXX11)
|
||||
|
||||
@@ -5,4 +5,4 @@ install(FILES
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11 COMPONENT Devel
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11 COMPONENT Devel FILES_MATCHING PATTERN "*.h")
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(ThreadPool)
|
||||
add_subdirectory(Tensor)
|
||||
add_subdirectory(TensorSymmetry)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_CXX11_Tensor_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_CXX11_Tensor_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11/src/Tensor COMPONENT Devel
|
||||
)
|
||||
@@ -191,6 +191,12 @@ class TensorBase<Derived, ReadOnlyAccessors>
|
||||
return unaryExpr(internal::scalar_log_op<Scalar>());
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_log1p_op<Scalar>, const Derived>
|
||||
log1p() const {
|
||||
return unaryExpr(internal::scalar_log1p_op<Scalar>());
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived>
|
||||
abs() const {
|
||||
|
||||
@@ -25,8 +25,9 @@ template<typename Dimensions, typename LhsXprType, typename RhsXprType>
|
||||
struct traits<TensorContractionOp<Dimensions, LhsXprType, RhsXprType> >
|
||||
{
|
||||
// Type promotion to handle the case where the types of the lhs and the rhs are different.
|
||||
typedef typename internal::promote_storage_type<typename LhsXprType::Scalar,
|
||||
typename RhsXprType::Scalar>::ret Scalar;
|
||||
typedef typename gebp_traits<typename remove_const<typename LhsXprType::Scalar>::type,
|
||||
typename remove_const<typename RhsXprType::Scalar>::type>::ResScalar Scalar;
|
||||
|
||||
typedef typename promote_storage_type<typename traits<LhsXprType>::StorageKind,
|
||||
typename traits<RhsXprType>::StorageKind>::ret StorageKind;
|
||||
typedef typename promote_index_type<typename traits<LhsXprType>::Index,
|
||||
@@ -75,8 +76,8 @@ class TensorContractionOp : public TensorBase<TensorContractionOp<Indices, LhsXp
|
||||
{
|
||||
public:
|
||||
typedef typename Eigen::internal::traits<TensorContractionOp>::Scalar Scalar;
|
||||
typedef typename internal::promote_storage_type<typename LhsXprType::CoeffReturnType,
|
||||
typename RhsXprType::CoeffReturnType>::ret CoeffReturnType;
|
||||
typedef typename internal::gebp_traits<typename LhsXprType::CoeffReturnType,
|
||||
typename RhsXprType::CoeffReturnType>::ResScalar CoeffReturnType;
|
||||
typedef typename Eigen::internal::nested<TensorContractionOp>::type Nested;
|
||||
typedef typename Eigen::internal::traits<TensorContractionOp>::StorageKind StorageKind;
|
||||
typedef typename Eigen::internal::traits<TensorContractionOp>::Index Index;
|
||||
|
||||
@@ -91,21 +91,21 @@ class TensorOpCost {
|
||||
}
|
||||
|
||||
// TODO(rmlarsen): Define min in terms of total cost, not elementwise.
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost& cwiseMin(
|
||||
const TensorOpCost& rhs) {
|
||||
bytes_loaded_ = numext::mini(bytes_loaded_, rhs.bytes_loaded());
|
||||
bytes_stored_ = numext::mini(bytes_stored_, rhs.bytes_stored());
|
||||
compute_cycles_ = numext::mini(compute_cycles_, rhs.compute_cycles());
|
||||
return *this;
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost cwiseMin(
|
||||
const TensorOpCost& rhs) const {
|
||||
double bytes_loaded = numext::mini(bytes_loaded_, rhs.bytes_loaded());
|
||||
double bytes_stored = numext::mini(bytes_stored_, rhs.bytes_stored());
|
||||
double compute_cycles = numext::mini(compute_cycles_, rhs.compute_cycles());
|
||||
return TensorOpCost(bytes_loaded, bytes_stored, compute_cycles);
|
||||
}
|
||||
|
||||
// TODO(rmlarsen): Define max in terms of total cost, not elementwise.
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost& cwiseMax(
|
||||
const TensorOpCost& rhs) {
|
||||
bytes_loaded_ = numext::maxi(bytes_loaded_, rhs.bytes_loaded());
|
||||
bytes_stored_ = numext::maxi(bytes_stored_, rhs.bytes_stored());
|
||||
compute_cycles_ = numext::maxi(compute_cycles_, rhs.compute_cycles());
|
||||
return *this;
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost cwiseMax(
|
||||
const TensorOpCost& rhs) const {
|
||||
double bytes_loaded = numext::maxi(bytes_loaded_, rhs.bytes_loaded());
|
||||
double bytes_stored = numext::maxi(bytes_stored_, rhs.bytes_stored());
|
||||
double compute_cycles = numext::maxi(compute_cycles_, rhs.compute_cycles());
|
||||
return TensorOpCost(bytes_loaded, bytes_stored, compute_cycles);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost& operator+=(
|
||||
|
||||
@@ -239,7 +239,7 @@ struct TensorEvaluator<const TensorCwiseNullaryOp<NullaryOp, ArgType>, Device>
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
TensorEvaluator(const XprType& op, const Device& device)
|
||||
: m_functor(op.functor()), m_argImpl(op.nestedExpression(), device)
|
||||
: m_functor(op.functor()), m_argImpl(op.nestedExpression(), device), m_wrapper()
|
||||
{ }
|
||||
|
||||
typedef typename XprType::Index Index;
|
||||
@@ -256,13 +256,13 @@ struct TensorEvaluator<const TensorCwiseNullaryOp<NullaryOp, ArgType>, Device>
|
||||
|
||||
EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const
|
||||
{
|
||||
return m_functor(index);
|
||||
return m_wrapper(m_functor, index);
|
||||
}
|
||||
|
||||
template<int LoadMode>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const
|
||||
{
|
||||
return m_functor.template packetOp<Index, PacketReturnType>(index);
|
||||
return m_wrapper.template packetOp<PacketReturnType, Index>(m_functor, index);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
|
||||
@@ -282,6 +282,7 @@ struct TensorEvaluator<const TensorCwiseNullaryOp<NullaryOp, ArgType>, Device>
|
||||
private:
|
||||
const NullaryOp m_functor;
|
||||
TensorEvaluator<ArgType, Device> m_argImpl;
|
||||
const internal::nullary_wrapper<CoeffReturnType,NullaryOp> m_wrapper;
|
||||
};
|
||||
|
||||
|
||||
@@ -612,7 +613,7 @@ struct TensorEvaluator<const TensorSelectOp<IfArgType, ThenArgType, ElseArgType>
|
||||
.cwiseMax(m_elseImpl.costPerCoeff(vectorized));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType* data() const { return NULL; }
|
||||
/// required by sycl in order to extract the accessor
|
||||
const TensorEvaluator<IfArgType, Device> & cond_impl() const { return m_condImpl; }
|
||||
/// required by sycl in order to extract the accessor
|
||||
|
||||
@@ -25,7 +25,7 @@ struct scalar_mod_op {
|
||||
};
|
||||
template <typename Scalar>
|
||||
struct functor_traits<scalar_mod_op<Scalar> >
|
||||
{ enum { Cost = NumTraits<Scalar>::template Div<false>::Cost, PacketAccess = false }; };
|
||||
{ enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
|
||||
|
||||
|
||||
/** \internal
|
||||
@@ -38,7 +38,7 @@ struct scalar_mod2_op {
|
||||
};
|
||||
template <typename Scalar>
|
||||
struct functor_traits<scalar_mod2_op<Scalar> >
|
||||
{ enum { Cost = NumTraits<Scalar>::template Div<false>::Cost, PacketAccess = false }; };
|
||||
{ enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
|
||||
|
||||
template <typename Scalar>
|
||||
struct scalar_fmod_op {
|
||||
@@ -188,6 +188,32 @@ struct reducer_traits<MeanReducer<T>, Device> {
|
||||
};
|
||||
|
||||
|
||||
template <typename T, bool IsMax = true, bool IsInteger = true>
|
||||
struct MinMaxBottomValue {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static T bottom_value() {
|
||||
return Eigen::NumTraits<T>::lowest();
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct MinMaxBottomValue<T, true, false> {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static T bottom_value() {
|
||||
return -Eigen::NumTraits<T>::infinity();
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct MinMaxBottomValue<T, false, true> {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static T bottom_value() {
|
||||
return Eigen::NumTraits<T>::highest();
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct MinMaxBottomValue<T, false, false> {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static T bottom_value() {
|
||||
return Eigen::NumTraits<T>::infinity();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T> struct MaxReducer
|
||||
{
|
||||
static const bool PacketAccess = packet_traits<T>::HasMax;
|
||||
@@ -200,9 +226,8 @@ template <typename T> struct MaxReducer
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
||||
(*accum) = pmax<Packet>(*accum, p);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
||||
return Eigen::NumTraits<T>::lowest();
|
||||
return MinMaxBottomValue<T, true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
||||
@@ -242,9 +267,8 @@ template <typename T> struct MinReducer
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
||||
(*accum) = pmin<Packet>(*accum, p);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
||||
return Eigen::NumTraits<T>::highest();
|
||||
return MinMaxBottomValue<T, false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
||||
@@ -454,12 +478,11 @@ template <typename T> class UniformRandomGenerator {
|
||||
m_deterministic = other.m_deterministic;
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
T operator()(Index) const {
|
||||
T operator()() const {
|
||||
return random<T>();
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
PacketType packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
PacketType packetOp() const {
|
||||
const int packetSize = internal::unpacket_traits<PacketType>::size;
|
||||
EIGEN_ALIGN_MAX T values[packetSize];
|
||||
for (int i = 0; i < packetSize; ++i) {
|
||||
@@ -484,23 +507,22 @@ template <> class UniformRandomGenerator<float> {
|
||||
}
|
||||
UniformRandomGenerator(const UniformRandomGenerator<float>& other) {
|
||||
m_generator = new std::mt19937();
|
||||
m_generator->seed(other(0) * UINT_MAX);
|
||||
m_generator->seed(other() * UINT_MAX);
|
||||
m_deterministic = other.m_deterministic;
|
||||
}
|
||||
~UniformRandomGenerator() {
|
||||
delete m_generator;
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
float operator()(Index) const {
|
||||
float operator()() const {
|
||||
return m_distribution(*m_generator);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
PacketType packetOp(Index i) const {
|
||||
template<typename PacketType>
|
||||
PacketType packetOp() const {
|
||||
const int packetSize = internal::unpacket_traits<PacketType>::size;
|
||||
EIGEN_ALIGN_MAX float values[packetSize];
|
||||
for (int k = 0; k < packetSize; ++k) {
|
||||
values[k] = this->operator()(i);
|
||||
values[k] = this->operator()();
|
||||
}
|
||||
return internal::pload<PacketType>(values);
|
||||
}
|
||||
@@ -525,23 +547,22 @@ template <> class UniformRandomGenerator<double> {
|
||||
}
|
||||
UniformRandomGenerator(const UniformRandomGenerator<double>& other) {
|
||||
m_generator = new std::mt19937();
|
||||
m_generator->seed(other(0) * UINT_MAX);
|
||||
m_generator->seed(other() * UINT_MAX);
|
||||
m_deterministic = other.m_deterministic;
|
||||
}
|
||||
~UniformRandomGenerator() {
|
||||
delete m_generator;
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
double operator()(Index) const {
|
||||
double operator()() const {
|
||||
return m_distribution(*m_generator);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
PacketType packetOp(Index i) const {
|
||||
template<typename PacketType>
|
||||
PacketType packetOp() const {
|
||||
const int packetSize = internal::unpacket_traits<PacketType>::size;
|
||||
EIGEN_ALIGN_MAX double values[packetSize];
|
||||
for (int k = 0; k < packetSize; ++k) {
|
||||
values[k] = this->operator()(i);
|
||||
values[k] = this->operator()();
|
||||
}
|
||||
return internal::pload<PacketType>(values);
|
||||
}
|
||||
@@ -578,12 +599,11 @@ template <> class UniformRandomGenerator<float> {
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
__device__ float operator()(Index) const {
|
||||
__device__ float operator()() const {
|
||||
return curand_uniform(&m_state);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
__device__ float4 packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
__device__ float4 packetOp() const {
|
||||
EIGEN_STATIC_ASSERT((is_same<PacketType, float4>::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
return curand_uniform4(&m_state);
|
||||
}
|
||||
@@ -608,12 +628,11 @@ template <> class UniformRandomGenerator<double> {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ double operator()(Index) const {
|
||||
__device__ double operator()() const {
|
||||
return curand_uniform_double(&m_state);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
__device__ double2 packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
__device__ double2 packetOp() const {
|
||||
EIGEN_STATIC_ASSERT((is_same<PacketType, double2>::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
return curand_uniform2_double(&m_state);
|
||||
}
|
||||
@@ -638,8 +657,7 @@ template <> class UniformRandomGenerator<std::complex<float> > {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ std::complex<float> operator()(Index) const {
|
||||
__device__ std::complex<float> operator()() const {
|
||||
float4 vals = curand_uniform4(&m_state);
|
||||
return std::complex<float>(vals.x, vals.y);
|
||||
}
|
||||
@@ -664,8 +682,7 @@ template <> class UniformRandomGenerator<std::complex<double> > {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ std::complex<double> operator()(Index) const {
|
||||
__device__ std::complex<double> operator()() const {
|
||||
double2 vals = curand_uniform2_double(&m_state);
|
||||
return std::complex<double>(vals.x, vals.y);
|
||||
}
|
||||
@@ -701,17 +718,16 @@ template <typename T> class NormalRandomGenerator {
|
||||
}
|
||||
NormalRandomGenerator(const NormalRandomGenerator& other)
|
||||
: m_deterministic(other.m_deterministic), m_distribution(other.m_distribution), m_generator(new std::mt19937()) {
|
||||
m_generator->seed(other(0) * UINT_MAX);
|
||||
m_generator->seed(other() * UINT_MAX);
|
||||
}
|
||||
~NormalRandomGenerator() {
|
||||
delete m_generator;
|
||||
}
|
||||
template<typename Index>
|
||||
T operator()(Index) const {
|
||||
T operator()() const {
|
||||
return m_distribution(*m_generator);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
PacketType packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
PacketType packetOp() const {
|
||||
const int packetSize = internal::unpacket_traits<PacketType>::size;
|
||||
EIGEN_ALIGN_MAX T values[packetSize];
|
||||
for (int i = 0; i < packetSize; ++i) {
|
||||
@@ -749,12 +765,11 @@ template <> class NormalRandomGenerator<float> {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ float operator()(Index) const {
|
||||
__device__ float operator()() const {
|
||||
return curand_normal(&m_state);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
__device__ float4 packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
__device__ float4 packetOp() const {
|
||||
EIGEN_STATIC_ASSERT((is_same<PacketType, float4>::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
return curand_normal4(&m_state);
|
||||
}
|
||||
@@ -779,12 +794,11 @@ template <> class NormalRandomGenerator<double> {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ double operator()(Index) const {
|
||||
__device__ double operator()() const {
|
||||
return curand_normal_double(&m_state);
|
||||
}
|
||||
template<typename Index, typename PacketType>
|
||||
__device__ double2 packetOp(Index) const {
|
||||
template<typename PacketType>
|
||||
__device__ double2 packetOp() const {
|
||||
EIGEN_STATIC_ASSERT((is_same<PacketType, double2>::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
return curand_normal2_double(&m_state);
|
||||
}
|
||||
@@ -809,8 +823,7 @@ template <> class NormalRandomGenerator<std::complex<float> > {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ std::complex<float> operator()(Index) const {
|
||||
__device__ std::complex<float> operator()() const {
|
||||
float4 vals = curand_normal4(&m_state);
|
||||
return std::complex<float>(vals.x, vals.y);
|
||||
}
|
||||
@@ -835,8 +848,7 @@ template <> class NormalRandomGenerator<std::complex<double> > {
|
||||
const int seed = m_deterministic ? 0 : get_random_seed();
|
||||
curand_init(seed, tid, 0, &m_state);
|
||||
}
|
||||
template<typename Index>
|
||||
__device__ std::complex<double> operator()(Index) const {
|
||||
__device__ std::complex<double> operator()() const {
|
||||
double2 vals = curand_normal2_double(&m_state);
|
||||
return std::complex<double>(vals.x, vals.y);
|
||||
}
|
||||
|
||||
@@ -505,9 +505,14 @@ struct TensorEvaluator<const TensorReductionOp<Op, Dims, ArgType>, Device>
|
||||
(reducing_inner_dims || ReducingInnerMostDims)) {
|
||||
const Index num_values_to_reduce = internal::array_prod(m_reducedDims);
|
||||
const Index num_coeffs_to_preserve = internal::array_prod(m_dimensions);
|
||||
if (!data && num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 128) {
|
||||
data = static_cast<CoeffReturnType*>(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve));
|
||||
m_result = data;
|
||||
if (!data) {
|
||||
if (num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 128) {
|
||||
data = static_cast<CoeffReturnType*>(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve));
|
||||
m_result = data;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Op reducer(m_reducer);
|
||||
if (internal::InnerReducer<Self, Op, Device>::run(*this, reducer, m_device, data, num_values_to_reduce, num_coeffs_to_preserve)) {
|
||||
@@ -533,9 +538,14 @@ struct TensorEvaluator<const TensorReductionOp<Op, Dims, ArgType>, Device>
|
||||
preserving_inner_dims) {
|
||||
const Index num_values_to_reduce = internal::array_prod(m_reducedDims);
|
||||
const Index num_coeffs_to_preserve = internal::array_prod(m_dimensions);
|
||||
if (!data && num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 32) {
|
||||
data = static_cast<CoeffReturnType*>(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve));
|
||||
m_result = data;
|
||||
if (!data) {
|
||||
if (num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 32) {
|
||||
data = static_cast<CoeffReturnType*>(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve));
|
||||
m_result = data;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Op reducer(m_reducer);
|
||||
if (internal::OuterReducer<Self, Op, Device>::run(*this, reducer, m_device, data, num_values_to_reduce, num_coeffs_to_preserve)) {
|
||||
@@ -556,6 +566,7 @@ struct TensorEvaluator<const TensorReductionOp<Op, Dims, ArgType>, Device>
|
||||
m_impl.cleanup();
|
||||
if (m_result) {
|
||||
m_device.deallocate(m_result);
|
||||
m_result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,11 +67,21 @@ __device__ EIGEN_ALWAYS_INLINE void atomicReduce(T* output, T accum, R& reducer)
|
||||
#endif
|
||||
}
|
||||
|
||||
// We extend atomicExch to support extra data types
|
||||
template <typename Type>
|
||||
__device__ inline Type atomicExchCustom(Type* address, Type val) {
|
||||
return atomicExch(address, val);
|
||||
}
|
||||
|
||||
template <>
|
||||
__device__ inline double atomicExchCustom(double* address, double val) {
|
||||
unsigned long long int* address_as_ull = reinterpret_cast<unsigned long long int*>(address);
|
||||
return __longlong_as_double(atomicExch(address_as_ull, __double_as_longlong(val)));
|
||||
}
|
||||
|
||||
#ifdef EIGEN_HAS_CUDA_FP16
|
||||
template <template <typename T> class R>
|
||||
__device__ inline void atomicReduce(half2* output, half2 accum, R<half>& reducer) {
|
||||
#if __CUDA_ARCH__ >= 300
|
||||
unsigned int oldval = *reinterpret_cast<unsigned int*>(output);
|
||||
unsigned int newval = oldval;
|
||||
reducer.reducePacket(accum, reinterpret_cast<half2*>(&newval));
|
||||
@@ -87,9 +97,6 @@ __device__ inline void atomicReduce(half2* output, half2 accum, R<half>& reducer
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert(0 && "Shouldn't be called on unsupported device");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -130,7 +137,7 @@ __global__ void FullReductionKernel(Reducer reducer, const Self input, Index num
|
||||
unsigned int block = atomicCAS(semaphore, 0u, 1u);
|
||||
if (block == 0) {
|
||||
// We're the first block to run, initialize the output value
|
||||
atomicExch(output, reducer.initialize());
|
||||
atomicExchCustom(output, reducer.initialize());
|
||||
__threadfence();
|
||||
atomicExch(semaphore, 2u);
|
||||
}
|
||||
@@ -263,17 +270,22 @@ __global__ void ReductionCleanupKernelHalfFloat(Op& reducer, half* output, half2
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess>
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess, typename Enabled = void>
|
||||
struct FullReductionLauncher {
|
||||
static void run(const Self&, Op&, const GpuDevice&, OutputType*, typename Self::Index) {
|
||||
assert(false && "Should only be called on floats and half floats");
|
||||
assert(false && "Should only be called on doubles, floats and half floats");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Self, typename Op, bool PacketAccess>
|
||||
struct FullReductionLauncher<Self, Op, float, PacketAccess> {
|
||||
static void run(const Self& self, Op& reducer, const GpuDevice& device, float* output, typename Self::Index num_coeffs) {
|
||||
// Specialization for float and double
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess>
|
||||
struct FullReductionLauncher<
|
||||
Self, Op, OutputType, PacketAccess,
|
||||
typename internal::enable_if<
|
||||
internal::is_same<float, OutputType>::value ||
|
||||
internal::is_same<double, OutputType>::value,
|
||||
void>::type> {
|
||||
static void run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs) {
|
||||
typedef typename Self::Index Index;
|
||||
typedef typename Self::CoeffReturnType Scalar;
|
||||
const int block_size = 256;
|
||||
@@ -330,20 +342,22 @@ struct FullReductionLauncher<Self, Op, Eigen::half, true> {
|
||||
template <typename Self, typename Op, bool Vectorizable>
|
||||
struct FullReducer<Self, Op, GpuDevice, Vectorizable> {
|
||||
// Unfortunately nvidia doesn't support well exotic types such as complex,
|
||||
// so reduce the scope of the optimized version of the code to the simple case
|
||||
// of floats and half floats.
|
||||
// so reduce the scope of the optimized version of the code to the simple cases
|
||||
// of doubles, floats and half floats
|
||||
#ifdef EIGEN_HAS_CUDA_FP16
|
||||
static const bool HasOptimizedImplementation = !Op::IsStateful &&
|
||||
(internal::is_same<typename Self::CoeffReturnType, float>::value ||
|
||||
internal::is_same<typename Self::CoeffReturnType, double>::value ||
|
||||
(internal::is_same<typename Self::CoeffReturnType, Eigen::half>::value && reducer_traits<Op, GpuDevice>::PacketAccess));
|
||||
#else
|
||||
static const bool HasOptimizedImplementation = !Op::IsStateful &&
|
||||
internal::is_same<typename Self::CoeffReturnType, float>::value;
|
||||
(internal::is_same<typename Self::CoeffReturnType, float>::value ||
|
||||
internal::is_same<typename Self::CoeffReturnType, double>::value);
|
||||
#endif
|
||||
|
||||
template <typename OutputType>
|
||||
static void run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output) {
|
||||
assert(HasOptimizedImplementation && "Should only be called on floats or half floats");
|
||||
assert(HasOptimizedImplementation && "Should only be called on doubles, floats or half floats");
|
||||
const Index num_coeffs = array_prod(self.m_impl.dimensions());
|
||||
// Don't crash when we're called with an input tensor of size 0.
|
||||
if (num_coeffs == 0) {
|
||||
@@ -360,6 +374,7 @@ template <int NumPerThread, typename Self,
|
||||
__global__ void InnerReductionKernel(Reducer reducer, const Self input, Index num_coeffs_to_reduce, Index num_preserved_coeffs,
|
||||
typename Self::CoeffReturnType* output) {
|
||||
#if __CUDA_ARCH__ >= 300
|
||||
typedef typename Self::CoeffReturnType Type;
|
||||
eigen_assert(blockDim.y == 1);
|
||||
eigen_assert(blockDim.z == 1);
|
||||
eigen_assert(gridDim.y == 1);
|
||||
@@ -389,13 +404,13 @@ __global__ void InnerReductionKernel(Reducer reducer, const Self input, Index nu
|
||||
const Index col_block = i % input_col_blocks;
|
||||
const Index col_begin = col_block * blockDim.x * NumPerThread + threadIdx.x;
|
||||
|
||||
float reduced_val = reducer.initialize();
|
||||
Type reduced_val = reducer.initialize();
|
||||
|
||||
for (Index j = 0; j < NumPerThread; j += unroll_times) {
|
||||
const Index last_col = col_begin + blockDim.x * (j + unroll_times - 1);
|
||||
if (last_col >= num_coeffs_to_reduce) {
|
||||
for (Index col = col_begin + blockDim.x * j; col < num_coeffs_to_reduce; col += blockDim.x) {
|
||||
const float val = input.m_impl.coeff(row * num_coeffs_to_reduce + col);
|
||||
const Type val = input.m_impl.coeff(row * num_coeffs_to_reduce + col);
|
||||
reducer.reduce(val, &reduced_val);
|
||||
}
|
||||
break;
|
||||
@@ -521,17 +536,23 @@ __global__ void InnerReductionKernelHalfFloat(Reducer reducer, const Self input,
|
||||
|
||||
#endif
|
||||
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess>
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess, typename Enabled = void>
|
||||
struct InnerReductionLauncher {
|
||||
static EIGEN_DEVICE_FUNC bool run(const Self&, Op&, const GpuDevice&, OutputType*, typename Self::Index, typename Self::Index) {
|
||||
assert(false && "Should only be called to reduce floats and half floats on a gpu device");
|
||||
assert(false && "Should only be called to reduce doubles, floats and half floats on a gpu device");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Self, typename Op, bool PacketAccess>
|
||||
struct InnerReductionLauncher<Self, Op, float, PacketAccess> {
|
||||
static bool run(const Self& self, Op& reducer, const GpuDevice& device, float* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
|
||||
// Specialization for float and double
|
||||
template <typename Self, typename Op, typename OutputType, bool PacketAccess>
|
||||
struct InnerReductionLauncher<
|
||||
Self, Op, OutputType, PacketAccess,
|
||||
typename internal::enable_if<
|
||||
internal::is_same<float, OutputType>::value ||
|
||||
internal::is_same<double, OutputType>::value,
|
||||
void>::type> {
|
||||
static bool run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
|
||||
typedef typename Self::Index Index;
|
||||
|
||||
const Index num_coeffs = num_coeffs_to_reduce * num_preserved_vals;
|
||||
@@ -549,7 +570,7 @@ struct InnerReductionLauncher<Self, Op, float, PacketAccess> {
|
||||
const int max_blocks = device.getNumCudaMultiProcessors() *
|
||||
device.maxCudaThreadsPerMultiProcessor() / 1024;
|
||||
const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
|
||||
LAUNCH_CUDA_KERNEL((ReductionInitKernel<float, Index>),
|
||||
LAUNCH_CUDA_KERNEL((ReductionInitKernel<OutputType, Index>),
|
||||
num_blocks, 1024, 0, device, reducer.initialize(),
|
||||
num_preserved_vals, output);
|
||||
}
|
||||
@@ -616,15 +637,17 @@ struct InnerReducer<Self, Op, GpuDevice> {
|
||||
#ifdef EIGEN_HAS_CUDA_FP16
|
||||
static const bool HasOptimizedImplementation = !Op::IsStateful &&
|
||||
(internal::is_same<typename Self::CoeffReturnType, float>::value ||
|
||||
internal::is_same<typename Self::CoeffReturnType, double>::value ||
|
||||
(internal::is_same<typename Self::CoeffReturnType, Eigen::half>::value && reducer_traits<Op, GpuDevice>::PacketAccess));
|
||||
#else
|
||||
static const bool HasOptimizedImplementation = !Op::IsStateful &&
|
||||
internal::is_same<typename Self::CoeffReturnType, float>::value;
|
||||
(internal::is_same<typename Self::CoeffReturnType, float>::value ||
|
||||
internal::is_same<typename Self::CoeffReturnType, double>::value);
|
||||
#endif
|
||||
|
||||
template <typename OutputType>
|
||||
static bool run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
|
||||
assert(HasOptimizedImplementation && "Should only be called on floats or half floats");
|
||||
assert(HasOptimizedImplementation && "Should only be called on doubles, floats or half floats");
|
||||
const Index num_coeffs = array_prod(self.m_impl.dimensions());
|
||||
// Don't crash when we're called with an input tensor of size 0.
|
||||
if (num_coeffs == 0) {
|
||||
@@ -675,11 +698,11 @@ struct OuterReducer<Self, Op, GpuDevice> {
|
||||
// so reduce the scope of the optimized version of the code to the simple case
|
||||
// of floats.
|
||||
static const bool HasOptimizedImplementation = !Op::IsStateful &&
|
||||
internal::is_same<typename Self::CoeffReturnType, float>::value;
|
||||
|
||||
(internal::is_same<typename Self::CoeffReturnType, float>::value ||
|
||||
internal::is_same<typename Self::CoeffReturnType, double>::value);
|
||||
template <typename Device, typename OutputType>
|
||||
static EIGEN_DEVICE_FUNC bool run(const Self&, Op&, const Device&, OutputType*, typename Self::Index, typename Self::Index) {
|
||||
assert(false && "Should only be called to reduce floats on a gpu device");
|
||||
assert(false && "Should only be called to reduce doubles or floats on a gpu device");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FILE(GLOB Eigen_CXX11_TensorSymmetry_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_CXX11_TensorSymmetry_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11/src/TensorSymmetry COMPONENT Devel
|
||||
)
|
||||
|
||||
add_subdirectory(util)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_CXX11_TensorSymmetry_util_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_CXX11_TensorSymmetry_util_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11/src/TensorSymmetry/util COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_CXX11_ThreadPool_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_CXX11_ThreadPool_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11/src/ThreadPool COMPONENT Devel
|
||||
)
|
||||
@@ -50,7 +50,7 @@ class EventCount {
|
||||
public:
|
||||
class Waiter;
|
||||
|
||||
EventCount(std::vector<Waiter>& waiters) : waiters_(waiters) {
|
||||
EventCount(MaxSizeVector<Waiter>& waiters) : waiters_(waiters) {
|
||||
eigen_assert(waiters.size() < (1 << kWaiterBits) - 1);
|
||||
// Initialize epoch to something close to overflow to test overflow.
|
||||
state_ = kStackMask | (kEpochMask - kEpochInc * waiters.size() * 2);
|
||||
@@ -199,7 +199,7 @@ class EventCount {
|
||||
static const uint64_t kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift;
|
||||
static const uint64_t kEpochInc = 1ull << kEpochShift;
|
||||
std::atomic<uint64_t> state_;
|
||||
std::vector<Waiter>& waiters_;
|
||||
MaxSizeVector<Waiter>& waiters_;
|
||||
|
||||
void Park(Waiter* w) {
|
||||
std::unique_lock<std::mutex> lock(w->mu);
|
||||
|
||||
@@ -29,6 +29,8 @@ class NonBlockingThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
||||
spinning_(0),
|
||||
done_(false),
|
||||
ec_(waiters_) {
|
||||
waiters_.resize(num_threads);
|
||||
|
||||
// Calculate coprimes of num_threads.
|
||||
// Coprimes are used for a random walk over all threads in Steal
|
||||
// and NonEmptyQueueIndex. Iteration is based on the fact that if we take
|
||||
@@ -123,7 +125,7 @@ class NonBlockingThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
||||
MaxSizeVector<Thread*> threads_;
|
||||
MaxSizeVector<Queue*> queues_;
|
||||
MaxSizeVector<unsigned> coprimes_;
|
||||
std::vector<EventCount::Waiter> waiters_;
|
||||
MaxSizeVector<EventCount::Waiter> waiters_;
|
||||
std::atomic<unsigned> blocked_;
|
||||
std::atomic<bool> spinning_;
|
||||
std::atomic<bool> done_;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_CXX11_util_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_CXX11_util_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11/src/util COMPONENT Devel
|
||||
)
|
||||
@@ -55,6 +55,17 @@ class MaxSizeVector {
|
||||
internal::aligned_free(data_);
|
||||
}
|
||||
|
||||
void resize(size_t n) {
|
||||
eigen_assert(n <= reserve_);
|
||||
for (size_t i = size_; i < n; ++i) {
|
||||
new (&data_[i]) T;
|
||||
}
|
||||
for (size_t i = n; i < size_; ++i) {
|
||||
data_[i].~T();
|
||||
}
|
||||
size_ = n;
|
||||
}
|
||||
|
||||
// Append new elements (up to reserved size).
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
void push_back(const T& t) {
|
||||
|
||||
43
unsupported/Eigen/EulerAngles
Normal file
43
unsupported/Eigen/EulerAngles
Normal file
@@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Tal Hadad <tal_hd@hotmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_EULERANGLES_MODULE_H
|
||||
#define EIGEN_EULERANGLES_MODULE_H
|
||||
|
||||
|
||||
#include "Eigen/Core"
|
||||
#include "Eigen/Geometry"
|
||||
|
||||
#include "Eigen/src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/**
|
||||
* \defgroup EulerAngles_Module EulerAngles module
|
||||
* \brief This module provides generic euler angles rotation.
|
||||
*
|
||||
* Euler angles are a way to represent 3D rotation.
|
||||
*
|
||||
* In order to use this module in your code, include this header:
|
||||
* \code
|
||||
* #include <unsupported/Eigen/EulerAngles>
|
||||
* \endcode
|
||||
*
|
||||
* See \ref EulerAngles for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#include "src/EulerAngles/EulerSystem.h"
|
||||
#include "src/EulerAngles/EulerAngles.h"
|
||||
|
||||
#include "Eigen/src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_EULERANGLES_MODULE_H
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#include "../../Eigen/src/SparseCore/SparseUtil.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_AutoDiff_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_AutoDiff_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/AutoDiff COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_BVH_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_BVH_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/BVH COMPONENT Devel
|
||||
)
|
||||
@@ -1,16 +0,0 @@
|
||||
ADD_SUBDIRECTORY(AutoDiff)
|
||||
ADD_SUBDIRECTORY(BVH)
|
||||
ADD_SUBDIRECTORY(Eigenvalues)
|
||||
ADD_SUBDIRECTORY(FFT)
|
||||
ADD_SUBDIRECTORY(IterativeSolvers)
|
||||
ADD_SUBDIRECTORY(LevenbergMarquardt)
|
||||
ADD_SUBDIRECTORY(MatrixFunctions)
|
||||
ADD_SUBDIRECTORY(MoreVectorization)
|
||||
ADD_SUBDIRECTORY(NonLinearOptimization)
|
||||
ADD_SUBDIRECTORY(NumericalDiff)
|
||||
ADD_SUBDIRECTORY(Polynomials)
|
||||
ADD_SUBDIRECTORY(Skyline)
|
||||
ADD_SUBDIRECTORY(SparseExtra)
|
||||
ADD_SUBDIRECTORY(SpecialFunctions)
|
||||
ADD_SUBDIRECTORY(KroneckerProduct)
|
||||
ADD_SUBDIRECTORY(Splines)
|
||||
@@ -628,15 +628,15 @@ ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD>&
|
||||
m_info = Success;
|
||||
}
|
||||
|
||||
delete select;
|
||||
delete[] select;
|
||||
}
|
||||
|
||||
delete v;
|
||||
delete iparam;
|
||||
delete ipntr;
|
||||
delete workd;
|
||||
delete workl;
|
||||
delete resid;
|
||||
delete[] v;
|
||||
delete[] iparam;
|
||||
delete[] ipntr;
|
||||
delete[] workd;
|
||||
delete[] workl;
|
||||
delete[] resid;
|
||||
|
||||
m_isInitialized = true;
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_Eigenvalues_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_Eigenvalues_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Eigenvalues COMPONENT Devel
|
||||
)
|
||||
6
unsupported/Eigen/src/EulerAngles/CMakeLists.txt
Normal file
6
unsupported/Eigen/src/EulerAngles/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
FILE(GLOB Eigen_EulerAngles_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_EulerAngles_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/EulerAngles COMPONENT Devel
|
||||
)
|
||||
386
unsupported/Eigen/src/EulerAngles/EulerAngles.h
Normal file
386
unsupported/Eigen/src/EulerAngles/EulerAngles.h
Normal file
@@ -0,0 +1,386 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Tal Hadad <tal_hd@hotmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_EULERANGLESCLASS_H// TODO: Fix previous "EIGEN_EULERANGLES_H" definition?
|
||||
#define EIGEN_EULERANGLESCLASS_H
|
||||
|
||||
namespace Eigen
|
||||
{
|
||||
/*template<typename Other,
|
||||
int OtherRows=Other::RowsAtCompileTime,
|
||||
int OtherCols=Other::ColsAtCompileTime>
|
||||
struct ei_eulerangles_assign_impl;*/
|
||||
|
||||
/** \class EulerAngles
|
||||
*
|
||||
* \ingroup EulerAngles_Module
|
||||
*
|
||||
* \brief Represents a rotation in a 3 dimensional space as three Euler angles.
|
||||
*
|
||||
* Euler rotation is a set of three rotation of three angles over three fixed axes, defined by the EulerSystem given as a template parameter.
|
||||
*
|
||||
* Here is how intrinsic Euler angles works:
|
||||
* - first, rotate the axes system over the alpha axis in angle alpha
|
||||
* - then, rotate the axes system over the beta axis(which was rotated in the first stage) in angle beta
|
||||
* - then, rotate the axes system over the gamma axis(which was rotated in the two stages above) in angle gamma
|
||||
*
|
||||
* \note This class support only intrinsic Euler angles for simplicity,
|
||||
* see EulerSystem how to easily overcome this for extrinsic systems.
|
||||
*
|
||||
* ### Rotation representation and conversions ###
|
||||
*
|
||||
* It has been proved(see Wikipedia link below) that every rotation can be represented
|
||||
* by Euler angles, but there is no singular representation (e.g. unlike rotation matrices).
|
||||
* Therefore, you can convert from Eigen rotation and to them
|
||||
* (including rotation matrices, which is not called "rotations" by Eigen design).
|
||||
*
|
||||
* Euler angles usually used for:
|
||||
* - convenient human representation of rotation, especially in interactive GUI.
|
||||
* - gimbal systems and robotics
|
||||
* - efficient encoding(i.e. 3 floats only) of rotation for network protocols.
|
||||
*
|
||||
* However, Euler angles are slow comparing to quaternion or matrices,
|
||||
* because their unnatural math definition, although it's simple for human.
|
||||
* To overcome this, this class provide easy movement from the math friendly representation
|
||||
* to the human friendly representation, and vise-versa.
|
||||
*
|
||||
* All the user need to do is a safe simple C++ type conversion,
|
||||
* and this class take care for the math.
|
||||
* Additionally, some axes related computation is done in compile time.
|
||||
*
|
||||
* #### Euler angles ranges in conversions ####
|
||||
*
|
||||
* When converting some rotation to Euler angles, there are some ways you can guarantee
|
||||
* the Euler angles ranges.
|
||||
*
|
||||
* #### implicit ranges ####
|
||||
* When using implicit ranges, all angles are guarantee to be in the range [-PI, +PI],
|
||||
* unless you convert from some other Euler angles.
|
||||
* In this case, the range is __undefined__ (might be even less than -PI or greater than +2*PI).
|
||||
* \sa EulerAngles(const MatrixBase<Derived>&)
|
||||
* \sa EulerAngles(const RotationBase<Derived, 3>&)
|
||||
*
|
||||
* #### explicit ranges ####
|
||||
* When using explicit ranges, all angles are guarantee to be in the range you choose.
|
||||
* In the range Boolean parameter, you're been ask whether you prefer the positive range or not:
|
||||
* - _true_ - force the range between [0, +2*PI]
|
||||
* - _false_ - force the range between [-PI, +PI]
|
||||
*
|
||||
* ##### compile time ranges #####
|
||||
* This is when you have compile time ranges and you prefer to
|
||||
* use template parameter. (e.g. for performance)
|
||||
* \sa FromRotation()
|
||||
*
|
||||
* ##### run-time time ranges #####
|
||||
* Run-time ranges are also supported.
|
||||
* \sa EulerAngles(const MatrixBase<Derived>&, bool, bool, bool)
|
||||
* \sa EulerAngles(const RotationBase<Derived, 3>&, bool, bool, bool)
|
||||
*
|
||||
* ### Convenient user typedefs ###
|
||||
*
|
||||
* Convenient typedefs for EulerAngles exist for float and double scalar,
|
||||
* in a form of EulerAngles{A}{B}{C}{scalar},
|
||||
* e.g. \ref EulerAnglesXYZd, \ref EulerAnglesZYZf.
|
||||
*
|
||||
* Only for positive axes{+x,+y,+z} Euler systems are have convenient typedef.
|
||||
* If you need negative axes{-x,-y,-z}, it is recommended to create you own typedef with
|
||||
* a word that represent what you need.
|
||||
*
|
||||
* ### Example ###
|
||||
*
|
||||
* \include EulerAngles.cpp
|
||||
* Output: \verbinclude EulerAngles.out
|
||||
*
|
||||
* ### Additional reading ###
|
||||
*
|
||||
* If you're want to get more idea about how Euler system work in Eigen see EulerSystem.
|
||||
*
|
||||
* More information about Euler angles: https://en.wikipedia.org/wiki/Euler_angles
|
||||
*
|
||||
* \tparam _Scalar the scalar type, i.e., the type of the angles.
|
||||
*
|
||||
* \tparam _System the EulerSystem to use, which represents the axes of rotation.
|
||||
*/
|
||||
template <typename _Scalar, class _System>
|
||||
class EulerAngles : public RotationBase<EulerAngles<_Scalar, _System>, 3>
|
||||
{
|
||||
public:
|
||||
/** the scalar type of the angles */
|
||||
typedef _Scalar Scalar;
|
||||
|
||||
/** the EulerSystem to use, which represents the axes of rotation. */
|
||||
typedef _System System;
|
||||
|
||||
typedef Matrix<Scalar,3,3> Matrix3; /*!< the equivalent rotation matrix type */
|
||||
typedef Matrix<Scalar,3,1> Vector3; /*!< the equivalent 3 dimension vector type */
|
||||
typedef Quaternion<Scalar> QuaternionType; /*!< the equivalent quaternion type */
|
||||
typedef AngleAxis<Scalar> AngleAxisType; /*!< the equivalent angle-axis type */
|
||||
|
||||
/** \returns the axis vector of the first (alpha) rotation */
|
||||
static Vector3 AlphaAxisVector() {
|
||||
const Vector3& u = Vector3::Unit(System::AlphaAxisAbs - 1);
|
||||
return System::IsAlphaOpposite ? -u : u;
|
||||
}
|
||||
|
||||
/** \returns the axis vector of the second (beta) rotation */
|
||||
static Vector3 BetaAxisVector() {
|
||||
const Vector3& u = Vector3::Unit(System::BetaAxisAbs - 1);
|
||||
return System::IsBetaOpposite ? -u : u;
|
||||
}
|
||||
|
||||
/** \returns the axis vector of the third (gamma) rotation */
|
||||
static Vector3 GammaAxisVector() {
|
||||
const Vector3& u = Vector3::Unit(System::GammaAxisAbs - 1);
|
||||
return System::IsGammaOpposite ? -u : u;
|
||||
}
|
||||
|
||||
private:
|
||||
Vector3 m_angles;
|
||||
|
||||
public:
|
||||
/** Default constructor without initialization. */
|
||||
EulerAngles() {}
|
||||
/** Constructs and initialize Euler angles(\p alpha, \p beta, \p gamma). */
|
||||
EulerAngles(const Scalar& alpha, const Scalar& beta, const Scalar& gamma) :
|
||||
m_angles(alpha, beta, gamma) {}
|
||||
|
||||
/** Constructs and initialize Euler angles from a 3x3 rotation matrix \p m.
|
||||
*
|
||||
* \note All angles will be in the range [-PI, PI].
|
||||
*/
|
||||
template<typename Derived>
|
||||
EulerAngles(const MatrixBase<Derived>& m) { *this = m; }
|
||||
|
||||
/** Constructs and initialize Euler angles from a 3x3 rotation matrix \p m,
|
||||
* with options to choose for each angle the requested range.
|
||||
*
|
||||
* If positive range is true, then the specified angle will be in the range [0, +2*PI].
|
||||
* Otherwise, the specified angle will be in the range [-PI, +PI].
|
||||
*
|
||||
* \param m The 3x3 rotation matrix to convert
|
||||
* \param positiveRangeAlpha If true, alpha will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \param positiveRangeBeta If true, beta will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \param positiveRangeGamma If true, gamma will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
*/
|
||||
template<typename Derived>
|
||||
EulerAngles(
|
||||
const MatrixBase<Derived>& m,
|
||||
bool positiveRangeAlpha,
|
||||
bool positiveRangeBeta,
|
||||
bool positiveRangeGamma) {
|
||||
|
||||
System::CalcEulerAngles(*this, m, positiveRangeAlpha, positiveRangeBeta, positiveRangeGamma);
|
||||
}
|
||||
|
||||
/** Constructs and initialize Euler angles from a rotation \p rot.
|
||||
*
|
||||
* \note All angles will be in the range [-PI, PI], unless \p rot is an EulerAngles.
|
||||
* If rot is an EulerAngles, expected EulerAngles range is __undefined__.
|
||||
* (Use other functions here for enforcing range if this effect is desired)
|
||||
*/
|
||||
template<typename Derived>
|
||||
EulerAngles(const RotationBase<Derived, 3>& rot) { *this = rot; }
|
||||
|
||||
/** Constructs and initialize Euler angles from a rotation \p rot,
|
||||
* with options to choose for each angle the requested range.
|
||||
*
|
||||
* If positive range is true, then the specified angle will be in the range [0, +2*PI].
|
||||
* Otherwise, the specified angle will be in the range [-PI, +PI].
|
||||
*
|
||||
* \param rot The 3x3 rotation matrix to convert
|
||||
* \param positiveRangeAlpha If true, alpha will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \param positiveRangeBeta If true, beta will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \param positiveRangeGamma If true, gamma will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
*/
|
||||
template<typename Derived>
|
||||
EulerAngles(
|
||||
const RotationBase<Derived, 3>& rot,
|
||||
bool positiveRangeAlpha,
|
||||
bool positiveRangeBeta,
|
||||
bool positiveRangeGamma) {
|
||||
|
||||
System::CalcEulerAngles(*this, rot.toRotationMatrix(), positiveRangeAlpha, positiveRangeBeta, positiveRangeGamma);
|
||||
}
|
||||
|
||||
/** \returns The angle values stored in a vector (alpha, beta, gamma). */
|
||||
const Vector3& angles() const { return m_angles; }
|
||||
/** \returns A read-write reference to the angle values stored in a vector (alpha, beta, gamma). */
|
||||
Vector3& angles() { return m_angles; }
|
||||
|
||||
/** \returns The value of the first angle. */
|
||||
Scalar alpha() const { return m_angles[0]; }
|
||||
/** \returns A read-write reference to the angle of the first angle. */
|
||||
Scalar& alpha() { return m_angles[0]; }
|
||||
|
||||
/** \returns The value of the second angle. */
|
||||
Scalar beta() const { return m_angles[1]; }
|
||||
/** \returns A read-write reference to the angle of the second angle. */
|
||||
Scalar& beta() { return m_angles[1]; }
|
||||
|
||||
/** \returns The value of the third angle. */
|
||||
Scalar gamma() const { return m_angles[2]; }
|
||||
/** \returns A read-write reference to the angle of the third angle. */
|
||||
Scalar& gamma() { return m_angles[2]; }
|
||||
|
||||
/** \returns The Euler angles rotation inverse (which is as same as the negative),
|
||||
* (-alpha, -beta, -gamma).
|
||||
*/
|
||||
EulerAngles inverse() const
|
||||
{
|
||||
EulerAngles res;
|
||||
res.m_angles = -m_angles;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** \returns The Euler angles rotation negative (which is as same as the inverse),
|
||||
* (-alpha, -beta, -gamma).
|
||||
*/
|
||||
EulerAngles operator -() const
|
||||
{
|
||||
return inverse();
|
||||
}
|
||||
|
||||
/** Constructs and initialize Euler angles from a 3x3 rotation matrix \p m,
|
||||
* with options to choose for each angle the requested range (__only in compile time__).
|
||||
*
|
||||
* If positive range is true, then the specified angle will be in the range [0, +2*PI].
|
||||
* Otherwise, the specified angle will be in the range [-PI, +PI].
|
||||
*
|
||||
* \param m The 3x3 rotation matrix to convert
|
||||
* \tparam positiveRangeAlpha If true, alpha will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \tparam positiveRangeBeta If true, beta will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \tparam positiveRangeGamma If true, gamma will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
*/
|
||||
template<
|
||||
bool PositiveRangeAlpha,
|
||||
bool PositiveRangeBeta,
|
||||
bool PositiveRangeGamma,
|
||||
typename Derived>
|
||||
static EulerAngles FromRotation(const MatrixBase<Derived>& m)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived, 3, 3)
|
||||
|
||||
EulerAngles e;
|
||||
System::template CalcEulerAngles<
|
||||
PositiveRangeAlpha, PositiveRangeBeta, PositiveRangeGamma, _Scalar>(e, m);
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Constructs and initialize Euler angles from a rotation \p rot,
|
||||
* with options to choose for each angle the requested range (__only in compile time__).
|
||||
*
|
||||
* If positive range is true, then the specified angle will be in the range [0, +2*PI].
|
||||
* Otherwise, the specified angle will be in the range [-PI, +PI].
|
||||
*
|
||||
* \param rot The 3x3 rotation matrix to convert
|
||||
* \tparam positiveRangeAlpha If true, alpha will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \tparam positiveRangeBeta If true, beta will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
* \tparam positiveRangeGamma If true, gamma will be in [0, 2*PI]. Otherwise, in [-PI, +PI].
|
||||
*/
|
||||
template<
|
||||
bool PositiveRangeAlpha,
|
||||
bool PositiveRangeBeta,
|
||||
bool PositiveRangeGamma,
|
||||
typename Derived>
|
||||
static EulerAngles FromRotation(const RotationBase<Derived, 3>& rot)
|
||||
{
|
||||
return FromRotation<PositiveRangeAlpha, PositiveRangeBeta, PositiveRangeGamma>(rot.toRotationMatrix());
|
||||
}
|
||||
|
||||
/*EulerAngles& fromQuaternion(const QuaternionType& q)
|
||||
{
|
||||
// TODO: Implement it in a faster way for quaternions
|
||||
// According to http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
||||
// we can compute only the needed matrix cells and then convert to euler angles. (see ZYX example below)
|
||||
// Currently we compute all matrix cells from quaternion.
|
||||
|
||||
// Special case only for ZYX
|
||||
//Scalar y2 = q.y() * q.y();
|
||||
//m_angles[0] = std::atan2(2*(q.w()*q.z() + q.x()*q.y()), (1 - 2*(y2 + q.z()*q.z())));
|
||||
//m_angles[1] = std::asin( 2*(q.w()*q.y() - q.z()*q.x()));
|
||||
//m_angles[2] = std::atan2(2*(q.w()*q.x() + q.y()*q.z()), (1 - 2*(q.x()*q.x() + y2)));
|
||||
}*/
|
||||
|
||||
/** Set \c *this from a rotation matrix(i.e. pure orthogonal matrix with determinant of +1). */
|
||||
template<typename Derived>
|
||||
EulerAngles& operator=(const MatrixBase<Derived>& m) {
|
||||
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived, 3, 3)
|
||||
|
||||
System::CalcEulerAngles(*this, m);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Assign and construct from another EulerAngles (with different system)
|
||||
|
||||
/** Set \c *this from a rotation. */
|
||||
template<typename Derived>
|
||||
EulerAngles& operator=(const RotationBase<Derived, 3>& rot) {
|
||||
System::CalcEulerAngles(*this, rot.toRotationMatrix());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Support isApprox function
|
||||
|
||||
/** \returns an equivalent 3x3 rotation matrix. */
|
||||
Matrix3 toRotationMatrix() const
|
||||
{
|
||||
return static_cast<QuaternionType>(*this).toRotationMatrix();
|
||||
}
|
||||
|
||||
/** Convert the Euler angles to quaternion. */
|
||||
operator QuaternionType() const
|
||||
{
|
||||
return
|
||||
AngleAxisType(alpha(), AlphaAxisVector()) *
|
||||
AngleAxisType(beta(), BetaAxisVector()) *
|
||||
AngleAxisType(gamma(), GammaAxisVector());
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& s, const EulerAngles<Scalar, System>& eulerAngles)
|
||||
{
|
||||
s << eulerAngles.angles().transpose();
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#define EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(AXES, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
/** \ingroup EulerAngles_Module */ \
|
||||
typedef EulerAngles<SCALAR_TYPE, EulerSystem##AXES> EulerAngles##AXES##SCALAR_POSTFIX;
|
||||
|
||||
#define EIGEN_EULER_ANGLES_TYPEDEFS(SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(XYZ, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(XYX, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(XZY, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(XZX, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
\
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(YZX, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(YZY, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(YXZ, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(YXY, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
\
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(ZXY, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(ZXZ, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(ZYX, SCALAR_TYPE, SCALAR_POSTFIX) \
|
||||
EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(ZYZ, SCALAR_TYPE, SCALAR_POSTFIX)
|
||||
|
||||
EIGEN_EULER_ANGLES_TYPEDEFS(float, f)
|
||||
EIGEN_EULER_ANGLES_TYPEDEFS(double, d)
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template<typename _Scalar, class _System>
|
||||
struct traits<EulerAngles<_Scalar, _System> >
|
||||
{
|
||||
typedef _Scalar Scalar;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EIGEN_EULERANGLESCLASS_H
|
||||
316
unsupported/Eigen/src/EulerAngles/EulerSystem.h
Normal file
316
unsupported/Eigen/src/EulerAngles/EulerSystem.h
Normal file
@@ -0,0 +1,316 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2015 Tal Hadad <tal_hd@hotmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_EULERSYSTEM_H
|
||||
#define EIGEN_EULERSYSTEM_H
|
||||
|
||||
namespace Eigen
|
||||
{
|
||||
// Forward declerations
|
||||
template <typename _Scalar, class _System>
|
||||
class EulerAngles;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
// TODO: Check if already exists on the rest API
|
||||
template <int Num, bool IsPositive = (Num > 0)>
|
||||
struct Abs
|
||||
{
|
||||
enum { value = Num };
|
||||
};
|
||||
|
||||
template <int Num>
|
||||
struct Abs<Num, false>
|
||||
{
|
||||
enum { value = -Num };
|
||||
};
|
||||
|
||||
template <int Axis>
|
||||
struct IsValidAxis
|
||||
{
|
||||
enum { value = Axis != 0 && Abs<Axis>::value <= 3 };
|
||||
};
|
||||
}
|
||||
|
||||
#define EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
|
||||
|
||||
/** \brief Representation of a fixed signed rotation axis for EulerSystem.
|
||||
*
|
||||
* \ingroup EulerAngles_Module
|
||||
*
|
||||
* Values here represent:
|
||||
* - The axis of the rotation: X, Y or Z.
|
||||
* - The sign (i.e. direction of the rotation along the axis): positive(+) or negative(-)
|
||||
*
|
||||
* Therefore, this could express all the axes {+X,+Y,+Z,-X,-Y,-Z}
|
||||
*
|
||||
* For positive axis, use +EULER_{axis}, and for negative axis use -EULER_{axis}.
|
||||
*/
|
||||
enum EulerAxis
|
||||
{
|
||||
EULER_X = 1, /*!< the X axis */
|
||||
EULER_Y = 2, /*!< the Y axis */
|
||||
EULER_Z = 3 /*!< the Z axis */
|
||||
};
|
||||
|
||||
/** \class EulerSystem
|
||||
*
|
||||
* \ingroup EulerAngles_Module
|
||||
*
|
||||
* \brief Represents a fixed Euler rotation system.
|
||||
*
|
||||
* This meta-class goal is to represent the Euler system in compilation time, for EulerAngles.
|
||||
*
|
||||
* You can use this class to get two things:
|
||||
* - Build an Euler system, and then pass it as a template parameter to EulerAngles.
|
||||
* - Query some compile time data about an Euler system. (e.g. Whether it's tait bryan)
|
||||
*
|
||||
* Euler rotation is a set of three rotation on fixed axes. (see \ref EulerAngles)
|
||||
* This meta-class store constantly those signed axes. (see \ref EulerAxis)
|
||||
*
|
||||
* ### Types of Euler systems ###
|
||||
*
|
||||
* All and only valid 3 dimension Euler rotation over standard
|
||||
* signed axes{+X,+Y,+Z,-X,-Y,-Z} are supported:
|
||||
* - all axes X, Y, Z in each valid order (see below what order is valid)
|
||||
* - rotation over the axis is supported both over the positive and negative directions.
|
||||
* - both tait bryan and proper/classic Euler angles (i.e. the opposite).
|
||||
*
|
||||
* Since EulerSystem support both positive and negative directions,
|
||||
* you may call this rotation distinction in other names:
|
||||
* - _right handed_ or _left handed_
|
||||
* - _counterclockwise_ or _clockwise_
|
||||
*
|
||||
* Notice all axed combination are valid, and would trigger a static assertion.
|
||||
* Same unsigned axes can't be neighbors, e.g. {X,X,Y} is invalid.
|
||||
* This yield two and only two classes:
|
||||
* - _tait bryan_ - all unsigned axes are distinct, e.g. {X,Y,Z}
|
||||
* - _proper/classic Euler angles_ - The first and the third unsigned axes is equal,
|
||||
* and the second is different, e.g. {X,Y,X}
|
||||
*
|
||||
* ### Intrinsic vs extrinsic Euler systems ###
|
||||
*
|
||||
* Only intrinsic Euler systems are supported for simplicity.
|
||||
* If you want to use extrinsic Euler systems,
|
||||
* just use the equal intrinsic opposite order for axes and angles.
|
||||
* I.e axes (A,B,C) becomes (C,B,A), and angles (a,b,c) becomes (c,b,a).
|
||||
*
|
||||
* ### Convenient user typedefs ###
|
||||
*
|
||||
* Convenient typedefs for EulerSystem exist (only for positive axes Euler systems),
|
||||
* in a form of EulerSystem{A}{B}{C}, e.g. \ref EulerSystemXYZ.
|
||||
*
|
||||
* ### Additional reading ###
|
||||
*
|
||||
* More information about Euler angles: https://en.wikipedia.org/wiki/Euler_angles
|
||||
*
|
||||
* \tparam _AlphaAxis the first fixed EulerAxis
|
||||
*
|
||||
* \tparam _AlphaAxis the second fixed EulerAxis
|
||||
*
|
||||
* \tparam _AlphaAxis the third fixed EulerAxis
|
||||
*/
|
||||
template <int _AlphaAxis, int _BetaAxis, int _GammaAxis>
|
||||
class EulerSystem
|
||||
{
|
||||
public:
|
||||
// It's defined this way and not as enum, because I think
|
||||
// that enum is not guerantee to support negative numbers
|
||||
|
||||
/** The first rotation axis */
|
||||
static const int AlphaAxis = _AlphaAxis;
|
||||
|
||||
/** The second rotation axis */
|
||||
static const int BetaAxis = _BetaAxis;
|
||||
|
||||
/** The third rotation axis */
|
||||
static const int GammaAxis = _GammaAxis;
|
||||
|
||||
enum
|
||||
{
|
||||
AlphaAxisAbs = internal::Abs<AlphaAxis>::value, /*!< the first rotation axis unsigned */
|
||||
BetaAxisAbs = internal::Abs<BetaAxis>::value, /*!< the second rotation axis unsigned */
|
||||
GammaAxisAbs = internal::Abs<GammaAxis>::value, /*!< the third rotation axis unsigned */
|
||||
|
||||
IsAlphaOpposite = (AlphaAxis < 0) ? 1 : 0, /*!< weather alpha axis is negative */
|
||||
IsBetaOpposite = (BetaAxis < 0) ? 1 : 0, /*!< weather beta axis is negative */
|
||||
IsGammaOpposite = (GammaAxis < 0) ? 1 : 0, /*!< weather gamma axis is negative */
|
||||
|
||||
IsOdd = ((AlphaAxisAbs)%3 == (BetaAxisAbs - 1)%3) ? 0 : 1, /*!< weather the Euler system is odd */
|
||||
IsEven = IsOdd ? 0 : 1, /*!< weather the Euler system is even */
|
||||
|
||||
IsTaitBryan = ((unsigned)AlphaAxisAbs != (unsigned)GammaAxisAbs) ? 1 : 0 /*!< weather the Euler system is tait bryan */
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT(internal::IsValidAxis<AlphaAxis>::value,
|
||||
ALPHA_AXIS_IS_INVALID);
|
||||
|
||||
EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT(internal::IsValidAxis<BetaAxis>::value,
|
||||
BETA_AXIS_IS_INVALID);
|
||||
|
||||
EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT(internal::IsValidAxis<GammaAxis>::value,
|
||||
GAMMA_AXIS_IS_INVALID);
|
||||
|
||||
EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT((unsigned)AlphaAxisAbs != (unsigned)BetaAxisAbs,
|
||||
ALPHA_AXIS_CANT_BE_EQUAL_TO_BETA_AXIS);
|
||||
|
||||
EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT((unsigned)BetaAxisAbs != (unsigned)GammaAxisAbs,
|
||||
BETA_AXIS_CANT_BE_EQUAL_TO_GAMMA_AXIS);
|
||||
|
||||
enum
|
||||
{
|
||||
// I, J, K are the pivot indexes permutation for the rotation matrix, that match this Euler system.
|
||||
// They are used in this class converters.
|
||||
// They are always different from each other, and their possible values are: 0, 1, or 2.
|
||||
I = AlphaAxisAbs - 1,
|
||||
J = (AlphaAxisAbs - 1 + 1 + IsOdd)%3,
|
||||
K = (AlphaAxisAbs - 1 + 2 - IsOdd)%3
|
||||
};
|
||||
|
||||
// TODO: Get @mat parameter in form that avoids double evaluation.
|
||||
template <typename Derived>
|
||||
static void CalcEulerAngles_imp(Matrix<typename MatrixBase<Derived>::Scalar, 3, 1>& res, const MatrixBase<Derived>& mat, internal::true_type /*isTaitBryan*/)
|
||||
{
|
||||
using std::atan2;
|
||||
using std::sin;
|
||||
using std::cos;
|
||||
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
typedef Matrix<Scalar,2,1> Vector2;
|
||||
|
||||
res[0] = atan2(mat(J,K), mat(K,K));
|
||||
Scalar c2 = Vector2(mat(I,I), mat(I,J)).norm();
|
||||
if((IsOdd && res[0]<Scalar(0)) || ((!IsOdd) && res[0]>Scalar(0))) {
|
||||
res[0] = (res[0] > Scalar(0)) ? res[0] - Scalar(EIGEN_PI) : res[0] + Scalar(EIGEN_PI);
|
||||
res[1] = atan2(-mat(I,K), -c2);
|
||||
}
|
||||
else
|
||||
res[1] = atan2(-mat(I,K), c2);
|
||||
Scalar s1 = sin(res[0]);
|
||||
Scalar c1 = cos(res[0]);
|
||||
res[2] = atan2(s1*mat(K,I)-c1*mat(J,I), c1*mat(J,J) - s1 * mat(K,J));
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
static void CalcEulerAngles_imp(Matrix<typename MatrixBase<Derived>::Scalar,3,1>& res, const MatrixBase<Derived>& mat, internal::false_type /*isTaitBryan*/)
|
||||
{
|
||||
using std::atan2;
|
||||
using std::sin;
|
||||
using std::cos;
|
||||
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
typedef Matrix<Scalar,2,1> Vector2;
|
||||
|
||||
res[0] = atan2(mat(J,I), mat(K,I));
|
||||
if((IsOdd && res[0]<Scalar(0)) || ((!IsOdd) && res[0]>Scalar(0)))
|
||||
{
|
||||
res[0] = (res[0] > Scalar(0)) ? res[0] - Scalar(EIGEN_PI) : res[0] + Scalar(EIGEN_PI);
|
||||
Scalar s2 = Vector2(mat(J,I), mat(K,I)).norm();
|
||||
res[1] = -atan2(s2, mat(I,I));
|
||||
}
|
||||
else
|
||||
{
|
||||
Scalar s2 = Vector2(mat(J,I), mat(K,I)).norm();
|
||||
res[1] = atan2(s2, mat(I,I));
|
||||
}
|
||||
|
||||
// With a=(0,1,0), we have i=0; j=1; k=2, and after computing the first two angles,
|
||||
// we can compute their respective rotation, and apply its inverse to M. Since the result must
|
||||
// be a rotation around x, we have:
|
||||
//
|
||||
// c2 s1.s2 c1.s2 1 0 0
|
||||
// 0 c1 -s1 * M = 0 c3 s3
|
||||
// -s2 s1.c2 c1.c2 0 -s3 c3
|
||||
//
|
||||
// Thus: m11.c1 - m21.s1 = c3 & m12.c1 - m22.s1 = s3
|
||||
|
||||
Scalar s1 = sin(res[0]);
|
||||
Scalar c1 = cos(res[0]);
|
||||
res[2] = atan2(c1*mat(J,K)-s1*mat(K,K), c1*mat(J,J) - s1 * mat(K,J));
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
static void CalcEulerAngles(
|
||||
EulerAngles<Scalar, EulerSystem>& res,
|
||||
const typename EulerAngles<Scalar, EulerSystem>::Matrix3& mat)
|
||||
{
|
||||
CalcEulerAngles(res, mat, false, false, false);
|
||||
}
|
||||
|
||||
template<
|
||||
bool PositiveRangeAlpha,
|
||||
bool PositiveRangeBeta,
|
||||
bool PositiveRangeGamma,
|
||||
typename Scalar>
|
||||
static void CalcEulerAngles(
|
||||
EulerAngles<Scalar, EulerSystem>& res,
|
||||
const typename EulerAngles<Scalar, EulerSystem>::Matrix3& mat)
|
||||
{
|
||||
CalcEulerAngles(res, mat, PositiveRangeAlpha, PositiveRangeBeta, PositiveRangeGamma);
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
static void CalcEulerAngles(
|
||||
EulerAngles<Scalar, EulerSystem>& res,
|
||||
const typename EulerAngles<Scalar, EulerSystem>::Matrix3& mat,
|
||||
bool PositiveRangeAlpha,
|
||||
bool PositiveRangeBeta,
|
||||
bool PositiveRangeGamma)
|
||||
{
|
||||
CalcEulerAngles_imp(
|
||||
res.angles(), mat,
|
||||
typename internal::conditional<IsTaitBryan, internal::true_type, internal::false_type>::type());
|
||||
|
||||
if (IsAlphaOpposite == IsOdd)
|
||||
res.alpha() = -res.alpha();
|
||||
|
||||
if (IsBetaOpposite == IsOdd)
|
||||
res.beta() = -res.beta();
|
||||
|
||||
if (IsGammaOpposite == IsOdd)
|
||||
res.gamma() = -res.gamma();
|
||||
|
||||
// Saturate results to the requested range
|
||||
if (PositiveRangeAlpha && (res.alpha() < 0))
|
||||
res.alpha() += Scalar(2 * EIGEN_PI);
|
||||
|
||||
if (PositiveRangeBeta && (res.beta() < 0))
|
||||
res.beta() += Scalar(2 * EIGEN_PI);
|
||||
|
||||
if (PositiveRangeGamma && (res.gamma() < 0))
|
||||
res.gamma() += Scalar(2 * EIGEN_PI);
|
||||
}
|
||||
|
||||
template <typename _Scalar, class _System>
|
||||
friend class Eigen::EulerAngles;
|
||||
};
|
||||
|
||||
#define EIGEN_EULER_SYSTEM_TYPEDEF(A, B, C) \
|
||||
/** \ingroup EulerAngles_Module */ \
|
||||
typedef EulerSystem<EULER_##A, EULER_##B, EULER_##C> EulerSystem##A##B##C;
|
||||
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(X,Y,Z)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(X,Y,X)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(X,Z,Y)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(X,Z,X)
|
||||
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Y,Z,X)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Y,Z,Y)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Y,X,Z)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Y,X,Y)
|
||||
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Z,X,Y)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Z,X,Z)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Z,Y,X)
|
||||
EIGEN_EULER_SYSTEM_TYPEDEF(Z,Y,Z)
|
||||
}
|
||||
|
||||
#endif // EIGEN_EULERSYSTEM_H
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_FFT_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_FFT_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/FFT COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_IterativeSolvers_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_IterativeSolvers_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/IterativeSolvers COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_KroneckerProduct_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_KroneckerProduct_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/KroneckerProduct COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_LevenbergMarquardt_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_LevenbergMarquardt_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/LevenbergMarquardt COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_MatrixFunctions_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_MatrixFunctions_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MatrixFunctions COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_MoreVectorization_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_MoreVectorization_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/MoreVectorization COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_NonLinearOptimization_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_NonLinearOptimization_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NonLinearOptimization COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_NumericalDiff_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_NumericalDiff_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/NumericalDiff COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_Polynomials_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_Polynomials_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Polynomials COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_Skyline_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_Skyline_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Skyline COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_SparseExtra_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_SparseExtra_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/SparseExtra COMPONENT Devel
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
FILE(GLOB Eigen_SpecialFunctions_SRCS "*.h")
|
||||
INSTALL(FILES
|
||||
${Eigen_SpecialFunctions_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/SpecialFunctions COMPONENT Devel
|
||||
)
|
||||
|
||||
FILE(GLOB Eigen_SpecialFunctions_arch_CUDA_SRCS "arch/CUDA/*.h")
|
||||
INSTALL(FILES
|
||||
${Eigen_SpecialFunctions_arch_CUDA_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/SpecialFunctions/arch/CUDA COMPONENT Devel
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB Eigen_Splines_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_Splines_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/src/Splines COMPONENT Devel
|
||||
)
|
||||
Reference in New Issue
Block a user