aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Benoit Steiner <benoit.steiner.goog@gmail.com>2016-11-26 11:28:25 -0800
committerGravatar Benoit Steiner <benoit.steiner.goog@gmail.com>2016-11-26 11:28:25 -0800
commit9f8fbd9434a604e54fee59460cbd13fe629299fa (patch)
treeafebfa832e8f978df9710eb0d6da8efae3672a2f
parent7318daf887c4f06fa62e59e29fa675e48ad168f9 (diff)
parent67b2c41f30a29debcb720fe85c2581901ff36fd2 (diff)
Merged eigen/eigen into default
-rw-r--r--Eigen/src/Core/arch/AVX/PacketMath.h7
-rwxr-xr-xEigen/src/Core/arch/SSE/PacketMath.h42
-rwxr-xr-xEigen/src/Core/util/DisableStupidWarnings.h3
-rw-r--r--Eigen/src/SparseCore/SparseBlock.h12
-rw-r--r--Eigen/src/SparseCore/SparseCwiseBinaryOp.h52
-rw-r--r--doc/PreprocessorDirectives.dox24
-rw-r--r--test/sparse_block.cpp27
-rw-r--r--unsupported/Eigen/CXX11/src/Tensor/README.md8
-rw-r--r--unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h2
-rw-r--r--unsupported/Eigen/CXX11/src/util/CXX11Meta.h4
-rw-r--r--unsupported/Eigen/src/EulerAngles/EulerAngles.h257
-rw-r--r--unsupported/Eigen/src/EulerAngles/EulerSystem.h184
-rw-r--r--unsupported/Eigen/src/Polynomials/Companion.h50
-rw-r--r--unsupported/Eigen/src/Polynomials/PolynomialSolver.h18
-rw-r--r--unsupported/doc/examples/EulerAngles.cpp4
-rw-r--r--unsupported/test/EulerAngles.cpp296
-rw-r--r--unsupported/test/polynomialsolver.cpp34
17 files changed, 549 insertions, 475 deletions
diff --git a/Eigen/src/Core/arch/AVX/PacketMath.h b/Eigen/src/Core/arch/AVX/PacketMath.h
index e60ef307b..195d40fb4 100644
--- a/Eigen/src/Core/arch/AVX/PacketMath.h
+++ b/Eigen/src/Core/arch/AVX/PacketMath.h
@@ -395,14 +395,11 @@ template<> EIGEN_STRONG_INLINE Packet4d preduxp<Packet4d>(const Packet4d* vecs)
template<> EIGEN_STRONG_INLINE float predux<Packet8f>(const Packet8f& a)
{
- Packet8f tmp0 = _mm256_hadd_ps(a,_mm256_permute2f128_ps(a,a,1));
- tmp0 = _mm256_hadd_ps(tmp0,tmp0);
- return pfirst(_mm256_hadd_ps(tmp0, tmp0));
+ return predux(Packet4f(_mm_add_ps(_mm256_castps256_ps128(a),_mm256_extractf128_ps(a,1))));
}
template<> EIGEN_STRONG_INLINE double predux<Packet4d>(const Packet4d& a)
{
- Packet4d tmp0 = _mm256_hadd_pd(a,_mm256_permute2f128_pd(a,a,1));
- return pfirst(_mm256_hadd_pd(tmp0,tmp0));
+ return predux(Packet2d(_mm_add_pd(_mm256_castpd256_pd128(a),_mm256_extractf128_pd(a,1))));
}
template<> EIGEN_STRONG_INLINE Packet4f predux_downto4<Packet8f>(const Packet8f& a)
diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h
index 6f31cf12b..80cf8af09 100755
--- a/Eigen/src/Core/arch/SSE/PacketMath.h
+++ b/Eigen/src/Core/arch/SSE/PacketMath.h
@@ -504,30 +504,13 @@ template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
{
return _mm_hadd_ps(_mm_hadd_ps(vecs[0], vecs[1]),_mm_hadd_ps(vecs[2], vecs[3]));
}
+
template<> EIGEN_STRONG_INLINE Packet2d preduxp<Packet2d>(const Packet2d* vecs)
{
return _mm_hadd_pd(vecs[0], vecs[1]);
}
-template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
-{
- Packet4f tmp0 = _mm_hadd_ps(a,a);
- return pfirst<Packet4f>(_mm_hadd_ps(tmp0, tmp0));
-}
-
-template<> EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a) { return pfirst<Packet2d>(_mm_hadd_pd(a, a)); }
#else
-// SSE2 versions
-template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
-{
- Packet4f tmp = _mm_add_ps(a, _mm_movehl_ps(a,a));
- return pfirst<Packet4f>(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
-}
-template<> EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a)
-{
- return pfirst<Packet2d>(_mm_add_sd(a, _mm_unpackhi_pd(a,a)));
-}
-
template<> EIGEN_STRONG_INLINE Packet4f preduxp<Packet4f>(const Packet4f* vecs)
{
Packet4f tmp0, tmp1, tmp2;
@@ -548,6 +531,29 @@ template<> EIGEN_STRONG_INLINE Packet2d preduxp<Packet2d>(const Packet2d* vecs)
}
#endif // SSE3
+template<> EIGEN_STRONG_INLINE float predux<Packet4f>(const Packet4f& a)
+{
+ // Disable SSE3 _mm_hadd_pd that is extremely slow on all existing Intel's architectures
+ // (from Nehalem to Haswell)
+// #ifdef EIGEN_VECTORIZE_SSE3
+// Packet4f tmp = _mm_add_ps(a, vec4f_swizzle1(a,2,3,2,3));
+// return pfirst<Packet4f>(_mm_hadd_ps(tmp, tmp));
+// #else
+ Packet4f tmp = _mm_add_ps(a, _mm_movehl_ps(a,a));
+ return pfirst<Packet4f>(_mm_add_ss(tmp, _mm_shuffle_ps(tmp,tmp, 1)));
+// #endif
+}
+
+template<> EIGEN_STRONG_INLINE double predux<Packet2d>(const Packet2d& a)
+{
+ // Disable SSE3 _mm_hadd_pd that is extremely slow on all existing Intel's architectures
+ // (from Nehalem to Haswell)
+// #ifdef EIGEN_VECTORIZE_SSE3
+// return pfirst<Packet2d>(_mm_hadd_pd(a, a));
+// #else
+ return pfirst<Packet2d>(_mm_add_sd(a, _mm_unpackhi_pd(a,a)));
+// #endif
+}
#ifdef EIGEN_VECTORIZE_SSSE3
template<> EIGEN_STRONG_INLINE Packet4i preduxp<Packet4i>(const Packet4i* vecs)
diff --git a/Eigen/src/Core/util/DisableStupidWarnings.h b/Eigen/src/Core/util/DisableStupidWarnings.h
index 7559e129c..21f80d86b 100755
--- a/Eigen/src/Core/util/DisableStupidWarnings.h
+++ b/Eigen/src/Core/util/DisableStupidWarnings.h
@@ -42,6 +42,9 @@
#pragma clang diagnostic push
#endif
#pragma clang diagnostic ignored "-Wconstant-logical-operand"
+ #if __clang_major__ >= 3 && __clang_minor__ >= 5
+ #pragma clang diagnostic ignored "-Wabsolute-value"
+ #endif
#elif defined __GNUC__ && __GNUC__>=6
diff --git a/Eigen/src/SparseCore/SparseBlock.h b/Eigen/src/SparseCore/SparseBlock.h
index 13e8b0bf1..acaf933f4 100644
--- a/Eigen/src/SparseCore/SparseBlock.h
+++ b/Eigen/src/SparseCore/SparseBlock.h
@@ -130,7 +130,7 @@ public:
// 2 - let's check whether there is enough allocated memory
Index nnz = tmp.nonZeros();
- Index start = m_outerStart==0 ? 0 : matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block
+ Index start = m_outerStart==0 ? 0 : m_matrix.outerIndexPtr()[m_outerStart]; // starting position of the current block
Index end = m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]; // ending position of the current block
Index block_size = end - start; // available room in the current block
Index tail_size = m_matrix.outerIndexPtr()[m_matrix.outerSize()] - end;
@@ -139,6 +139,8 @@ public:
? Index(matrix.data().allocatedSize()) + block_size
: block_size;
+ Index tmp_start = tmp.outerIndexPtr()[0];
+
bool update_trailing_pointers = false;
if(nnz>free_size)
{
@@ -148,8 +150,8 @@ public:
internal::smart_copy(m_matrix.valuePtr(), m_matrix.valuePtr() + start, newdata.valuePtr());
internal::smart_copy(m_matrix.innerIndexPtr(), m_matrix.innerIndexPtr() + start, newdata.indexPtr());
- internal::smart_copy(tmp.valuePtr(), tmp.valuePtr() + nnz, newdata.valuePtr() + start);
- internal::smart_copy(tmp.innerIndexPtr(), tmp.innerIndexPtr() + nnz, newdata.indexPtr() + start);
+ internal::smart_copy(tmp.valuePtr() + tmp_start, tmp.valuePtr() + tmp_start + nnz, newdata.valuePtr() + start);
+ internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz, newdata.indexPtr() + start);
internal::smart_copy(matrix.valuePtr()+end, matrix.valuePtr()+end + tail_size, newdata.valuePtr()+start+nnz);
internal::smart_copy(matrix.innerIndexPtr()+end, matrix.innerIndexPtr()+end + tail_size, newdata.indexPtr()+start+nnz);
@@ -173,8 +175,8 @@ public:
update_trailing_pointers = true;
}
- internal::smart_copy(tmp.valuePtr(), tmp.valuePtr() + nnz, matrix.valuePtr() + start);
- internal::smart_copy(tmp.innerIndexPtr(), tmp.innerIndexPtr() + nnz, matrix.innerIndexPtr() + start);
+ internal::smart_copy(tmp.valuePtr() + tmp_start, tmp.valuePtr() + tmp_start + nnz, matrix.valuePtr() + start);
+ internal::smart_copy(tmp.innerIndexPtr() + tmp_start, tmp.innerIndexPtr() + tmp_start + nnz, matrix.innerIndexPtr() + start);
}
// update outer index pointers and innerNonZeros
diff --git a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
index 04cef66fc..4ba4d631d 100644
--- a/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
+++ b/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
@@ -394,10 +394,10 @@ struct sparse_conjunction_evaluator<XprType, IteratorBased, IteratorBased>
{
protected:
typedef typename XprType::Functor BinaryOp;
- typedef typename XprType::Lhs Lhs;
- typedef typename XprType::Rhs Rhs;
- typedef typename evaluator<Lhs>::InnerIterator LhsIterator;
- typedef typename evaluator<Rhs>::InnerIterator RhsIterator;
+ typedef typename XprType::Lhs LhsArg;
+ typedef typename XprType::Rhs RhsArg;
+ typedef typename evaluator<LhsArg>::InnerIterator LhsIterator;
+ typedef typename evaluator<RhsArg>::InnerIterator RhsIterator;
typedef typename XprType::StorageIndex StorageIndex;
typedef typename traits<XprType>::Scalar Scalar;
public:
@@ -449,7 +449,7 @@ public:
enum {
- CoeffReadCost = evaluator<Lhs>::CoeffReadCost + evaluator<Rhs>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
+ CoeffReadCost = evaluator<LhsArg>::CoeffReadCost + evaluator<RhsArg>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
Flags = XprType::Flags
};
@@ -468,8 +468,8 @@ public:
protected:
const BinaryOp m_functor;
- evaluator<Lhs> m_lhsImpl;
- evaluator<Rhs> m_rhsImpl;
+ evaluator<LhsArg> m_lhsImpl;
+ evaluator<RhsArg> m_rhsImpl;
};
// "dense ^ sparse"
@@ -479,10 +479,10 @@ struct sparse_conjunction_evaluator<XprType, IndexBased, IteratorBased>
{
protected:
typedef typename XprType::Functor BinaryOp;
- typedef typename XprType::Lhs Lhs;
- typedef typename XprType::Rhs Rhs;
- typedef evaluator<Lhs> LhsEvaluator;
- typedef typename evaluator<Rhs>::InnerIterator RhsIterator;
+ typedef typename XprType::Lhs LhsArg;
+ typedef typename XprType::Rhs RhsArg;
+ typedef evaluator<LhsArg> LhsEvaluator;
+ typedef typename evaluator<RhsArg>::InnerIterator RhsIterator;
typedef typename XprType::StorageIndex StorageIndex;
typedef typename traits<XprType>::Scalar Scalar;
public:
@@ -490,7 +490,7 @@ public:
class ReverseInnerIterator;
class InnerIterator
{
- enum { IsRowMajor = (int(Rhs::Flags)&RowMajorBit)==RowMajorBit };
+ enum { IsRowMajor = (int(RhsArg::Flags)&RowMajorBit)==RowMajorBit };
public:
@@ -522,9 +522,9 @@ public:
enum {
- CoeffReadCost = evaluator<Lhs>::CoeffReadCost + evaluator<Rhs>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
+ CoeffReadCost = evaluator<LhsArg>::CoeffReadCost + evaluator<RhsArg>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
// Expose storage order of the sparse expression
- Flags = (XprType::Flags & ~RowMajorBit) | (int(Rhs::Flags)&RowMajorBit)
+ Flags = (XprType::Flags & ~RowMajorBit) | (int(RhsArg::Flags)&RowMajorBit)
};
explicit sparse_conjunction_evaluator(const XprType& xpr)
@@ -542,8 +542,8 @@ public:
protected:
const BinaryOp m_functor;
- evaluator<Lhs> m_lhsImpl;
- evaluator<Rhs> m_rhsImpl;
+ evaluator<LhsArg> m_lhsImpl;
+ evaluator<RhsArg> m_rhsImpl;
};
// "sparse ^ dense"
@@ -553,10 +553,10 @@ struct sparse_conjunction_evaluator<XprType, IteratorBased, IndexBased>
{
protected:
typedef typename XprType::Functor BinaryOp;
- typedef typename XprType::Lhs Lhs;
- typedef typename XprType::Rhs Rhs;
- typedef typename evaluator<Lhs>::InnerIterator LhsIterator;
- typedef evaluator<Rhs> RhsEvaluator;
+ typedef typename XprType::Lhs LhsArg;
+ typedef typename XprType::Rhs RhsArg;
+ typedef typename evaluator<LhsArg>::InnerIterator LhsIterator;
+ typedef evaluator<RhsArg> RhsEvaluator;
typedef typename XprType::StorageIndex StorageIndex;
typedef typename traits<XprType>::Scalar Scalar;
public:
@@ -564,7 +564,7 @@ public:
class ReverseInnerIterator;
class InnerIterator
{
- enum { IsRowMajor = (int(Lhs::Flags)&RowMajorBit)==RowMajorBit };
+ enum { IsRowMajor = (int(LhsArg::Flags)&RowMajorBit)==RowMajorBit };
public:
@@ -590,16 +590,16 @@ public:
protected:
LhsIterator m_lhsIter;
- const evaluator<Rhs> &m_rhsEval;
+ const evaluator<RhsArg> &m_rhsEval;
const BinaryOp& m_functor;
const Index m_outer;
};
enum {
- CoeffReadCost = evaluator<Lhs>::CoeffReadCost + evaluator<Rhs>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
+ CoeffReadCost = evaluator<LhsArg>::CoeffReadCost + evaluator<RhsArg>::CoeffReadCost + functor_traits<BinaryOp>::Cost,
// Expose storage order of the sparse expression
- Flags = (XprType::Flags & ~RowMajorBit) | (int(Lhs::Flags)&RowMajorBit)
+ Flags = (XprType::Flags & ~RowMajorBit) | (int(LhsArg::Flags)&RowMajorBit)
};
explicit sparse_conjunction_evaluator(const XprType& xpr)
@@ -617,8 +617,8 @@ public:
protected:
const BinaryOp m_functor;
- evaluator<Lhs> m_lhsImpl;
- evaluator<Rhs> m_rhsImpl;
+ evaluator<LhsArg> m_lhsImpl;
+ evaluator<RhsArg> m_rhsImpl;
};
}
diff --git a/doc/PreprocessorDirectives.dox b/doc/PreprocessorDirectives.dox
index 2f9c4c370..c4b9903c1 100644
--- a/doc/PreprocessorDirectives.dox
+++ b/doc/PreprocessorDirectives.dox
@@ -97,31 +97,35 @@ run time. However, these assertions do cost time and can thus be turned off.
\section TopicPreprocessorDirectivesPerformance Alignment, vectorization and performance tweaking
- - \b EIGEN_MALLOC_ALREADY_ALIGNED - Can be set to 0 or 1 to tell whether default system \c malloc already
+ - \b \c EIGEN_MALLOC_ALREADY_ALIGNED - Can be set to 0 or 1 to tell whether default system \c malloc already
returns aligned buffers. In not defined, then this information is automatically deduced from the compiler
and system preprocessor tokens.
- - \b EIGEN_DONT_ALIGN - disables alignment completely. %Eigen will not try to align its objects and does not
- expect that any objects passed to it are aligned. This will turn off vectorization. Not defined by default.
- - \b EIGEN_DONT_ALIGN_STATICALLY - disables alignment of arrays on the stack. Not defined by default, unless
- \c EIGEN_DONT_ALIGN is defined.
- - \b EIGEN_DONT_PARALLELIZE - if defined, this disables multi-threading. This is only relevant if you enabled OpenMP.
+ - \b \c EIGEN_MAX_ALIGN_BYTES - Must be a power of two, or 0. Defines an upper bound on the memory boundary in bytes on which dynamically and statically allocated data may be aligned by %Eigen. If not defined, a default value is automatically computed based on architecture, compiler, and OS.
+ This option is typically used to enforce binary compatibility between code/libraries compiled with different SIMD options. For instance, one may compile AVX code and enforce ABI compatibility with existing SSE code by defining \c EIGEN_MAX_ALIGN_BYTES=16. In the other way round, since by default AVX implies 32 bytes alignment for best performance, one can compile SSE code to be ABI compatible with AVX code by defining \c EIGEN_MAX_ALIGN_BYTES=32.
+ - \b \c EIGEN_MAX_STATIC_ALIGN_BYTES - Same as \c EIGEN_MAX_ALIGN_BYTES but for statically allocated data only. By default, if only \c EIGEN_MAX_ALIGN_BYTES is defined, then \c EIGEN_MAX_STATIC_ALIGN_BYTES == \c EIGEN_MAX_ALIGN_BYTES, otherwise a default value is automatically computed based on architecture, compiler, and OS (can be smaller than the default value of EIGEN_MAX_ALIGN_BYTES on architectures that do not support stack alignment).
+ Let us emphasize that \c EIGEN_MAX_*_ALIGN_BYTES define only a diserable upper bound. In practice data is aligned to largest power-of-two common divisor of \c EIGEN_MAX_STATIC_ALIGN_BYTES and the size of the data, such that memory is not wasted.
+ - \b \c EIGEN_DONT_PARALLELIZE - if defined, this disables multi-threading. This is only relevant if you enabled OpenMP.
See \ref TopicMultiThreading for details.
- \b EIGEN_DONT_VECTORIZE - disables explicit vectorization when defined. Not defined by default, unless
alignment is disabled by %Eigen's platform test or the user defining \c EIGEN_DONT_ALIGN.
- - \b EIGEN_UNALIGNED_VECTORIZE - disables/enables vectorization with unaligned stores. Default is 1 (enabled).
+ - \b \c EIGEN_UNALIGNED_VECTORIZE - disables/enables vectorization with unaligned stores. Default is 1 (enabled).
If set to 0 (disabled), then expression for which the destination cannot be aligned are not vectorized (e.g., unaligned
small fixed size vectors or matrices)
- - \b EIGEN_FAST_MATH - enables some optimizations which might affect the accuracy of the result. This currently
+ - \b \c EIGEN_FAST_MATH - enables some optimizations which might affect the accuracy of the result. This currently
enables the SSE vectorization of sin() and cos(), and speedups sqrt() for single precision. Defined to 1 by default.
Define it to 0 to disable.
- - \b EIGEN_UNROLLING_LIMIT - defines the size of a loop to enable meta unrolling. Set it to zero to disable
+ - \b \c EIGEN_UNROLLING_LIMIT - defines the size of a loop to enable meta unrolling. Set it to zero to disable
unrolling. The size of a loop here is expressed in %Eigen's own notion of "number of FLOPS", it does not
correspond to the number of iterations or the number of instructions. The default is value 100.
- - \b EIGEN_STACK_ALLOCATION_LIMIT - defines the maximum bytes for a buffer to be allocated on the stack. For internal
+ - \b \c EIGEN_STACK_ALLOCATION_LIMIT - defines the maximum bytes for a buffer to be allocated on the stack. For internal
temporary buffers, dynamic memory allocation is employed as a fall back. For fixed-size matrices or arrays, exceeding
this threshold raises a compile time assertion. Use 0 to set no limit. Default is 128 KB.
+ - \c EIGEN_DONT_ALIGN - Deprecated, it is a synonym for \c EIGEN_MAX_ALIGN_BYTES=0. It disables alignment completely. %Eigen will not try to align its objects and does not expect that any objects passed to it are aligned. This will turn off vectorization if \b EIGEN_UNALIGNED_VECTORIZE=1. Not defined by default.
+ - \c EIGEN_DONT_ALIGN_STATICALLY - Deprecated, it is a synonym for \c EIGEN_MAX_STATIC_ALIGN_BYTES=0. It disables alignment of arrays on the stack. Not defined by default, unless \c EIGEN_DONT_ALIGN is defined.
+
+
\section TopicPreprocessorDirectivesPlugins Plugins
It is possible to add new methods to many fundamental classes in %Eigen by writing a plugin. As explained in
diff --git a/test/sparse_block.cpp b/test/sparse_block.cpp
index 49a5f135e..cb5213ade 100644
--- a/test/sparse_block.cpp
+++ b/test/sparse_block.cpp
@@ -223,6 +223,33 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
VERIFY_IS_APPROX(m2.block(r0,c0,r1,c1), refMat2.block(r0,c0,r1,c1));
VERIFY_IS_APPROX((2*m2).block(r0,c0,r1,c1), (2*refMat2).block(r0,c0,r1,c1));
+
+ if(m2.nonZeros()>0)
+ {
+ VERIFY_IS_APPROX(m2, refMat2);
+ SparseMatrixType m3(rows, cols);
+ DenseMatrix refMat3(rows, cols); refMat3.setZero();
+ Index n = internal::random<Index>(1,10);
+ for(Index k=0; k<n; ++k)
+ {
+ Index o1 = internal::random<Index>(0,outer-1);
+ Index o2 = internal::random<Index>(0,outer-1);
+ if(SparseMatrixType::IsRowMajor)
+ {
+ m3.innerVector(o1) = m2.row(o2);
+ refMat3.row(o1) = refMat2.row(o2);
+ }
+ else
+ {
+ m3.innerVector(o1) = m2.col(o2);
+ refMat3.col(o1) = refMat2.col(o2);
+ }
+ if(internal::random<bool>())
+ m3.makeCompressed();
+ }
+ if(m3.nonZeros()>0)
+ VERIFY_IS_APPROX(m3, refMat3);
+ }
}
}
diff --git a/unsupported/Eigen/CXX11/src/Tensor/README.md b/unsupported/Eigen/CXX11/src/Tensor/README.md
index 02146527b..fbb7f3bfc 100644
--- a/unsupported/Eigen/CXX11/src/Tensor/README.md
+++ b/unsupported/Eigen/CXX11/src/Tensor/README.md
@@ -1737,11 +1737,9 @@ TODO
## Representation of scalar values
-Scalar values are often represented by tensors of size 1 and rank 1. It would be
-more logical and user friendly to use tensors of rank 0 instead. For example
-Tensor<T, N>::maximum() currently returns a Tensor<T, 1>. Similarly, the inner
-product of 2 1d tensors (through contractions) returns a 1d tensor. In the
-future these operations might be updated to return 0d tensors instead.
+Scalar values are often represented by tensors of size 1 and rank 0.For example
+Tensor<T, N>::maximum() currently returns a Tensor<T, 0>. Similarly, the inner
+product of 2 1d tensors (through contractions) returns a 0d tensor.
## Limitations
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h
index ca45b542e..ff604bf54 100644
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h
+++ b/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h
@@ -33,7 +33,7 @@ namespace Eigen {
namespace internal {
template<std::size_t n, typename Dimension> struct dget {
- static const std::size_t value = get<n, Dimension>::value;
+ static const std::ptrdiff_t value = get<n, Dimension>::value;
};
diff --git a/unsupported/Eigen/CXX11/src/util/CXX11Meta.h b/unsupported/Eigen/CXX11/src/util/CXX11Meta.h
index ec27eddb8..63c2a1def 100644
--- a/unsupported/Eigen/CXX11/src/util/CXX11Meta.h
+++ b/unsupported/Eigen/CXX11/src/util/CXX11Meta.h
@@ -123,6 +123,10 @@ template<typename a, typename... as> struct get<0, type_lis
template<typename T, int n, T a, T... as> struct get<n, numeric_list<T, a, as...>> : get<n-1, numeric_list<T, as...>> {};
template<typename T, T a, T... as> struct get<0, numeric_list<T, a, as...>> { constexpr static T value = a; };
+template<std::size_t n, typename T, T a, T... as> constexpr inline const T array_get(const numeric_list<T, a, as...>& l) {
+ return get<(int)n, numeric_list<T, a, as...>>::value;
+}
+
/* always get type, regardless of dummy; good for parameter pack expansion */
template<typename T, T dummy, typename t> struct id_numeric { typedef t type; };
diff --git a/unsupported/Eigen/src/EulerAngles/EulerAngles.h b/unsupported/Eigen/src/EulerAngles/EulerAngles.h
index 13a0da1ab..a5d034d71 100644
--- a/unsupported/Eigen/src/EulerAngles/EulerAngles.h
+++ b/unsupported/Eigen/src/EulerAngles/EulerAngles.h
@@ -12,11 +12,6 @@
namespace Eigen
{
- /*template<typename Other,
- int OtherRows=Other::RowsAtCompileTime,
- int OtherCols=Other::ColsAtCompileTime>
- struct ei_eulerangles_assign_impl;*/
-
/** \class EulerAngles
*
* \ingroup EulerAngles_Module
@@ -36,7 +31,7 @@ namespace Eigen
* ### 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).
+ * by Euler angles, but there is no single 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).
*
@@ -55,33 +50,27 @@ namespace Eigen
* Additionally, some axes related computation is done in compile time.
*
* #### Euler angles ranges in conversions ####
+ * Rotations representation as EulerAngles are not single (unlike matrices),
+ * and even have infinite EulerAngles representations.<BR>
+ * For example, add or subtract 2*PI from either angle of EulerAngles
+ * and you'll get the same rotation.
+ * This is the general reason for infinite representation,
+ * but it's not the only general reason for not having a single representation.
*
- * When converting some rotation to Euler angles, there are some ways you can guarantee
- * the Euler angles ranges.
+ * When converting rotation to EulerAngles, this class convert it to specific ranges
+ * When converting some rotation to EulerAngles, the rules for ranges are as follow:
+ * - If the rotation we converting from is an EulerAngles
+ * (even when it represented as RotationBase explicitly), angles ranges are __undefined__.
+ * - otherwise, alpha and gamma angles will be in the range [-PI, PI].<BR>
+ * As for Beta angle:
+ * - If the system is Tait-Bryan, the beta angle will be in the range [-PI/2, PI/2].
+ * - otherwise:
+ * - If the beta axis is positive, the beta angle will be in the range [0, PI]
+ * - If the beta axis is negative, the beta angle will be in the range [-PI, 0]
*
- * #### 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,
@@ -103,7 +92,7 @@ namespace Eigen
*
* 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 _Scalar the scalar type, i.e. the type of the angles.
*
* \tparam _System the EulerSystem to use, which represents the axes of rotation.
*/
@@ -111,8 +100,11 @@ namespace Eigen
class EulerAngles : public RotationBase<EulerAngles<_Scalar, _System>, 3>
{
public:
+ typedef RotationBase<EulerAngles<_Scalar, _System>, 3> Base;
+
/** the scalar type of the angles */
typedef _Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
/** the EulerSystem to use, which represents the axes of rotation. */
typedef _System System;
@@ -146,67 +138,56 @@ namespace Eigen
public:
/** Default constructor without initialization. */
EulerAngles() {}
- /** Constructs and initialize Euler angles(\p alpha, \p beta, \p gamma). */
+ /** Constructs and initialize an EulerAngles (\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; }
+ // TODO: Test this constructor
+ /** Constructs and initialize an EulerAngles from the array data {alpha, beta, gamma} */
+ explicit EulerAngles(const Scalar* data) : m_angles(data) {}
- /** 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].
+ /** Constructs and initializes an EulerAngles from either:
+ * - a 3x3 rotation matrix expression(i.e. pure orthogonal matrix with determinant of +1),
+ * - a 3D vector expression representing Euler angles.
*
- * \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].
- */
+ * \note If \p other is a 3x3 rotation matrix, the angles range rules will be as follow:<BR>
+ * Alpha and gamma angles will be in the range [-PI, PI].<BR>
+ * As for Beta angle:
+ * - If the system is Tait-Bryan, the beta angle will be in the range [-PI/2, PI/2].
+ * - otherwise:
+ * - If the beta axis is positive, the beta angle will be in the range [0, PI]
+ * - If the beta axis is negative, the beta angle will be in the range [-PI, 0]
+ */
template<typename Derived>
- EulerAngles(
- const MatrixBase<Derived>& m,
- bool positiveRangeAlpha,
- bool positiveRangeBeta,
- bool positiveRangeGamma) {
-
- System::CalcEulerAngles(*this, m, positiveRangeAlpha, positiveRangeBeta, positiveRangeGamma);
- }
+ explicit EulerAngles(const MatrixBase<Derived>& other) { *this = other; }
/** 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)
+ * \note If \p rot is an EulerAngles (even when it represented as RotationBase explicitly),
+ * angles ranges are __undefined__.
+ * Otherwise, alpha and gamma angles will be in the range [-PI, PI].<BR>
+ * As for Beta angle:
+ * - If the system is Tait-Bryan, the beta angle will be in the range [-PI/2, PI/2].
+ * - otherwise:
+ * - If the beta axis is positive, the beta angle will be in the range [0, PI]
+ * - If the beta axis is negative, the beta angle will be in the range [-PI, 0]
*/
template<typename Derived>
- EulerAngles(const RotationBase<Derived, 3>& rot) { *this = rot; }
+ EulerAngles(const RotationBase<Derived, 3>& rot) { System::CalcEulerAngles(*this, rot.toRotationMatrix()); }
- /** 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);
- }
+ /*EulerAngles(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)));
+ }*/
/** \returns The angle values stored in a vector (alpha, beta, gamma). */
const Vector3& angles() const { return m_angles; }
@@ -246,90 +227,48 @@ namespace Eigen
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__).
+ /** Set \c *this from either:
+ * - a 3x3 rotation matrix expression(i.e. pure orthogonal matrix with determinant of +1),
+ * - a 3D vector expression representing Euler angles.
*
- * 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].
+ * See EulerAngles(const MatrixBase<Derived, 3>&) for more information about
+ * angles ranges output.
*/
- 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)
+ template<class Derived>
+ EulerAngles& operator=(const MatrixBase<Derived>& other)
{
- // 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)
+ EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename Derived::Scalar>::value),
+ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
- System::CalcEulerAngles(*this, m);
+ internal::eulerangles_assign_impl<System, Derived>::run(*this, other.derived());
return *this;
}
// TODO: Assign and construct from another EulerAngles (with different system)
- /** Set \c *this from a rotation. */
+ /** Set \c *this from a rotation.
+ *
+ * See EulerAngles(const RotationBase<Derived, 3>&) for more information about
+ * angles ranges output.
+ */
template<typename Derived>
EulerAngles& operator=(const RotationBase<Derived, 3>& rot) {
System::CalcEulerAngles(*this, rot.toRotationMatrix());
return *this;
}
- // TODO: Support isApprox function
+ /** \returns \c true if \c *this is approximately equal to \a other, within the precision
+ * determined by \a prec.
+ *
+ * \sa MatrixBase::isApprox() */
+ bool isApprox(const EulerAngles& other,
+ const RealScalar& prec = NumTraits<Scalar>::dummy_precision()) const
+ { return angles().isApprox(other.angles(), prec); }
/** \returns an equivalent 3x3 rotation matrix. */
Matrix3 toRotationMatrix() const
{
+ // TODO: Calc it faster
return static_cast<QuaternionType>(*this).toRotationMatrix();
}
@@ -347,6 +286,15 @@ namespace Eigen
s << eulerAngles.angles().transpose();
return s;
}
+
+ /** \returns \c *this with scalar type casted to \a NewScalarType */
+ template <typename NewScalarType>
+ EulerAngles<NewScalarType, System> cast() const
+ {
+ EulerAngles<NewScalarType, System> e;
+ e.angles() = angles().template cast<NewScalarType>();
+ return e;
+ }
};
#define EIGEN_EULER_ANGLES_SINGLE_TYPEDEF(AXES, SCALAR_TYPE, SCALAR_POSTFIX) \
@@ -379,8 +327,29 @@ EIGEN_EULER_ANGLES_TYPEDEFS(double, d)
{
typedef _Scalar Scalar;
};
+
+ // set from a rotation matrix
+ template<class System, class Other>
+ struct eulerangles_assign_impl<System,Other,3,3>
+ {
+ typedef typename Other::Scalar Scalar;
+ static void run(EulerAngles<Scalar, System>& e, const Other& m)
+ {
+ System::CalcEulerAngles(e, m);
+ }
+ };
+
+ // set from a vector of Euler angles
+ template<class System, class Other>
+ struct eulerangles_assign_impl<System,Other,4,1>
+ {
+ typedef typename Other::Scalar Scalar;
+ static void run(EulerAngles<Scalar, System>& e, const Other& vec)
+ {
+ e.angles() = vec;
+ }
+ };
}
-
}
#endif // EIGEN_EULERANGLESCLASS_H
diff --git a/unsupported/Eigen/src/EulerAngles/EulerSystem.h b/unsupported/Eigen/src/EulerAngles/EulerSystem.h
index 98f9f647d..28f52da61 100644
--- a/unsupported/Eigen/src/EulerAngles/EulerSystem.h
+++ b/unsupported/Eigen/src/EulerAngles/EulerSystem.h
@@ -18,7 +18,7 @@ namespace Eigen
namespace internal
{
- // TODO: Check if already exists on the rest API
+ // TODO: Add this trait to the Eigen internal API?
template <int Num, bool IsPositive = (Num > 0)>
struct Abs
{
@@ -36,6 +36,12 @@ namespace Eigen
{
enum { value = Axis != 0 && Abs<Axis>::value <= 3 };
};
+
+ template<typename System,
+ typename Other,
+ int OtherRows=Other::RowsAtCompileTime,
+ int OtherCols=Other::ColsAtCompileTime>
+ struct eulerangles_assign_impl;
}
#define EIGEN_EULER_ANGLES_CLASS_STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
@@ -69,7 +75,7 @@ namespace Eigen
*
* 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)
+ * - 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)
@@ -80,7 +86,7 @@ namespace Eigen
* 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).
+ * - 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:
@@ -90,7 +96,7 @@ namespace Eigen
* 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}
+ * - _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}
*
@@ -112,9 +118,9 @@ namespace Eigen
*
* \tparam _AlphaAxis the first fixed EulerAxis
*
- * \tparam _AlphaAxis the second fixed EulerAxis
+ * \tparam _BetaAxis the second fixed EulerAxis
*
- * \tparam _AlphaAxis the third fixed EulerAxis
+ * \tparam _GammaAxis the third fixed EulerAxis
*/
template <int _AlphaAxis, int _BetaAxis, int _GammaAxis>
class EulerSystem
@@ -138,14 +144,16 @@ namespace Eigen
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 */
+ IsAlphaOpposite = (AlphaAxis < 0) ? 1 : 0, /*!< whether alpha axis is negative */
+ IsBetaOpposite = (BetaAxis < 0) ? 1 : 0, /*!< whether beta axis is negative */
+ IsGammaOpposite = (GammaAxis < 0) ? 1 : 0, /*!< whether gamma axis is negative */
+
+ // Parity is even if alpha axis X is followed by beta axis Y, or Y is followed
+ // by Z, or Z is followed by X; otherwise it is odd.
+ IsOdd = ((AlphaAxisAbs)%3 == (BetaAxisAbs - 1)%3) ? 0 : 1, /*!< whether the Euler system is odd */
+ IsEven = IsOdd ? 0 : 1, /*!< whether the Euler system is even */
- IsTaitBryan = ((unsigned)AlphaAxisAbs != (unsigned)GammaAxisAbs) ? 1 : 0 /*!< weather the Euler system is tait bryan */
+ IsTaitBryan = ((unsigned)AlphaAxisAbs != (unsigned)GammaAxisAbs) ? 1 : 0 /*!< whether the Euler system is Tait-Bryan */
};
private:
@@ -180,71 +188,70 @@ namespace Eigen
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;
+ using std::sqrt;
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))) {
- if(res[0] > Scalar(0)) {
- res[0] -= Scalar(EIGEN_PI);
- }
- else {
- res[0] += Scalar(EIGEN_PI);
- }
- res[1] = atan2(-mat(I,K), -c2);
+
+ const Scalar plusMinus = IsEven? 1 : -1;
+ const Scalar minusPlus = IsOdd? 1 : -1;
+
+ const Scalar Rsum = sqrt((mat(I,I) * mat(I,I) + mat(I,J) * mat(I,J) + mat(J,K) * mat(J,K) + mat(K,K) * mat(K,K))/2);
+ res[1] = atan2(plusMinus * mat(I,K), Rsum);
+
+ // There is a singularity when cos(beta) == 0
+ if(Rsum > 4 * NumTraits<Scalar>::epsilon()) {// cos(beta) != 0
+ res[0] = atan2(minusPlus * mat(J, K), mat(K, K));
+ res[2] = atan2(minusPlus * mat(I, J), mat(I, I));
+ }
+ else if(plusMinus * mat(I, K) > 0) {// cos(beta) == 0 and sin(beta) == 1
+ Scalar spos = mat(J, I) + plusMinus * mat(K, J); // 2*sin(alpha + plusMinus * gamma
+ Scalar cpos = mat(J, J) + minusPlus * mat(K, I); // 2*cos(alpha + plusMinus * gamma)
+ Scalar alphaPlusMinusGamma = atan2(spos, cpos);
+ res[0] = alphaPlusMinusGamma;
+ res[2] = 0;
+ }
+ else {// cos(beta) == 0 and sin(beta) == -1
+ Scalar sneg = plusMinus * (mat(K, J) + minusPlus * mat(J, I)); // 2*sin(alpha + minusPlus*gamma)
+ Scalar cneg = mat(J, J) + plusMinus * mat(K, I); // 2*cos(alpha + minusPlus*gamma)
+ Scalar alphaMinusPlusBeta = atan2(sneg, cneg);
+ res[0] = alphaMinusPlusBeta;
+ res[2] = 0;
}
- 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*/)
+ 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;
+ using std::sqrt;
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)))
- {
- if(res[0] > Scalar(0)) {
- res[0] -= Scalar(EIGEN_PI);
- }
- else {
- 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
+ const Scalar plusMinus = IsEven? 1 : -1;
+ const Scalar minusPlus = IsOdd? 1 : -1;
+
+ const Scalar Rsum = sqrt((mat(I, J) * mat(I, J) + mat(I, K) * mat(I, K) + mat(J, I) * mat(J, I) + mat(K, I) * mat(K, I)) / 2);
- 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));
+ res[1] = atan2(Rsum, mat(I, I));
+
+ // There is a singularity when sin(beta) == 0
+ if(Rsum > 4 * NumTraits<Scalar>::epsilon()) {// sin(beta) != 0
+ res[0] = atan2(mat(J, I), minusPlus * mat(K, I));
+ res[2] = atan2(mat(I, J), plusMinus * mat(I, K));
+ }
+ else if(mat(I, I) > 0) {// sin(beta) == 0 and cos(beta) == 1
+ Scalar spos = plusMinus * mat(K, J) + minusPlus * mat(J, K); // 2*sin(alpha + gamma)
+ Scalar cpos = mat(J, J) + mat(K, K); // 2*cos(alpha + gamma)
+ res[0] = atan2(spos, cpos);
+ res[2] = 0;
+ }
+ else {// sin(beta) == 0 and cos(beta) == -1
+ Scalar sneg = plusMinus * mat(K, J) + plusMinus * mat(J, K); // 2*sin(alpha - gamma)
+ Scalar cneg = mat(J, J) - mat(K, K); // 2*cos(alpha - gamma)
+ res[0] = atan2(sneg, cneg);
+ res[2] = 0;
+ }
}
template<typename Scalar>
@@ -252,55 +259,28 @@ namespace Eigen
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)
+ if (IsAlphaOpposite)
res.alpha() = -res.alpha();
- if (IsBetaOpposite == IsOdd)
+ if (IsBetaOpposite)
res.beta() = -res.beta();
- if (IsGammaOpposite == IsOdd)
+ if (IsGammaOpposite)
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;
+
+ template<typename System,
+ typename Other,
+ int OtherRows,
+ int OtherCols>
+ friend struct internal::eulerangles_assign_impl;
};
#define EIGEN_EULER_SYSTEM_TYPEDEF(A, B, C) \
diff --git a/unsupported/Eigen/src/Polynomials/Companion.h b/unsupported/Eigen/src/Polynomials/Companion.h
index b515c2920..e0af6ebe4 100644
--- a/unsupported/Eigen/src/Polynomials/Companion.h
+++ b/unsupported/Eigen/src/Polynomials/Companion.h
@@ -75,7 +75,7 @@ class companion
void setPolynomial( const VectorType& poly )
{
const Index deg = poly.size()-1;
- m_monic = -1/poly[deg] * poly.head(deg);
+ m_monic = Scalar(-1)/poly[deg] * poly.head(deg);
//m_bl_diag.setIdentity( deg-1 );
m_bl_diag.setOnes(deg-1);
}
@@ -107,8 +107,8 @@ class companion
* colB and rowB are repectively the multipliers for
* the column and the row in order to balance them.
* */
- bool balanced( Scalar colNorm, Scalar rowNorm,
- bool& isBalanced, Scalar& colB, Scalar& rowB );
+ bool balanced( RealScalar colNorm, RealScalar rowNorm,
+ bool& isBalanced, RealScalar& colB, RealScalar& rowB );
/** Helper function for the balancing algorithm.
* \returns true if the row and the column, having colNorm and rowNorm
@@ -116,8 +116,8 @@ class companion
* colB and rowB are repectively the multipliers for
* the column and the row in order to balance them.
* */
- bool balancedR( Scalar colNorm, Scalar rowNorm,
- bool& isBalanced, Scalar& colB, Scalar& rowB );
+ bool balancedR( RealScalar colNorm, RealScalar rowNorm,
+ bool& isBalanced, RealScalar& colB, RealScalar& rowB );
public:
/**
@@ -139,10 +139,10 @@ class companion
template< typename _Scalar, int _Deg >
inline
-bool companion<_Scalar,_Deg>::balanced( Scalar colNorm, Scalar rowNorm,
- bool& isBalanced, Scalar& colB, Scalar& rowB )
+bool companion<_Scalar,_Deg>::balanced( RealScalar colNorm, RealScalar rowNorm,
+ bool& isBalanced, RealScalar& colB, RealScalar& rowB )
{
- if( Scalar(0) == colNorm || Scalar(0) == rowNorm ){ return true; }
+ if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm ){ return true; }
else
{
//To find the balancing coefficients, if the radix is 2,
@@ -150,29 +150,29 @@ bool companion<_Scalar,_Deg>::balanced( Scalar colNorm, Scalar rowNorm,
// \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
// then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
// and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
- rowB = rowNorm / radix<Scalar>();
- colB = Scalar(1);
- const Scalar s = colNorm + rowNorm;
+ rowB = rowNorm / radix<RealScalar>();
+ colB = RealScalar(1);
+ const RealScalar s = colNorm + rowNorm;
while (colNorm < rowB)
{
- colB *= radix<Scalar>();
- colNorm *= radix2<Scalar>();
+ colB *= radix<RealScalar>();
+ colNorm *= radix2<RealScalar>();
}
- rowB = rowNorm * radix<Scalar>();
+ rowB = rowNorm * radix<RealScalar>();
while (colNorm >= rowB)
{
- colB /= radix<Scalar>();
- colNorm /= radix2<Scalar>();
+ colB /= radix<RealScalar>();
+ colNorm /= radix2<RealScalar>();
}
//This line is used to avoid insubstantial balancing
- if ((rowNorm + colNorm) < Scalar(0.95) * s * colB)
+ if ((rowNorm + colNorm) < RealScalar(0.95) * s * colB)
{
isBalanced = false;
- rowB = Scalar(1) / colB;
+ rowB = RealScalar(1) / colB;
return false;
}
else{
@@ -182,21 +182,21 @@ bool companion<_Scalar,_Deg>::balanced( Scalar colNorm, Scalar rowNorm,
template< typename _Scalar, int _Deg >
inline
-bool companion<_Scalar,_Deg>::balancedR( Scalar colNorm, Scalar rowNorm,
- bool& isBalanced, Scalar& colB, Scalar& rowB )
+bool companion<_Scalar,_Deg>::balancedR( RealScalar colNorm, RealScalar rowNorm,
+ bool& isBalanced, RealScalar& colB, RealScalar& rowB )
{
- if( Scalar(0) == colNorm || Scalar(0) == rowNorm ){ return true; }
+ if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm ){ return true; }
else
{
/**
* Set the norm of the column and the row to the geometric mean
* of the row and column norm
*/
- const _Scalar q = colNorm/rowNorm;
+ const RealScalar q = colNorm/rowNorm;
if( !isApprox( q, _Scalar(1) ) )
{
rowB = sqrt( colNorm/rowNorm );
- colB = Scalar(1)/rowB;
+ colB = RealScalar(1)/rowB;
isBalanced = false;
return false;
@@ -219,8 +219,8 @@ void companion<_Scalar,_Deg>::balance()
while( !hasConverged )
{
hasConverged = true;
- Scalar colNorm,rowNorm;
- Scalar colB,rowB;
+ RealScalar colNorm,rowNorm;
+ RealScalar colB,rowB;
//First row, first column excluding the diagonal
//==============================================
diff --git a/unsupported/Eigen/src/Polynomials/PolynomialSolver.h b/unsupported/Eigen/src/Polynomials/PolynomialSolver.h
index 03198ec8e..788594247 100644
--- a/unsupported/Eigen/src/Polynomials/PolynomialSolver.h
+++ b/unsupported/Eigen/src/Polynomials/PolynomialSolver.h
@@ -99,7 +99,7 @@ class PolynomialSolverBase
*/
inline const RootType& greatestRoot() const
{
- std::greater<Scalar> greater;
+ std::greater<RealScalar> greater;
return selectComplexRoot_withRespectToNorm( greater );
}
@@ -108,7 +108,7 @@ class PolynomialSolverBase
*/
inline const RootType& smallestRoot() const
{
- std::less<Scalar> less;
+ std::less<RealScalar> less;
return selectComplexRoot_withRespectToNorm( less );
}
@@ -213,7 +213,7 @@ class PolynomialSolverBase
bool& hasArealRoot,
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
{
- std::greater<Scalar> greater;
+ std::greater<RealScalar> greater;
return selectRealRoot_withRespectToAbsRealPart( greater, hasArealRoot, absImaginaryThreshold );
}
@@ -236,7 +236,7 @@ class PolynomialSolverBase
bool& hasArealRoot,
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
{
- std::less<Scalar> less;
+ std::less<RealScalar> less;
return selectRealRoot_withRespectToAbsRealPart( less, hasArealRoot, absImaginaryThreshold );
}
@@ -259,7 +259,7 @@ class PolynomialSolverBase
bool& hasArealRoot,
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
{
- std::greater<Scalar> greater;
+ std::greater<RealScalar> greater;
return selectRealRoot_withRespectToRealPart( greater, hasArealRoot, absImaginaryThreshold );
}
@@ -282,7 +282,7 @@ class PolynomialSolverBase
bool& hasArealRoot,
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
{
- std::less<Scalar> less;
+ std::less<RealScalar> less;
return selectRealRoot_withRespectToRealPart( less, hasArealRoot, absImaginaryThreshold );
}
@@ -327,7 +327,7 @@ class PolynomialSolverBase
* However, almost always, correct accuracy is reached even in these cases for 64bit
* (double) floating types and small polynomial degree (<20).
*/
-template< typename _Scalar, int _Deg >
+template<typename _Scalar, int _Deg>
class PolynomialSolver : public PolynomialSolverBase<_Scalar,_Deg>
{
public:
@@ -337,7 +337,9 @@ class PolynomialSolver : public PolynomialSolverBase<_Scalar,_Deg>
EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
typedef Matrix<Scalar,_Deg,_Deg> CompanionMatrixType;
- typedef EigenSolver<CompanionMatrixType> EigenSolverType;
+ typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
+ ComplexEigenSolver<CompanionMatrixType>,
+ EigenSolver<CompanionMatrixType> >::type EigenSolverType;
public:
/** Computes the complex roots of a new polynomial. */
diff --git a/unsupported/doc/examples/EulerAngles.cpp b/unsupported/doc/examples/EulerAngles.cpp
index 1ef6aee18..3f8ca8c17 100644
--- a/unsupported/doc/examples/EulerAngles.cpp
+++ b/unsupported/doc/examples/EulerAngles.cpp
@@ -23,7 +23,7 @@ int main()
// Some Euler angles representation that our plane use.
EulerAnglesZYZd planeAngles(0.78474, 0.5271, -0.513794);
- MyArmyAngles planeAnglesInMyArmyAngles = MyArmyAngles::FromRotation<true, false, false>(planeAngles);
+ MyArmyAngles planeAnglesInMyArmyAngles(planeAngles);
std::cout << "vehicle angles(MyArmy): " << vehicleAngles << std::endl;
std::cout << "plane angles(ZYZ): " << planeAngles << std::endl;
@@ -37,7 +37,7 @@ int main()
Quaterniond planeRotated = AngleAxisd(-0.342, Vector3d::UnitY()) * planeAngles;
planeAngles = planeRotated;
- planeAnglesInMyArmyAngles = MyArmyAngles::FromRotation<true, false, false>(planeRotated);
+ planeAnglesInMyArmyAngles = planeRotated;
std::cout << "new plane angles(ZYZ): " << planeAngles << std::endl;
std::cout << "new plane angles(MyArmy): " << planeAnglesInMyArmyAngles << std::endl;
diff --git a/unsupported/test/EulerAngles.cpp b/unsupported/test/EulerAngles.cpp
index a8cb52864..79ee72847 100644
--- a/unsupported/test/EulerAngles.cpp
+++ b/unsupported/test/EulerAngles.cpp
@@ -13,146 +13,219 @@
using namespace Eigen;
-template<typename EulerSystem, typename Scalar>
-void verify_euler_ranged(const Matrix<Scalar,3,1>& ea,
- bool positiveRangeAlpha, bool positiveRangeBeta, bool positiveRangeGamma)
+// Unfortunately, we need to specialize it in order to work. (We could add it in main.h test framework)
+template <typename Scalar, class System>
+bool verifyIsApprox(const Eigen::EulerAngles<Scalar, System>& a, const Eigen::EulerAngles<Scalar, System>& b)
+{
+ return verifyIsApprox(a.angles(), b.angles());
+}
+
+// Verify that x is in the approxed range [a, b]
+#define VERIFY_APPROXED_RANGE(a, x, b) \
+ do { \
+ VERIFY_IS_APPROX_OR_LESS_THAN(a, x); \
+ VERIFY_IS_APPROX_OR_LESS_THAN(x, b); \
+ } while(0)
+
+const char X = EULER_X;
+const char Y = EULER_Y;
+const char Z = EULER_Z;
+
+template<typename Scalar, class EulerSystem>
+void verify_euler(const EulerAngles<Scalar, EulerSystem>& e)
{
typedef EulerAngles<Scalar, EulerSystem> EulerAnglesType;
typedef Matrix<Scalar,3,3> Matrix3;
typedef Matrix<Scalar,3,1> Vector3;
typedef Quaternion<Scalar> QuaternionType;
typedef AngleAxis<Scalar> AngleAxisType;
- using std::abs;
-
- Scalar alphaRangeStart, alphaRangeEnd;
- Scalar betaRangeStart, betaRangeEnd;
- Scalar gammaRangeStart, gammaRangeEnd;
- if (positiveRangeAlpha)
- {
- alphaRangeStart = Scalar(0);
- alphaRangeEnd = Scalar(2 * EIGEN_PI);
- }
- else
- {
- alphaRangeStart = -Scalar(EIGEN_PI);
- alphaRangeEnd = Scalar(EIGEN_PI);
- }
+ const Scalar ONE = Scalar(1);
+ const Scalar HALF_PI = Scalar(EIGEN_PI / 2);
+ const Scalar PI = Scalar(EIGEN_PI);
- if (positiveRangeBeta)
- {
- betaRangeStart = Scalar(0);
- betaRangeEnd = Scalar(2 * EIGEN_PI);
- }
- else
- {
- betaRangeStart = -Scalar(EIGEN_PI);
- betaRangeEnd = Scalar(EIGEN_PI);
- }
+ // It's very important calc the acceptable precision depending on the distance from the pole.
+ const Scalar longitudeRadius = std::abs(
+ EulerSystem::IsTaitBryan ?
+ std::cos(e.beta()) :
+ std::sin(e.beta())
+ );
+ Scalar precision = test_precision<Scalar>() / longitudeRadius;
- if (positiveRangeGamma)
+ Scalar betaRangeStart, betaRangeEnd;
+ if (EulerSystem::IsTaitBryan)
{
- gammaRangeStart = Scalar(0);
- gammaRangeEnd = Scalar(2 * EIGEN_PI);
+ betaRangeStart = -HALF_PI;
+ betaRangeEnd = HALF_PI;
}
else
{
- gammaRangeStart = -Scalar(EIGEN_PI);
- gammaRangeEnd = Scalar(EIGEN_PI);
+ if (!EulerSystem::IsBetaOpposite)
+ {
+ betaRangeStart = 0;
+ betaRangeEnd = PI;
+ }
+ else
+ {
+ betaRangeStart = -PI;
+ betaRangeEnd = 0;
+ }
}
- const int i = EulerSystem::AlphaAxisAbs - 1;
- const int j = EulerSystem::BetaAxisAbs - 1;
- const int k = EulerSystem::GammaAxisAbs - 1;
-
- const int iFactor = EulerSystem::IsAlphaOpposite ? -1 : 1;
- const int jFactor = EulerSystem::IsBetaOpposite ? -1 : 1;
- const int kFactor = EulerSystem::IsGammaOpposite ? -1 : 1;
-
const Vector3 I = EulerAnglesType::AlphaAxisVector();
const Vector3 J = EulerAnglesType::BetaAxisVector();
const Vector3 K = EulerAnglesType::GammaAxisVector();
- EulerAnglesType e(ea[0], ea[1], ea[2]);
+ // Is approx checks
+ VERIFY(e.isApprox(e));
+ VERIFY_IS_APPROX(e, e);
+ VERIFY_IS_NOT_APPROX(e, EulerAnglesType(e.alpha() + ONE, e.beta() + ONE, e.gamma() + ONE));
+
+ const Matrix3 m(e);
+ VERIFY_IS_APPROX(Scalar(m.determinant()), ONE);
+
+ EulerAnglesType ebis(m);
- Matrix3 m(e);
- Vector3 eabis = EulerAnglesType(m, positiveRangeAlpha, positiveRangeBeta, positiveRangeGamma).angles();
+ // When no roll(acting like polar representation), we have the best precision.
+ // One of those cases is when the Euler angles are on the pole, and because it's singular case,
+ // the computation returns no roll.
+ if (ebis.beta() == 0)
+ precision = test_precision<Scalar>();
// Check that eabis in range
- VERIFY(alphaRangeStart <= eabis[0] && eabis[0] <= alphaRangeEnd);
- VERIFY(betaRangeStart <= eabis[1] && eabis[1] <= betaRangeEnd);
- VERIFY(gammaRangeStart <= eabis[2] && eabis[2] <= gammaRangeEnd);
+ VERIFY_APPROXED_RANGE(-PI, ebis.alpha(), PI);
+ VERIFY_APPROXED_RANGE(betaRangeStart, ebis.beta(), betaRangeEnd);
+ VERIFY_APPROXED_RANGE(-PI, ebis.gamma(), PI);
+
+ const Matrix3 mbis(AngleAxisType(ebis.alpha(), I) * AngleAxisType(ebis.beta(), J) * AngleAxisType(ebis.gamma(), K));
+ VERIFY_IS_APPROX(Scalar(mbis.determinant()), ONE);
+ VERIFY_IS_APPROX(mbis, ebis.toRotationMatrix());
+ /*std::cout << "===================\n" <<
+ "e: " << e << std::endl <<
+ "eabis: " << eabis.transpose() << std::endl <<
+ "m: " << m << std::endl <<
+ "mbis: " << mbis << std::endl <<
+ "X: " << (m * Vector3::UnitX()).transpose() << std::endl <<
+ "X: " << (mbis * Vector3::UnitX()).transpose() << std::endl;*/
+ VERIFY(m.isApprox(mbis, precision));
+
+ // Test if ea and eabis are the same
+ // Need to check both singular and non-singular cases
+ // There are two singular cases.
+ // 1. When I==K and sin(ea(1)) == 0
+ // 2. When I!=K and cos(ea(1)) == 0
+
+ // TODO: Make this test work well, and use range saturation function.
+ /*// If I==K, and ea[1]==0, then there no unique solution.
+ // The remark apply in the case where I!=K, and |ea[1]| is close to +-pi/2.
+ if( (i!=k || ea[1]!=0) && (i==k || !internal::isApprox(abs(ea[1]),Scalar(EIGEN_PI/2),test_precision<Scalar>())) )
+ VERIFY_IS_APPROX(ea, eabis);*/
- Vector3 eabis2 = m.eulerAngles(i, j, k);
+ // Quaternions
+ const QuaternionType q(e);
+ ebis = q;
+ const QuaternionType qbis(ebis);
+ VERIFY(internal::isApprox<Scalar>(std::abs(q.dot(qbis)), ONE, precision));
+ //VERIFY_IS_APPROX(eabis, eabis2);// Verify that the euler angles are still the same
- // Invert the relevant axes
- eabis2[0] *= iFactor;
- eabis2[1] *= jFactor;
- eabis2[2] *= kFactor;
+ // A suggestion for simple product test when will be supported.
+ /*EulerAnglesType e2(PI/2, PI/2, PI/2);
+ Matrix3 m2(e2);
+ VERIFY_IS_APPROX(e*e2, m*m2);*/
+}
+
+template<signed char A, signed char B, signed char C, typename Scalar>
+void verify_euler_vec(const Matrix<Scalar,3,1>& ea)
+{
+ verify_euler(EulerAngles<Scalar, EulerSystem<A, B, C> >(ea[0], ea[1], ea[2]));
+}
+
+template<signed char A, signed char B, signed char C, typename Scalar>
+void verify_euler_all_neg(const Matrix<Scalar,3,1>& ea)
+{
+ verify_euler_vec<+A,+B,+C>(ea);
+ verify_euler_vec<+A,+B,-C>(ea);
+ verify_euler_vec<+A,-B,+C>(ea);
+ verify_euler_vec<+A,-B,-C>(ea);
- // Saturate the angles to the correct range
- if (positiveRangeAlpha && (eabis2[0] < 0))
- eabis2[0] += Scalar(2 * EIGEN_PI);
- if (positiveRangeBeta && (eabis2[1] < 0))
- eabis2[1] += Scalar(2 * EIGEN_PI);
- if (positiveRangeGamma && (eabis2[2] < 0))
- eabis2[2] += Scalar(2 * EIGEN_PI);
+ verify_euler_vec<-A,+B,+C>(ea);
+ verify_euler_vec<-A,+B,-C>(ea);
+ verify_euler_vec<-A,-B,+C>(ea);
+ verify_euler_vec<-A,-B,-C>(ea);
+}
+
+template<typename Scalar> void check_all_var(const Matrix<Scalar,3,1>& ea)
+{
+ verify_euler_all_neg<X,Y,Z>(ea);
+ verify_euler_all_neg<X,Y,X>(ea);
+ verify_euler_all_neg<X,Z,Y>(ea);
+ verify_euler_all_neg<X,Z,X>(ea);
- VERIFY_IS_APPROX(eabis, eabis2);// Verify that our estimation is the same as m.eulerAngles() is
+ verify_euler_all_neg<Y,Z,X>(ea);
+ verify_euler_all_neg<Y,Z,Y>(ea);
+ verify_euler_all_neg<Y,X,Z>(ea);
+ verify_euler_all_neg<Y,X,Y>(ea);
- Matrix3 mbis(AngleAxisType(eabis[0], I) * AngleAxisType(eabis[1], J) * AngleAxisType(eabis[2], K));
- VERIFY_IS_APPROX(m, mbis);
+ verify_euler_all_neg<Z,X,Y>(ea);
+ verify_euler_all_neg<Z,X,Z>(ea);
+ verify_euler_all_neg<Z,Y,X>(ea);
+ verify_euler_all_neg<Z,Y,Z>(ea);
+}
+
+template<typename Scalar> void check_singular_cases(const Scalar& singularBeta)
+{
+ typedef Matrix<Scalar,3,1> Vector3;
+ const Scalar PI = Scalar(EIGEN_PI);
- // Tests that are only relevant for no possitive range
- if (!(positiveRangeAlpha || positiveRangeBeta || positiveRangeGamma))
+ for (Scalar epsilon = NumTraits<Scalar>::epsilon(); epsilon < 1; epsilon *= Scalar(1.2))
{
- /* If I==K, and ea[1]==0, then there no unique solution. */
- /* The remark apply in the case where I!=K, and |ea[1]| is close to pi/2. */
- if( (i!=k || ea[1]!=0) && (i==k || !internal::isApprox(abs(ea[1]),Scalar(EIGEN_PI/2),test_precision<Scalar>())) )
- VERIFY((ea-eabis).norm() <= test_precision<Scalar>());
-
- // approx_or_less_than does not work for 0
- VERIFY(0 < eabis[0] || test_isMuchSmallerThan(eabis[0], Scalar(1)));
+ check_all_var(Vector3(PI/4, singularBeta, PI/3));
+ check_all_var(Vector3(PI/4, singularBeta - epsilon, PI/3));
+ check_all_var(Vector3(PI/4, singularBeta - Scalar(1.5)*epsilon, PI/3));
+ check_all_var(Vector3(PI/4, singularBeta - 2*epsilon, PI/3));
+ check_all_var(Vector3(PI*Scalar(0.8), singularBeta - epsilon, Scalar(0.9)*PI));
+ check_all_var(Vector3(PI*Scalar(-0.9), singularBeta + epsilon, PI*Scalar(0.3)));
+ check_all_var(Vector3(PI*Scalar(-0.6), singularBeta + Scalar(1.5)*epsilon, PI*Scalar(0.3)));
+ check_all_var(Vector3(PI*Scalar(-0.5), singularBeta + 2*epsilon, PI*Scalar(0.4)));
+ check_all_var(Vector3(PI*Scalar(0.9), singularBeta + epsilon, Scalar(0.8)*PI));
}
- // Quaternions
- QuaternionType q(e);
- eabis = EulerAnglesType(q, positiveRangeAlpha, positiveRangeBeta, positiveRangeGamma).angles();
- VERIFY_IS_APPROX(eabis, eabis2);// Verify that the euler angles are still the same
+ // This one for sanity, it had a problem with near pole cases in float scalar.
+ check_all_var(Vector3(PI*Scalar(0.8), singularBeta - Scalar(1E-6), Scalar(0.9)*PI));
}
-template<typename EulerSystem, typename Scalar>
-void verify_euler(const Matrix<Scalar,3,1>& ea)
+template<typename Scalar> void eulerangles_manual()
{
- verify_euler_ranged<EulerSystem>(ea, false, false, false);
- verify_euler_ranged<EulerSystem>(ea, false, false, true);
- verify_euler_ranged<EulerSystem>(ea, false, true, false);
- verify_euler_ranged<EulerSystem>(ea, false, true, true);
- verify_euler_ranged<EulerSystem>(ea, true, false, false);
- verify_euler_ranged<EulerSystem>(ea, true, false, true);
- verify_euler_ranged<EulerSystem>(ea, true, true, false);
- verify_euler_ranged<EulerSystem>(ea, true, true, true);
-}
-
-template<typename Scalar> void check_all_var(const Matrix<Scalar,3,1>& ea)
-{
- verify_euler<EulerSystemXYZ>(ea);
- verify_euler<EulerSystemXYX>(ea);
- verify_euler<EulerSystemXZY>(ea);
- verify_euler<EulerSystemXZX>(ea);
-
- verify_euler<EulerSystemYZX>(ea);
- verify_euler<EulerSystemYZY>(ea);
- verify_euler<EulerSystemYXZ>(ea);
- verify_euler<EulerSystemYXY>(ea);
-
- verify_euler<EulerSystemZXY>(ea);
- verify_euler<EulerSystemZXZ>(ea);
- verify_euler<EulerSystemZYX>(ea);
- verify_euler<EulerSystemZYZ>(ea);
+ typedef Matrix<Scalar,3,1> Vector3;
+ const Vector3 Zero = Vector3::Zero();
+ const Scalar PI = Scalar(EIGEN_PI);
+
+ check_all_var(Zero);
+
+ // singular cases
+ check_singular_cases(PI/2);
+ check_singular_cases(-PI/2);
+
+ check_singular_cases(Scalar(0));
+ check_singular_cases(Scalar(-0));
+
+ check_singular_cases(PI);
+ check_singular_cases(-PI);
+
+ // non-singular cases
+ VectorXd alpha = VectorXd::LinSpaced(Eigen::Sequential, 20, Scalar(-0.99) * PI, PI);
+ VectorXd beta = VectorXd::LinSpaced(Eigen::Sequential, 20, Scalar(-0.49) * PI, Scalar(0.49) * PI);
+ VectorXd gamma = VectorXd::LinSpaced(Eigen::Sequential, 20, Scalar(-0.99) * PI, PI);
+ for (int i = 0; i < alpha.size(); ++i) {
+ for (int j = 0; j < beta.size(); ++j) {
+ for (int k = 0; k < gamma.size(); ++k) {
+ check_all_var(Vector3d(alpha(i), beta(j), gamma(k)));
+ }
+ }
+ }
}
-template<typename Scalar> void eulerangles()
+template<typename Scalar> void eulerangles_rand()
{
typedef Matrix<Scalar,3,3> Matrix3;
typedef Matrix<Scalar,3,1> Vector3;
@@ -201,8 +274,19 @@ template<typename Scalar> void eulerangles()
void test_EulerAngles()
{
+ // Simple cast test
+ EulerAnglesXYZd onesEd(1, 1, 1);
+ EulerAnglesXYZf onesEf = onesEd.cast<float>();
+ VERIFY_IS_APPROX(onesEd, onesEf.cast<double>());
+
+ CALL_SUBTEST_1( eulerangles_manual<float>() );
+ CALL_SUBTEST_2( eulerangles_manual<double>() );
+
for(int i = 0; i < g_repeat; i++) {
- CALL_SUBTEST_1( eulerangles<float>() );
- CALL_SUBTEST_2( eulerangles<double>() );
+ CALL_SUBTEST_3( eulerangles_rand<float>() );
+ CALL_SUBTEST_4( eulerangles_rand<double>() );
}
+
+ // TODO: Add tests for auto diff
+ // TODO: Add tests for complex numbers
}
diff --git a/unsupported/test/polynomialsolver.cpp b/unsupported/test/polynomialsolver.cpp
index 0c87478dd..7ad4aa69d 100644
--- a/unsupported/test/polynomialsolver.cpp
+++ b/unsupported/test/polynomialsolver.cpp
@@ -32,9 +32,10 @@ bool aux_evalSolver( const POLYNOMIAL& pols, SOLVER& psolve )
{
typedef typename POLYNOMIAL::Index Index;
typedef typename POLYNOMIAL::Scalar Scalar;
+ typedef typename POLYNOMIAL::RealScalar RealScalar;
typedef typename SOLVER::RootsType RootsType;
- typedef Matrix<Scalar,Deg,1> EvalRootsType;
+ typedef Matrix<RealScalar,Deg,1> EvalRootsType;
const Index deg = pols.size()-1;
@@ -57,7 +58,7 @@ bool aux_evalSolver( const POLYNOMIAL& pols, SOLVER& psolve )
cerr << endl;
}
- std::vector<Scalar> rootModuli( roots.size() );
+ std::vector<RealScalar> rootModuli( roots.size() );
Map< EvalRootsType > aux( &rootModuli[0], roots.size() );
aux = roots.array().abs();
std::sort( rootModuli.begin(), rootModuli.end() );
@@ -83,7 +84,7 @@ void evalSolver( const POLYNOMIAL& pols )
{
typedef typename POLYNOMIAL::Scalar Scalar;
- typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
+ typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
PolynomialSolverType psolve;
aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( pols, psolve );
@@ -97,6 +98,7 @@ void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const
{
using std::sqrt;
typedef typename POLYNOMIAL::Scalar Scalar;
+ typedef typename POLYNOMIAL::RealScalar RealScalar;
typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
@@ -107,15 +109,12 @@ void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const
// 1) the roots found are correct
// 2) the roots have distinct moduli
- typedef typename POLYNOMIAL::Scalar Scalar;
- typedef typename REAL_ROOTS::Scalar Real;
-
//Test realRoots
- std::vector< Real > calc_realRoots;
- psolve.realRoots( calc_realRoots );
- VERIFY( calc_realRoots.size() == (size_t)real_roots.size() );
+ std::vector< RealScalar > calc_realRoots;
+ psolve.realRoots( calc_realRoots, test_precision<RealScalar>());
+ VERIFY_IS_EQUAL( calc_realRoots.size() , (size_t)real_roots.size() );
- const Scalar psPrec = sqrt( test_precision<Scalar>() );
+ const RealScalar psPrec = sqrt( test_precision<RealScalar>() );
for( size_t i=0; i<calc_realRoots.size(); ++i )
{
@@ -138,7 +137,7 @@ void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const
bool hasRealRoot;
//Test absGreatestRealRoot
- Real r = psolve.absGreatestRealRoot( hasRealRoot );
+ RealScalar r = psolve.absGreatestRealRoot( hasRealRoot );
VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
if( hasRealRoot ){
VERIFY( internal::isApprox( real_roots.array().abs().maxCoeff(), abs(r), psPrec ) ); }
@@ -167,9 +166,11 @@ void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const
template<typename _Scalar, int _Deg>
void polynomialsolver(int deg)
{
- typedef internal::increment_if_fixed_size<_Deg> Dim;
+ typedef typename NumTraits<_Scalar>::Real RealScalar;
+ typedef internal::increment_if_fixed_size<_Deg> Dim;
typedef Matrix<_Scalar,Dim::ret,1> PolynomialType;
typedef Matrix<_Scalar,_Deg,1> EvalRootsType;
+ typedef Matrix<RealScalar,_Deg,1> RealRootsType;
cout << "Standard cases" << endl;
PolynomialType pols = PolynomialType::Random(deg+1);
@@ -182,15 +183,11 @@ void polynomialsolver(int deg)
evalSolver<_Deg,PolynomialType>( pols );
cout << "Test sugar" << endl;
- EvalRootsType realRoots = EvalRootsType::Random(deg);
+ RealRootsType realRoots = RealRootsType::Random(deg);
roots_to_monicPolynomial( realRoots, pols );
evalSolverSugarFunction<_Deg>(
pols,
- realRoots.template cast <
- std::complex<
- typename NumTraits<_Scalar>::Real
- >
- >(),
+ realRoots.template cast <std::complex<RealScalar> >().eval(),
realRoots );
}
@@ -214,5 +211,6 @@ void test_polynomialsolver()
internal::random<int>(9,13)
)) );
CALL_SUBTEST_11((polynomialsolver<float,Dynamic>(1)) );
+ CALL_SUBTEST_12((polynomialsolver<std::complex<double>,Dynamic>(internal::random<int>(2,13))) );
}
}