mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24fd14dab6 | ||
|
|
4d44ca226e | ||
|
|
b26e12abcf | ||
|
|
a7554023a4 | ||
|
|
9d97c06d9d | ||
|
|
1fc17c4792 | ||
|
|
6efaece8ce | ||
|
|
294f5f16dd | ||
|
|
f86818b5a6 | ||
|
|
336ad58213 | ||
|
|
af5034b3c0 | ||
|
|
7f881e814f | ||
|
|
a4252584ed | ||
|
|
b365f443a2 | ||
|
|
484ed3bbe2 | ||
|
|
92959aa5f3 | ||
|
|
2db5888253 | ||
|
|
f268e79709 | ||
|
|
9e8f437a6f | ||
|
|
824b75f182 | ||
|
|
a30b498ab4 | ||
|
|
28e15574df | ||
|
|
6c84b03d77 | ||
|
|
4361cb8913 | ||
|
|
50ad8b9010 | ||
|
|
0c1ef2f4c6 | ||
|
|
3efe6e4176 | ||
|
|
335d3bcf05 | ||
|
|
5052d3659b | ||
|
|
5bef59e371 | ||
|
|
265ab86005 | ||
|
|
b3d580dec7 | ||
|
|
fd831d5a12 | ||
|
|
f52a9e5315 | ||
|
|
003d0ce03e | ||
|
|
208b273106 | ||
|
|
b315f4c359 | ||
|
|
51aa62a5d4 | ||
|
|
eb7dcbbfce | ||
|
|
1d52bd4cad | ||
|
|
e2d2a7d222 | ||
|
|
af27fb7590 | ||
|
|
8d3469ca44 | ||
|
|
4432cf8ca3 | ||
|
|
cb71dc4bbf | ||
|
|
709e903335 | ||
|
|
7078cfaeaa | ||
|
|
336f0a8486 | ||
|
|
6b9d647fc2 | ||
|
|
3e90940189 | ||
|
|
8cea5f6b31 | ||
|
|
94efa16187 | ||
|
|
ac9d805c2f | ||
|
|
2db434265b | ||
|
|
8e888a45d0 | ||
|
|
6736e52d25 | ||
|
|
1c29d70312 | ||
|
|
e71de20f16 |
@@ -1,5 +1,5 @@
|
||||
project(Eigen)
|
||||
set(EIGEN_VERSION_NUMBER "2.0-beta5")
|
||||
set(EIGEN_VERSION_NUMBER "2.0-beta6")
|
||||
|
||||
#if the svnversion program is absent, this will leave the SVN_REVISION string empty,
|
||||
#but won't stop CMake.
|
||||
@@ -81,6 +81,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_subdirectory(Eigen)
|
||||
|
||||
if(EIGEN_BUILD_TESTS)
|
||||
include(CTest)
|
||||
add_subdirectory(test)
|
||||
endif(EIGEN_BUILD_TESTS)
|
||||
|
||||
|
||||
13
CTestConfig.cmake
Normal file
13
CTestConfig.cmake
Normal file
@@ -0,0 +1,13 @@
|
||||
## This file should be placed in the root directory of your project.
|
||||
## Then modify the CMakeLists.txt file in the root directory of your
|
||||
## project to incorporate the testing dashboard.
|
||||
## # The following are required to uses Dart and the Cdash dashboard
|
||||
## ENABLE_TESTING()
|
||||
## INCLUDE(Dart)
|
||||
set(CTEST_PROJECT_NAME "Eigen")
|
||||
set(CTEST_NIGHTLY_START_TIME "05:00:00 UTC")
|
||||
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "www.cdash.org")
|
||||
set(CTEST_DROP_LOCATION "/CDashPublic/submit.php?project=Eigen")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
@@ -1,4 +1,4 @@
|
||||
set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression LeastSquares)
|
||||
set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression LeastSquares StdVector)
|
||||
|
||||
if(EIGEN_BUILD_LIB)
|
||||
set(Eigen_SRCS
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
// first thing Eigen does: prevent MSVC from committing suicide
|
||||
#include "src/Core/util/DisableMSVCWarnings.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h> // for _aligned_malloc -- need it regardless of whether vectorization is enabled
|
||||
#if (_MSC_VER >= 1500) // 2008 or later
|
||||
// Remember that usage of defined() in a #define is undefined by the standard
|
||||
#ifdef _M_IX86_FP
|
||||
@@ -57,10 +59,7 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#if defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER) && defined(EIGEN_VECTORIZE)
|
||||
#include <malloc.h> // for _aligned_malloc
|
||||
#endif
|
||||
#include <limits>
|
||||
|
||||
#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(EIGEN_NO_EXCEPTIONS)
|
||||
#define EIGEN_EXCEPTIONS
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace Eigen {
|
||||
#include "src/Sparse/SparseMatrix.h"
|
||||
#include "src/Sparse/SparseVector.h"
|
||||
#include "src/Sparse/CoreIterators.h"
|
||||
#include "src/Sparse/SparseRedux.h"
|
||||
#include "src/Sparse/SparseProduct.h"
|
||||
#include "src/Sparse/TriangularSolver.h"
|
||||
#include "src/Sparse/SparseLLT.h"
|
||||
|
||||
15
Eigen/StdVector
Normal file
15
Eigen/StdVector
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef EIGEN_STDVECTOR_MODULE_H
|
||||
#define EIGEN_STDVECTOR_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
#include <vector>
|
||||
|
||||
namespace Eigen {
|
||||
#include "src/StdVector/UnalignedType.h"
|
||||
} // namespace Eigen
|
||||
|
||||
namespace std {
|
||||
#include "src/StdVector/StdVector.h"
|
||||
} // namespace std
|
||||
|
||||
#endif // EIGEN_STDVECTOR_MODULE_H
|
||||
@@ -45,15 +45,18 @@ template<typename ConditionMatrixType, typename ThenMatrixType, typename ElseMat
|
||||
struct ei_traits<Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType> >
|
||||
{
|
||||
typedef typename ei_traits<ThenMatrixType>::Scalar Scalar;
|
||||
typedef typename ConditionMatrixType::Nested ConditionMatrixNested;
|
||||
typedef typename ThenMatrixType::Nested ThenMatrixNested;
|
||||
typedef typename ElseMatrixType::Nested ElseMatrixNested;
|
||||
enum {
|
||||
RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime,
|
||||
Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits,
|
||||
CoeffReadCost = ei_traits<ConditionMatrixType>::CoeffReadCost
|
||||
+ EIGEN_ENUM_MAX(ei_traits<ThenMatrixType>::CoeffReadCost,
|
||||
ei_traits<ElseMatrixType>::CoeffReadCost)
|
||||
CoeffReadCost = ei_traits<typename ei_cleantype<ConditionMatrixNested>::type>::CoeffReadCost
|
||||
+ EIGEN_ENUM_MAX(ei_traits<typename ei_cleantype<ThenMatrixNested>::type>::CoeffReadCost,
|
||||
ei_traits<typename ei_cleantype<ElseMatrixNested>::type>::CoeffReadCost)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ static void ei_cache_friendly_product(
|
||||
const bool needRhsCopy = (PacketSize>1) && ((rhsStride%PacketSize!=0) || (size_t(rhs)%16!=0));
|
||||
Scalar* EIGEN_RESTRICT block = 0;
|
||||
const int allocBlockSize = l2BlockRows*size;
|
||||
block = ei_aligned_stack_alloc(Scalar, allocBlockSize);
|
||||
block = ei_aligned_stack_new(Scalar, allocBlockSize);
|
||||
Scalar* EIGEN_RESTRICT rhsCopy
|
||||
= ei_aligned_stack_alloc(Scalar, l2BlockSizeAligned*l2BlockSizeAligned);
|
||||
= ei_aligned_stack_new(Scalar, l2BlockSizeAligned*l2BlockSizeAligned);
|
||||
|
||||
// loops on each L2 cache friendly blocks of the result
|
||||
for(int l2i=0; l2i<rows; l2i+=l2BlockRows)
|
||||
@@ -338,8 +338,8 @@ static void ei_cache_friendly_product(
|
||||
}
|
||||
}
|
||||
|
||||
ei_aligned_stack_free(block, Scalar, allocBlockSize);
|
||||
ei_aligned_stack_free(rhsCopy, Scalar, l2BlockSizeAligned*l2BlockSizeAligned);
|
||||
ei_aligned_stack_delete(Scalar, block, allocBlockSize);
|
||||
ei_aligned_stack_delete(Scalar, rhsCopy, l2BlockSizeAligned*l2BlockSizeAligned);
|
||||
}
|
||||
|
||||
#endif // EIGEN_EXTERN_INSTANTIATIONS
|
||||
|
||||
@@ -128,6 +128,12 @@ template<typename ExpressionType> class Cwise
|
||||
|
||||
ExpressionType& operator-=(const Scalar& scalar);
|
||||
|
||||
template<typename OtherDerived>
|
||||
inline ExpressionType& operator*=(const MatrixBase<OtherDerived> &other);
|
||||
|
||||
template<typename OtherDerived>
|
||||
inline ExpressionType& operator/=(const MatrixBase<OtherDerived> &other);
|
||||
|
||||
template<typename OtherDerived> const EIGEN_CWISE_BINOP_RETURN_TYPE(std::less)
|
||||
operator<(const MatrixBase<OtherDerived>& other) const;
|
||||
|
||||
|
||||
@@ -224,6 +224,34 @@ Cwise<ExpressionType>::operator/(const MatrixBase<OtherDerived> &other) const
|
||||
return EIGEN_CWISE_BINOP_RETURN_TYPE(ei_scalar_quotient_op)(_expression(), other.derived());
|
||||
}
|
||||
|
||||
/** Replaces this expression by its coefficient-wise product with \a other.
|
||||
*
|
||||
* Example: \include Cwise_times_equal.cpp
|
||||
* Output: \verbinclude Cwise_times_equal.out
|
||||
*
|
||||
* \sa operator*(), operator/=()
|
||||
*/
|
||||
template<typename ExpressionType>
|
||||
template<typename OtherDerived>
|
||||
inline ExpressionType& Cwise<ExpressionType>::operator*=(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
return m_matrix.const_cast_derived() = *this * other;
|
||||
}
|
||||
|
||||
/** Replaces this expression by its coefficient-wise quotient by \a other.
|
||||
*
|
||||
* Example: \include Cwise_slash_equal.cpp
|
||||
* Output: \verbinclude Cwise_slash_equal.out
|
||||
*
|
||||
* \sa operator/(), operator*=()
|
||||
*/
|
||||
template<typename ExpressionType>
|
||||
template<typename OtherDerived>
|
||||
inline ExpressionType& Cwise<ExpressionType>::operator/=(const MatrixBase<OtherDerived> &other)
|
||||
{
|
||||
return m_matrix.const_cast_derived() = *this / other;
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise min of *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_min.cpp
|
||||
|
||||
@@ -41,14 +41,9 @@
|
||||
* \sa class CwiseUnaryOp, class CwiseBinaryOp, MatrixBase::NullaryExpr()
|
||||
*/
|
||||
template<typename NullaryOp, typename MatrixType>
|
||||
struct ei_traits<CwiseNullaryOp<NullaryOp, MatrixType> >
|
||||
struct ei_traits<CwiseNullaryOp<NullaryOp, MatrixType> > : ei_traits<MatrixType>
|
||||
{
|
||||
typedef typename ei_traits<MatrixType>::Scalar Scalar;
|
||||
enum {
|
||||
RowsAtCompileTime = ei_traits<MatrixType>::RowsAtCompileTime,
|
||||
ColsAtCompileTime = ei_traits<MatrixType>::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = ei_traits<MatrixType>::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = ei_traits<MatrixType>::MaxColsAtCompileTime,
|
||||
Flags = (ei_traits<MatrixType>::Flags
|
||||
& ( HereditaryBits
|
||||
| (ei_functor_has_linear_access<NullaryOp>::ret ? LinearAccessBit : 0)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
template<typename UnaryOp, typename MatrixType>
|
||||
struct ei_traits<CwiseUnaryOp<UnaryOp, MatrixType> >
|
||||
: ei_traits<MatrixType>
|
||||
{
|
||||
typedef typename ei_result_of<
|
||||
UnaryOp(typename MatrixType::Scalar)
|
||||
@@ -48,16 +49,10 @@ struct ei_traits<CwiseUnaryOp<UnaryOp, MatrixType> >
|
||||
typedef typename MatrixType::Nested MatrixTypeNested;
|
||||
typedef typename ei_unref<MatrixTypeNested>::type _MatrixTypeNested;
|
||||
enum {
|
||||
MatrixTypeCoeffReadCost = _MatrixTypeNested::CoeffReadCost,
|
||||
MatrixTypeFlags = _MatrixTypeNested::Flags,
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
Flags = (MatrixTypeFlags & (
|
||||
Flags = (_MatrixTypeNested::Flags & (
|
||||
HereditaryBits | LinearAccessBit | AlignedBit
|
||||
| (ei_functor_traits<UnaryOp>::PacketAccess ? PacketAccessBit : 0))),
|
||||
CoeffReadCost = MatrixTypeCoeffReadCost + ei_functor_traits<UnaryOp>::Cost
|
||||
CoeffReadCost = _MatrixTypeNested::CoeffReadCost + ei_functor_traits<UnaryOp>::Cost
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -143,12 +143,13 @@ struct ei_dot_vec_unroller<Derived1, Derived2, Index, Stop, true>
|
||||
|
||||
template<typename Derived1, typename Derived2,
|
||||
int Vectorization = ei_dot_traits<Derived1, Derived2>::Vectorization,
|
||||
int Unrolling = ei_dot_traits<Derived1, Derived2>::Unrolling
|
||||
int Unrolling = ei_dot_traits<Derived1, Derived2>::Unrolling,
|
||||
int Storage = (ei_traits<Derived1>::Flags | ei_traits<Derived2>::Flags) & SparseBit
|
||||
>
|
||||
struct ei_dot_impl;
|
||||
|
||||
template<typename Derived1, typename Derived2>
|
||||
struct ei_dot_impl<Derived1, Derived2, NoVectorization, NoUnrolling>
|
||||
struct ei_dot_impl<Derived1, Derived2, NoVectorization, NoUnrolling, IsDense>
|
||||
{
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
static Scalar run(const Derived1& v1, const Derived2& v2)
|
||||
@@ -163,12 +164,12 @@ struct ei_dot_impl<Derived1, Derived2, NoVectorization, NoUnrolling>
|
||||
};
|
||||
|
||||
template<typename Derived1, typename Derived2>
|
||||
struct ei_dot_impl<Derived1, Derived2, NoVectorization, CompleteUnrolling>
|
||||
struct ei_dot_impl<Derived1, Derived2, NoVectorization, CompleteUnrolling, IsDense>
|
||||
: public ei_dot_novec_unroller<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
|
||||
{};
|
||||
|
||||
template<typename Derived1, typename Derived2>
|
||||
struct ei_dot_impl<Derived1, Derived2, LinearVectorization, NoUnrolling>
|
||||
struct ei_dot_impl<Derived1, Derived2, LinearVectorization, NoUnrolling, IsDense>
|
||||
{
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
typedef typename ei_packet_traits<Scalar>::type PacketScalar;
|
||||
@@ -221,7 +222,7 @@ struct ei_dot_impl<Derived1, Derived2, LinearVectorization, NoUnrolling>
|
||||
};
|
||||
|
||||
template<typename Derived1, typename Derived2>
|
||||
struct ei_dot_impl<Derived1, Derived2, LinearVectorization, CompleteUnrolling>
|
||||
struct ei_dot_impl<Derived1, Derived2, LinearVectorization, CompleteUnrolling, IsDense>
|
||||
{
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
typedef typename ei_packet_traits<Scalar>::type PacketScalar;
|
||||
@@ -258,20 +259,15 @@ template<typename OtherDerived>
|
||||
typename ei_traits<Derived>::Scalar
|
||||
MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
|
||||
{
|
||||
typedef typename Derived::Nested Nested;
|
||||
typedef typename OtherDerived::Nested OtherNested;
|
||||
typedef typename ei_unref<Nested>::type _Nested;
|
||||
typedef typename ei_unref<OtherNested>::type _OtherNested;
|
||||
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested)
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
|
||||
EIGEN_STATIC_ASSERT((ei_is_same_type<Scalar, typename OtherDerived::Scalar>::ret),
|
||||
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
|
||||
|
||||
ei_assert(size() == other.size());
|
||||
|
||||
return ei_dot_impl<_Nested, _OtherNested>::run(derived(), other.derived());
|
||||
return ei_dot_impl<Derived, OtherDerived>::run(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns the squared norm of *this, i.e. the dot product of *this with itself.
|
||||
@@ -287,7 +283,7 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
|
||||
template<typename Derived>
|
||||
EIGEN_DEPRECATED inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm2() const
|
||||
{
|
||||
return ei_real(dot(*this));
|
||||
return ei_real((*this).cwise().abs2().sum());
|
||||
}
|
||||
|
||||
/** \returns the squared norm of *this, i.e. the dot product of *this with itself.
|
||||
@@ -299,7 +295,7 @@ EIGEN_DEPRECATED inline typename NumTraits<typename ei_traits<Derived>::Scalar>:
|
||||
template<typename Derived>
|
||||
inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const
|
||||
{
|
||||
return ei_real(dot(*this));
|
||||
return ei_real((*this).cwise().abs2().sum());
|
||||
}
|
||||
|
||||
/** \returns the \em l2 norm of *this, i.e. the square root of the dot product of *this with itself.
|
||||
|
||||
@@ -40,18 +40,9 @@
|
||||
* \sa MatrixBase::flagged()
|
||||
*/
|
||||
template<typename ExpressionType, unsigned int Added, unsigned int Removed>
|
||||
struct ei_traits<Flagged<ExpressionType, Added, Removed> >
|
||||
struct ei_traits<Flagged<ExpressionType, Added, Removed> > : ei_traits<ExpressionType>
|
||||
{
|
||||
typedef typename ExpressionType::Scalar Scalar;
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = ExpressionType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = ExpressionType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = ExpressionType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = ExpressionType::MaxColsAtCompileTime,
|
||||
Flags = (ExpressionType::Flags | Added) & ~Removed,
|
||||
CoeffReadCost = ExpressionType::CoeffReadCost
|
||||
};
|
||||
enum { Flags = (ExpressionType::Flags | Added) & ~Removed };
|
||||
};
|
||||
|
||||
template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged
|
||||
|
||||
@@ -34,6 +34,16 @@ template<typename T> inline T ei_random_amplitude()
|
||||
else return static_cast<T>(10);
|
||||
}
|
||||
|
||||
template<typename T> inline T ei_hypot(T x, T y)
|
||||
{
|
||||
T _x = ei_abs(x);
|
||||
T _y = ei_abs(y);
|
||||
T p = std::max(_x, _y);
|
||||
T q = std::min(_x, _y);
|
||||
T qp = q/p;
|
||||
return p * ei_sqrt(T(1) + qp*qp);
|
||||
}
|
||||
|
||||
/**************
|
||||
*** int ***
|
||||
**************/
|
||||
@@ -138,7 +148,7 @@ inline double ei_exp(double x) { return std::exp(x); }
|
||||
inline double ei_log(double x) { return std::log(x); }
|
||||
inline double ei_sin(double x) { return std::sin(x); }
|
||||
inline double ei_cos(double x) { return std::cos(x); }
|
||||
inline double ei_pow(double x, double y) { return std::pow(x, y); }
|
||||
inline double ei_pow(double x, double y) { return std::pow(x, y); }
|
||||
|
||||
template<> inline double ei_random(double a, double b)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef EIGEN_MATRIX_H
|
||||
#define EIGEN_MATRIX_H
|
||||
|
||||
|
||||
/** \class Matrix
|
||||
*
|
||||
* \brief The matrix class, also used for vectors and row-vectors
|
||||
@@ -40,8 +41,8 @@
|
||||
* \param _Cols Number of columns, or \b Dynamic
|
||||
*
|
||||
* The remaining template parameters are optional -- in most cases you don't have to worry about them.
|
||||
* \param _Options A combination of either \b Matrix_RowMajor or \b Matrix_ColMajor, and of either
|
||||
* \b Matrix_AutoAlign or \b Matrix_DontAlign.
|
||||
* \param _Options A combination of either \b RowMajor or \b ColMajor, and of either
|
||||
* \b AutoAlign or \b DontAlign.
|
||||
* The former controls storage order, and defaults to column-major. The latter controls alignment, which is required
|
||||
* for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size.
|
||||
* \param _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note").
|
||||
@@ -133,33 +134,9 @@ class Matrix
|
||||
ei_matrix_storage<Scalar, MaxSizeAtCompileTime, RowsAtCompileTime, ColsAtCompileTime, Options> m_storage;
|
||||
|
||||
public:
|
||||
enum { NeedsToAlign = (Options&Matrix_AutoAlign) == Matrix_AutoAlign
|
||||
enum { NeedsToAlign = (Options&AutoAlign) == AutoAlign
|
||||
&& SizeAtCompileTime!=Dynamic && ((sizeof(Scalar)*SizeAtCompileTime)%16)==0 };
|
||||
typedef typename ei_meta_if<NeedsToAlign, ei_byte_forcing_aligned_malloc, char>::ret ByteAlignedAsNeeded;
|
||||
void *operator new(size_t size) throw()
|
||||
{
|
||||
return ei_aligned_malloc<ByteAlignedAsNeeded>(size);
|
||||
}
|
||||
|
||||
void *operator new(size_t, void *ptr) throw()
|
||||
{
|
||||
return static_cast<void*>(ptr);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size) throw()
|
||||
{
|
||||
return ei_aligned_malloc<ByteAlignedAsNeeded>(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t, void *ptr) throw()
|
||||
{
|
||||
return static_cast<void*>(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void * ptr) { ei_aligned_free(static_cast<ByteAlignedAsNeeded *>(ptr), 0); }
|
||||
void operator delete[](void * ptr) { ei_aligned_free(static_cast<ByteAlignedAsNeeded *>(ptr), 0); }
|
||||
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
|
||||
|
||||
EIGEN_STRONG_INLINE int rows() const { return m_storage.rows(); }
|
||||
EIGEN_STRONG_INLINE int cols() const { return m_storage.cols(); }
|
||||
@@ -360,6 +337,9 @@ class Matrix
|
||||
ei_assert(RowsAtCompileTime > 0 && ColsAtCompileTime > 0);
|
||||
}
|
||||
|
||||
Matrix(ei_constructor_without_unaligned_array_assert)
|
||||
: m_storage(ei_constructor_without_unaligned_array_assert()) {}
|
||||
|
||||
/** Constructs a vector or row-vector with given dimension. \only_for_vectors
|
||||
*
|
||||
* Note that this is only useful for dynamic-size vectors. For fixed-size vectors,
|
||||
|
||||
@@ -26,25 +26,33 @@
|
||||
#ifndef EIGEN_MATRIXSTORAGE_H
|
||||
#define EIGEN_MATRIXSTORAGE_H
|
||||
|
||||
struct ei_constructor_without_unaligned_array_assert {};
|
||||
|
||||
/** \internal
|
||||
* Static array automatically aligned if the total byte size is a multiple of 16 and the matrix options require auto alignment
|
||||
*/
|
||||
template <typename T, int Size, int MatrixOptions,
|
||||
bool Align = (MatrixOptions&Matrix_AutoAlign) && (((Size*sizeof(T))&0xf)==0)
|
||||
bool Align = (MatrixOptions&AutoAlign) && (((Size*sizeof(T))&0xf)==0)
|
||||
> struct ei_matrix_array
|
||||
{
|
||||
EIGEN_ALIGN_128 T array[Size];
|
||||
|
||||
ei_matrix_array()
|
||||
{
|
||||
#ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
|
||||
ei_assert((reinterpret_cast<size_t>(array) & 0xf) == 0
|
||||
&& "this assertion is explained here: http://eigen.tuxfamily.org/api/UnalignedArrayAssert.html **** READ THIS WEB PAGE !!! ****");
|
||||
#endif
|
||||
}
|
||||
|
||||
ei_matrix_array(ei_constructor_without_unaligned_array_assert) {}
|
||||
};
|
||||
|
||||
template <typename T, int Size, int MatrixOptions> struct ei_matrix_array<T,Size,MatrixOptions,false>
|
||||
{
|
||||
T array[Size];
|
||||
ei_matrix_array() {}
|
||||
ei_matrix_array(ei_constructor_without_unaligned_array_assert) {}
|
||||
};
|
||||
|
||||
/** \internal
|
||||
@@ -66,6 +74,8 @@ template<typename T, int Size, int _Rows, int _Cols, int _Options> class ei_matr
|
||||
ei_matrix_array<T,Size,_Options> m_data;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() {}
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert)
|
||||
: m_data(ei_constructor_without_unaligned_array_assert()) {}
|
||||
inline ei_matrix_storage(int,int,int) {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); }
|
||||
inline static int rows(void) {return _Rows;}
|
||||
@@ -83,6 +93,8 @@ template<typename T, int Size, int _Options> class ei_matrix_storage<T, Size, Dy
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert)
|
||||
: m_data(ei_constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int, int rows, int cols) : m_rows(rows), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other)
|
||||
@@ -105,6 +117,8 @@ template<typename T, int Size, int _Cols, int _Options> class ei_matrix_storage<
|
||||
int m_rows;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_rows(0) {}
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert)
|
||||
: m_data(ei_constructor_without_unaligned_array_assert()), m_rows(0) {}
|
||||
inline ei_matrix_storage(int, int rows, int) : m_rows(rows) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
|
||||
@@ -125,6 +139,8 @@ template<typename T, int Size, int _Rows, int _Options> class ei_matrix_storage<
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_cols(0) {}
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert)
|
||||
: m_data(ei_constructor_without_unaligned_array_assert()), m_cols(0) {}
|
||||
inline ei_matrix_storage(int, int, int cols) : m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() {}
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
|
||||
@@ -146,9 +162,11 @@ template<typename T, int _Options> class ei_matrix_storage<T, Dynamic, Dynamic,
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert)
|
||||
: m_data(0), m_rows(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int size, int rows, int cols)
|
||||
: m_data(ei_aligned_malloc<T>(size)), m_rows(rows), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data, m_rows*m_cols); }
|
||||
: m_data(ei_aligned_new<T>(size)), m_rows(rows), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_delete(m_data, m_rows*m_cols); }
|
||||
inline void swap(ei_matrix_storage& other)
|
||||
{ std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); }
|
||||
inline int rows(void) const {return m_rows;}
|
||||
@@ -157,8 +175,8 @@ template<typename T, int _Options> class ei_matrix_storage<T, Dynamic, Dynamic,
|
||||
{
|
||||
if(size != m_rows*m_cols)
|
||||
{
|
||||
ei_aligned_free(m_data, m_rows*m_cols);
|
||||
m_data = ei_aligned_malloc<T>(size);
|
||||
ei_aligned_delete(m_data, m_rows*m_cols);
|
||||
m_data = ei_aligned_new<T>(size);
|
||||
}
|
||||
m_rows = rows;
|
||||
m_cols = cols;
|
||||
@@ -174,8 +192,9 @@ template<typename T, int _Rows, int _Options> class ei_matrix_storage<T, Dynamic
|
||||
int m_cols;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int size, int, int cols) : m_data(ei_aligned_malloc<T>(size)), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data, _Rows*m_cols); }
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {}
|
||||
inline ei_matrix_storage(int size, int, int cols) : m_data(ei_aligned_new<T>(size)), m_cols(cols) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_delete(m_data, _Rows*m_cols); }
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
|
||||
inline static int rows(void) {return _Rows;}
|
||||
inline int cols(void) const {return m_cols;}
|
||||
@@ -183,8 +202,8 @@ template<typename T, int _Rows, int _Options> class ei_matrix_storage<T, Dynamic
|
||||
{
|
||||
if(size != _Rows*m_cols)
|
||||
{
|
||||
ei_aligned_free(m_data, _Rows*m_cols);
|
||||
m_data = ei_aligned_malloc<T>(size);
|
||||
ei_aligned_delete(m_data, _Rows*m_cols);
|
||||
m_data = ei_aligned_new<T>(size);
|
||||
}
|
||||
m_cols = cols;
|
||||
}
|
||||
@@ -199,8 +218,9 @@ template<typename T, int _Cols, int _Options> class ei_matrix_storage<T, Dynamic
|
||||
int m_rows;
|
||||
public:
|
||||
inline explicit ei_matrix_storage() : m_data(0), m_rows(0) {}
|
||||
inline ei_matrix_storage(int size, int rows, int) : m_data(ei_aligned_malloc<T>(size)), m_rows(rows) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_free(m_data, _Cols*m_rows); }
|
||||
inline ei_matrix_storage(ei_constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {}
|
||||
inline ei_matrix_storage(int size, int rows, int) : m_data(ei_aligned_new<T>(size)), m_rows(rows) {}
|
||||
inline ~ei_matrix_storage() { ei_aligned_delete(m_data, _Cols*m_rows); }
|
||||
inline void swap(ei_matrix_storage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
|
||||
inline int rows(void) const {return m_rows;}
|
||||
inline static int cols(void) {return _Cols;}
|
||||
@@ -208,8 +228,8 @@ template<typename T, int _Cols, int _Options> class ei_matrix_storage<T, Dynamic
|
||||
{
|
||||
if(size != m_rows*_Cols)
|
||||
{
|
||||
ei_aligned_free(m_data, _Cols*m_rows);
|
||||
m_data = ei_aligned_malloc<T>(size);
|
||||
ei_aligned_delete(m_data, _Cols*m_rows);
|
||||
m_data = ei_aligned_new<T>(size);
|
||||
}
|
||||
m_rows = rows;
|
||||
}
|
||||
|
||||
@@ -38,18 +38,8 @@
|
||||
* \sa MatrixBase::nestByValue()
|
||||
*/
|
||||
template<typename ExpressionType>
|
||||
struct ei_traits<NestByValue<ExpressionType> >
|
||||
{
|
||||
typedef typename ExpressionType::Scalar Scalar;
|
||||
enum {
|
||||
RowsAtCompileTime = ExpressionType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = ExpressionType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = ExpressionType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = ExpressionType::MaxColsAtCompileTime,
|
||||
Flags = ExpressionType::Flags,
|
||||
CoeffReadCost = ExpressionType::CoeffReadCost
|
||||
};
|
||||
};
|
||||
struct ei_traits<NestByValue<ExpressionType> > : public ei_traits<ExpressionType>
|
||||
{};
|
||||
|
||||
template<typename ExpressionType> class NestByValue
|
||||
: public MatrixBase<NestByValue<ExpressionType> >
|
||||
|
||||
@@ -43,16 +43,11 @@
|
||||
* \sa MatrixBase::part()
|
||||
*/
|
||||
template<typename MatrixType, unsigned int Mode>
|
||||
struct ei_traits<Part<MatrixType, Mode> >
|
||||
struct ei_traits<Part<MatrixType, Mode> > : ei_traits<MatrixType>
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename ei_nested<MatrixType>::type MatrixTypeNested;
|
||||
typedef typename ei_unref<MatrixTypeNested>::type _MatrixTypeNested;
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
Flags = (_MatrixTypeNested::Flags & (HereditaryBits) & (~(PacketAccessBit | DirectAccessBit | LinearAccessBit))) | Mode,
|
||||
CoeffReadCost = _MatrixTypeNested::CoeffReadCost
|
||||
};
|
||||
|
||||
@@ -573,7 +573,7 @@ struct ei_cache_friendly_product_selector<ProductType,LhsRows,ColMajor,HasDirect
|
||||
_res = &res.coeffRef(0);
|
||||
else
|
||||
{
|
||||
_res = ei_aligned_stack_alloc(Scalar,res.size());
|
||||
_res = ei_aligned_stack_new(Scalar,res.size());
|
||||
Map<Matrix<Scalar,DestDerived::RowsAtCompileTime,1> >(_res, res.size()) = res;
|
||||
}
|
||||
ei_cache_friendly_product_colmajor_times_vector(res.size(),
|
||||
@@ -583,7 +583,7 @@ struct ei_cache_friendly_product_selector<ProductType,LhsRows,ColMajor,HasDirect
|
||||
if (!EvalToRes)
|
||||
{
|
||||
res = Map<Matrix<Scalar,DestDerived::SizeAtCompileTime,1> >(_res, res.size());
|
||||
ei_aligned_stack_free(_res, Scalar, res.size());
|
||||
ei_aligned_stack_delete(Scalar, _res, res.size());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -619,7 +619,7 @@ struct ei_cache_friendly_product_selector<ProductType,1,LhsOrder,LhsAccess,RhsCo
|
||||
_res = &res.coeffRef(0);
|
||||
else
|
||||
{
|
||||
_res = ei_aligned_stack_alloc(Scalar, res.size());
|
||||
_res = ei_aligned_stack_new(Scalar, res.size());
|
||||
Map<Matrix<Scalar,DestDerived::SizeAtCompileTime,1> >(_res, res.size()) = res;
|
||||
}
|
||||
ei_cache_friendly_product_colmajor_times_vector(res.size(),
|
||||
@@ -629,7 +629,7 @@ struct ei_cache_friendly_product_selector<ProductType,1,LhsOrder,LhsAccess,RhsCo
|
||||
if (!EvalToRes)
|
||||
{
|
||||
res = Map<Matrix<Scalar,DestDerived::SizeAtCompileTime,1> >(_res, res.size());
|
||||
ei_aligned_stack_free(_res, Scalar, res.size());
|
||||
ei_aligned_stack_delete(Scalar, _res, res.size());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -652,13 +652,13 @@ struct ei_cache_friendly_product_selector<ProductType,LhsRows,RowMajor,HasDirect
|
||||
_rhs = &product.rhs().const_cast_derived().coeffRef(0);
|
||||
else
|
||||
{
|
||||
_rhs = ei_aligned_stack_alloc(Scalar, product.rhs().size());
|
||||
_rhs = ei_aligned_stack_new(Scalar, product.rhs().size());
|
||||
Map<Matrix<Scalar,Rhs::SizeAtCompileTime,1> >(_rhs, product.rhs().size()) = product.rhs();
|
||||
}
|
||||
ei_cache_friendly_product_rowmajor_times_vector(&product.lhs().const_cast_derived().coeffRef(0,0), product.lhs().stride(),
|
||||
_rhs, product.rhs().size(), res);
|
||||
|
||||
if (!UseRhsDirectly) ei_aligned_stack_free(_rhs, Scalar, product.rhs().size());
|
||||
if (!UseRhsDirectly) ei_aligned_stack_delete(Scalar, _rhs, product.rhs().size());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -680,13 +680,13 @@ struct ei_cache_friendly_product_selector<ProductType,1,LhsOrder,LhsAccess,RhsCo
|
||||
_lhs = &product.lhs().const_cast_derived().coeffRef(0);
|
||||
else
|
||||
{
|
||||
_lhs = ei_aligned_stack_alloc(Scalar, product.lhs().size());
|
||||
_lhs = ei_aligned_stack_new(Scalar, product.lhs().size());
|
||||
Map<Matrix<Scalar,Lhs::SizeAtCompileTime,1> >(_lhs, product.lhs().size()) = product.lhs();
|
||||
}
|
||||
ei_cache_friendly_product_rowmajor_times_vector(&product.rhs().const_cast_derived().coeffRef(0,0), product.rhs().stride(),
|
||||
_lhs, product.lhs().size(), res);
|
||||
|
||||
if(!UseLhsDirectly) ei_aligned_stack_free(_lhs, Scalar, product.lhs().size());
|
||||
if(!UseLhsDirectly) ei_aligned_stack_delete(Scalar, _lhs, product.lhs().size());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ public:
|
||||
enum {
|
||||
Vectorization = (int(Derived::Flags)&ActualPacketAccessBit)
|
||||
&& (int(Derived::Flags)&LinearAccessBit)
|
||||
&& (int(Derived::SizeAtCompileTime)>2*PacketSize)
|
||||
? LinearVectorization
|
||||
: NoVectorization
|
||||
};
|
||||
@@ -155,12 +154,13 @@ struct ei_sum_vec_unroller<Derived, Index, Stop, true>
|
||||
|
||||
template<typename Derived,
|
||||
int Vectorization = ei_sum_traits<Derived>::Vectorization,
|
||||
int Unrolling = ei_sum_traits<Derived>::Unrolling
|
||||
int Unrolling = ei_sum_traits<Derived>::Unrolling,
|
||||
int Storage = ei_traits<Derived>::Flags & SparseBit
|
||||
>
|
||||
struct ei_sum_impl;
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_sum_impl<Derived, NoVectorization, NoUnrolling>
|
||||
struct ei_sum_impl<Derived, NoVectorization, NoUnrolling, IsDense>
|
||||
{
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
static Scalar run(const Derived& mat)
|
||||
@@ -178,12 +178,12 @@ struct ei_sum_impl<Derived, NoVectorization, NoUnrolling>
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_sum_impl<Derived, NoVectorization, CompleteUnrolling>
|
||||
struct ei_sum_impl<Derived, NoVectorization, CompleteUnrolling, IsDense>
|
||||
: public ei_sum_novec_unroller<Derived, 0, Derived::SizeAtCompileTime>
|
||||
{};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_sum_impl<Derived, LinearVectorization, NoUnrolling>
|
||||
struct ei_sum_impl<Derived, LinearVectorization, NoUnrolling,IsDense>
|
||||
{
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
typedef typename ei_packet_traits<Scalar>::type PacketScalar;
|
||||
@@ -228,14 +228,21 @@ struct ei_sum_impl<Derived, LinearVectorization, NoUnrolling>
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct ei_sum_impl<Derived, LinearVectorization, CompleteUnrolling>
|
||||
struct ei_sum_impl<Derived, LinearVectorization, CompleteUnrolling, IsDense>
|
||||
{
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
typedef typename ei_packet_traits<Scalar>::type PacketScalar;
|
||||
enum {
|
||||
PacketSize = ei_packet_traits<Scalar>::size,
|
||||
Size = Derived::SizeAtCompileTime,
|
||||
VectorizationSize = (Size / PacketSize) * PacketSize
|
||||
};
|
||||
static Scalar run(const Derived& mat)
|
||||
{
|
||||
return ei_predux(
|
||||
ei_sum_vec_unroller<Derived, 0, Derived::SizeAtCompileTime>::run(mat)
|
||||
);
|
||||
Scalar res = ei_predux(ei_sum_vec_unroller<Derived, 0, VectorizationSize>::run(mat));
|
||||
if (VectorizationSize != Size)
|
||||
res += ei_sum_novec_unroller<Derived, VectorizationSize, Size-VectorizationSize>::run(mat);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -223,15 +223,13 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
Matrix_ColMajor = 0,
|
||||
Matrix_RowMajor = 0x1, // it is only a coincidence that this is equal to RowMajorBit -- don't rely on that
|
||||
ColMajor = 0,
|
||||
RowMajor = 0x1, // it is only a coincidence that this is equal to RowMajorBit -- don't rely on that
|
||||
/** \internal Don't require alignment for the matrix itself (the array of coefficients, if dynamically allocated, may still be
|
||||
requested to be aligned) */
|
||||
ColMajor = Matrix_ColMajor, // deprecated
|
||||
RowMajor = Matrix_RowMajor, // deprecated
|
||||
Matrix_DontAlign = 0,
|
||||
/** \internal Align the matrix itself */
|
||||
Matrix_AutoAlign = 0x2
|
||||
DontAlign = 0,
|
||||
/** \internal Align the matrix itself if it is vectorizable fixed-size */
|
||||
AutoAlign = 0x2
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#ifndef EIGEN_DISABLEMSVCWARNINGS_H
|
||||
#define EIGEN_DISABLEMSVCWARNINGS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4181 4244 4127 4211 )
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_DISABLEMSVCWARNINGS_H
|
||||
@@ -1,8 +1,4 @@
|
||||
#ifndef EIGEN_ENABLEMSVCWARNINGS_H
|
||||
#define EIGEN_ENABLEMSVCWARNINGS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_ENABLEMSVCWARNINGS_H
|
||||
@@ -29,7 +29,7 @@ template<typename T> struct ei_traits;
|
||||
template<typename T> struct NumTraits;
|
||||
|
||||
template<typename _Scalar, int _Rows, int _Cols,
|
||||
int _Options = EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION | Matrix_AutoAlign,
|
||||
int _Options = EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION | AutoAlign,
|
||||
int _MaxRows = _Rows, int _MaxCols = _Cols> class Matrix;
|
||||
|
||||
template<typename ExpressionType, unsigned int Added, unsigned int Removed> class Flagged;
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
EIGEN_MINOR_VERSION>=z))))
|
||||
|
||||
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
|
||||
#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION Matrix_RowMajor
|
||||
#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION RowMajor
|
||||
#else
|
||||
#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION Matrix_ColMajor
|
||||
#define EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ColMajor
|
||||
#endif
|
||||
|
||||
/** \internal Defines the maximal loop size to enable meta unrolling of loops.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2009 Kenneth Riddile <kfriddile@yahoo.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
@@ -26,87 +27,170 @@
|
||||
#ifndef EIGEN_MEMORY_H
|
||||
#define EIGEN_MEMORY_H
|
||||
|
||||
#ifdef __linux
|
||||
// it seems we cannot assume posix_memalign is defined in the stdlib header
|
||||
extern "C" int posix_memalign (void **, size_t, size_t) throw ();
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_WIN64)
|
||||
#define EIGEN_MALLOC_ALREADY_ALIGNED 1
|
||||
#else
|
||||
#define EIGEN_MALLOC_ALREADY_ALIGNED 0
|
||||
#endif
|
||||
|
||||
struct ei_byte_forcing_aligned_malloc
|
||||
{
|
||||
unsigned char c; // sizeof must be 1.
|
||||
};
|
||||
template<typename T> struct ei_force_aligned_malloc { enum { ret = 0 }; };
|
||||
template<> struct ei_force_aligned_malloc<ei_byte_forcing_aligned_malloc> { enum { ret = 1 }; };
|
||||
#if (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))
|
||||
#define EIGEN_HAS_POSIX_MEMALIGN 1
|
||||
#else
|
||||
#define EIGEN_HAS_POSIX_MEMALIGN 0
|
||||
#endif
|
||||
|
||||
/** \internal allocates \a size * sizeof(\a T) bytes. If vectorization is enabled and T is such that a packet
|
||||
* containts more than one T, then the returned pointer is guaranteed to have 16 bytes alignment.
|
||||
#ifdef EIGEN_VECTORIZE_SSE
|
||||
#define EIGEN_HAS_MM_MALLOC 1
|
||||
#else
|
||||
#define EIGEN_HAS_MM_MALLOC 0
|
||||
#endif
|
||||
|
||||
/** \internal like malloc, but the returned pointer is guaranteed to be 16-byte aligned.
|
||||
* Fast, but wastes 16 additional bytes of memory.
|
||||
* Does not throw any exception.
|
||||
*/
|
||||
inline void* ei_handmade_aligned_malloc(size_t size)
|
||||
{
|
||||
void *original = malloc(size+16);
|
||||
void *aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(original) & ~(size_t(15))) + 16);
|
||||
*(reinterpret_cast<void**>(aligned) - 1) = original;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
/** \internal frees memory allocated with ei_handmade_aligned_malloc */
|
||||
inline void ei_handmade_aligned_free(void *ptr)
|
||||
{
|
||||
if(ptr)
|
||||
free(*(reinterpret_cast<void**>(ptr) - 1));
|
||||
}
|
||||
|
||||
/** \internal allocates \a size bytes. The returned pointer is guaranteed to have 16 bytes alignment.
|
||||
* On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T* ei_aligned_malloc(size_t size)
|
||||
inline void* ei_aligned_malloc(size_t size)
|
||||
{
|
||||
if(ei_packet_traits<T>::size>1 || ei_force_aligned_malloc<T>::ret)
|
||||
{
|
||||
void *void_result;
|
||||
#ifdef __linux
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
const int failed =
|
||||
#endif
|
||||
posix_memalign(&void_result, 16, size*sizeof(T));
|
||||
#ifdef EIGEN_NO_MALLOC
|
||||
ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)");
|
||||
#endif
|
||||
|
||||
void *result;
|
||||
#if EIGEN_HAS_POSIX_MEMALIGN && !EIGEN_MALLOC_ALREADY_ALIGNED
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
const int failed =
|
||||
#endif
|
||||
posix_memalign(&result, 16, size);
|
||||
#else
|
||||
#if EIGEN_MALLOC_ALREADY_ALIGNED
|
||||
result = malloc(size);
|
||||
#elif EIGEN_HAS_MM_MALLOC
|
||||
result = _mm_malloc(size, 16);
|
||||
#elif (defined _MSC_VER)
|
||||
result = _aligned_malloc(size, 16);
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
void_result = _aligned_malloc(size*sizeof(T), 16);
|
||||
#elif defined(__APPLE__)
|
||||
void_result = malloc(size*sizeof(T)); // Apple's malloc() already returns aligned ptrs
|
||||
#else
|
||||
void_result = _mm_malloc(size*sizeof(T), 16);
|
||||
#endif
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
const int failed = (void_result == 0);
|
||||
#endif
|
||||
result = ei_handmade_aligned_malloc(size);
|
||||
#endif
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
if(failed)
|
||||
throw std::bad_alloc();
|
||||
const int failed = (result == 0);
|
||||
#endif
|
||||
// if the user uses Eigen on some fancy scalar type such as multiple-precision numbers,
|
||||
// and this type has a custom operator new, then we want to honor this operator new!
|
||||
// so when we use C functions to allocate memory, we must be careful to call manually the constructor using
|
||||
// the special placement-new syntax.
|
||||
return new(void_result) T[size];
|
||||
}
|
||||
else
|
||||
return new T[size]; // here we really want a new, not a malloc. Justification: if the user uses Eigen on
|
||||
// some fancy scalar type such as multiple-precision numbers, and this type has a custom operator new,
|
||||
// then we want to honor this operator new! Anyway this type won't have vectorization so the vectorizing path
|
||||
// is irrelevant here. Yes, we should say somewhere in the docs that if the user uses a custom scalar type then
|
||||
// he can't have both vectorization and a custom operator new on his scalar type.
|
||||
#endif
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
if(failed)
|
||||
throw std::bad_alloc();
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/** allocates \a size bytes. If Align is true, then the returned ptr is 16-byte-aligned.
|
||||
* On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown.
|
||||
*/
|
||||
template<bool Align> inline void* ei_conditional_aligned_malloc(size_t size)
|
||||
{
|
||||
return ei_aligned_malloc(size);
|
||||
}
|
||||
|
||||
template<> inline void* ei_conditional_aligned_malloc<false>(size_t size)
|
||||
{
|
||||
#ifdef EIGEN_NO_MALLOC
|
||||
ei_assert(false && "heap allocation is forbidden (EIGEN_NO_MALLOC is defined)");
|
||||
#endif
|
||||
|
||||
void *void_result = malloc(size);
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
if(!void_result) throw std::bad_alloc();
|
||||
#endif
|
||||
return void_result;
|
||||
}
|
||||
|
||||
/** allocates \a size objects of type T. The returned pointer is guaranteed to have 16 bytes alignment.
|
||||
* On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown.
|
||||
* The default constructor of T is called.
|
||||
*/
|
||||
template<typename T> inline T* ei_aligned_new(size_t size)
|
||||
{
|
||||
void *void_result = ei_aligned_malloc(sizeof(T)*size);
|
||||
return ::new(void_result) T[size];
|
||||
}
|
||||
|
||||
template<typename T, bool Align> inline T* ei_conditional_aligned_new(size_t size)
|
||||
{
|
||||
void *void_result = ei_conditional_aligned_malloc<Align>(sizeof(T)*size);
|
||||
return ::new(void_result) T[size];
|
||||
}
|
||||
|
||||
/** \internal free memory allocated with ei_aligned_malloc
|
||||
* The \a size parameter is used to determine on how many elements to call the destructor. If you don't
|
||||
* want any destructor to be called, just pass 0.
|
||||
*/
|
||||
template<typename T>
|
||||
inline void ei_aligned_free(T* ptr, size_t size)
|
||||
inline void ei_aligned_free(void *ptr)
|
||||
{
|
||||
if (ei_packet_traits<T>::size>1 || ei_force_aligned_malloc<T>::ret)
|
||||
{
|
||||
// need to call manually the dtor in case T is some user-defined fancy numeric type.
|
||||
// always destruct an array starting from the end.
|
||||
while(size) ptr[--size].~T();
|
||||
#if defined(__linux)
|
||||
free(ptr);
|
||||
#elif defined(__APPLE__)
|
||||
free(ptr);
|
||||
#elif defined(_MSC_VER)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
_mm_free(ptr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
delete[] ptr;
|
||||
#if EIGEN_MALLOC_ALREADY_ALIGNED
|
||||
free(ptr);
|
||||
#elif EIGEN_HAS_POSIX_MEMALIGN
|
||||
free(ptr);
|
||||
#elif EIGEN_HAS_MM_MALLOC
|
||||
_mm_free(ptr);
|
||||
#elif defined(_MSC_VER)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
ei_handmade_aligned_free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \internal free memory allocated with ei_conditional_aligned_malloc
|
||||
*/
|
||||
template<bool Align> inline void ei_conditional_aligned_free(void *ptr)
|
||||
{
|
||||
ei_aligned_free(ptr);
|
||||
}
|
||||
|
||||
template<> inline void ei_conditional_aligned_free<false>(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/** \internal delete the elements of an array.
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T> inline void ei_delete_elements_of_array(T *ptr, size_t size)
|
||||
{
|
||||
// always destruct an array starting from the end.
|
||||
while(size) ptr[--size].~T();
|
||||
}
|
||||
|
||||
/** \internal delete objects constructed with ei_aligned_new
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T> inline void ei_aligned_delete(T *ptr, size_t size)
|
||||
{
|
||||
ei_delete_elements_of_array<T>(ptr, size);
|
||||
ei_aligned_free(ptr);
|
||||
}
|
||||
|
||||
/** \internal delete objects constructed with ei_conditional_aligned_new
|
||||
* The \a size parameters tells on how many objects to call the destructor of T.
|
||||
*/
|
||||
template<typename T, bool Align> inline void ei_conditional_aligned_delete(T *ptr, size_t size)
|
||||
{
|
||||
ei_delete_elements_of_array<T>(ptr, size);
|
||||
ei_conditional_aligned_free<Align>(ptr);
|
||||
}
|
||||
|
||||
/** \internal \returns the number of elements which have to be skipped such that data are 16 bytes aligned */
|
||||
@@ -124,10 +208,10 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* ei_aligned_stack_alloc(TYPE,SIZE) allocates an aligned buffer of sizeof(TYPE)*SIZE bytes
|
||||
* on the stack if sizeof(TYPE)*SIZE is smaller than EIGEN_STACK_ALLOCATION_LIMIT.
|
||||
* ei_aligned_stack_alloc(SIZE) allocates an aligned buffer of SIZE bytes
|
||||
* on the stack if SIZE is smaller than EIGEN_STACK_ALLOCATION_LIMIT.
|
||||
* Otherwise the memory is allocated on the heap.
|
||||
* Data allocated with ei_aligned_stack_alloc \b must be freed by calling ei_aligned_stack_free(PTR,TYPE,SIZE).
|
||||
* Data allocated with ei_aligned_stack_alloc \b must be freed by calling ei_aligned_stack_free(PTR,SIZE).
|
||||
* \code
|
||||
* float * data = ei_aligned_stack_alloc(float,array.size());
|
||||
* // ...
|
||||
@@ -135,18 +219,41 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
* \endcode
|
||||
*/
|
||||
#ifdef __linux__
|
||||
#define ei_aligned_stack_alloc(TYPE,SIZE) ((sizeof(TYPE)*(SIZE)>EIGEN_STACK_ALLOCATION_LIMIT) \
|
||||
? ei_aligned_malloc<TYPE>(SIZE) \
|
||||
: (TYPE*)alloca(sizeof(TYPE)*(SIZE)))
|
||||
#define ei_aligned_stack_free(PTR,TYPE,SIZE) if (sizeof(TYPE)*SIZE>EIGEN_STACK_ALLOCATION_LIMIT) ei_aligned_free(PTR,SIZE)
|
||||
#define ei_aligned_stack_alloc(SIZE) (SIZE<=EIGEN_STACK_ALLOCATION_LIMIT) \
|
||||
? alloca(SIZE) \
|
||||
: ei_aligned_malloc(SIZE)
|
||||
#define ei_aligned_stack_free(PTR,SIZE) if(SIZE>EIGEN_STACK_ALLOCATION_LIMIT) ei_aligned_free(PTR)
|
||||
#else
|
||||
#define ei_aligned_stack_alloc(TYPE,SIZE) ei_aligned_malloc<TYPE>(SIZE)
|
||||
#define ei_aligned_stack_free(PTR,TYPE,SIZE) ei_aligned_free(PTR,SIZE)
|
||||
#define ei_aligned_stack_alloc(SIZE) ei_aligned_malloc(SIZE)
|
||||
#define ei_aligned_stack_free(PTR,SIZE) ei_aligned_free(PTR)
|
||||
#endif
|
||||
|
||||
/** \class WithAlignedOperatorNew
|
||||
#define ei_aligned_stack_new(TYPE,SIZE) ::new(ei_aligned_stack_alloc(sizeof(TYPE)*SIZE)) TYPE[SIZE]
|
||||
#define ei_aligned_stack_delete(TYPE,PTR,SIZE) do {ei_delete_elements_of_array<TYPE>(PTR, SIZE); \
|
||||
ei_aligned_stack_free(PTR,sizeof(TYPE)*SIZE);} while(0)
|
||||
|
||||
/** Qt <= 4.4 has a bug where it calls new(ptr) T instead of ::new(ptr) T.
|
||||
* This fails as we overload other operator new but not this one. What Qt really means is placement new.
|
||||
* Since this is getting used only with fixed-size Eigen matrices where the ctor does nothing, it is OK to
|
||||
* emulate placement new by just returning the ptr -- no need to call ctors. Good, because we don't know the
|
||||
* class in this macro. So this can safely be used for QVector<Eigen::Vector4f> but definitely not for
|
||||
* QVector<Eigen::VectorXf>.
|
||||
*
|
||||
* \brief Enforces instances of inherited classes to be 16 bytes aligned when allocated with operator new
|
||||
* This macro will go away as soon as Qt >= 4.5 is prevalent -- most likely it should go away in Eigen 2.1.
|
||||
*/
|
||||
#ifdef EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5
|
||||
#define EIGEN_WORKAROUND_FOR_QT_BUG_CALLING_WRONG_OPERATOR_NEW \
|
||||
void *operator new(size_t, void *ptr) throw() { \
|
||||
return ptr; \
|
||||
} \
|
||||
void *operator new[](size_t, void *ptr) throw() { \
|
||||
return ptr; \
|
||||
}
|
||||
#else
|
||||
#define EIGEN_WORKAROUND_FOR_QT_BUG_CALLING_WRONG_OPERATOR_NEW
|
||||
#endif
|
||||
|
||||
/** \brief Overloads the operator new and delete of the class Type with operators that are aligned if NeedsToAlign is true
|
||||
*
|
||||
* When Eigen's explicit vectorization is enabled, Eigen assumes that some fixed sizes types are aligned
|
||||
* on a 16 bytes boundary. Those include all Matrix types having a sizeof multiple of 16 bytes, e.g.:
|
||||
@@ -173,7 +280,8 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
* overloading the operator new to return aligned data when the vectorization is enabled.
|
||||
* Here is a similar safe example:
|
||||
* \code
|
||||
* struct Foo : public WithAlignedOperatorNew {
|
||||
* struct Foo {
|
||||
* EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
* char dummy;
|
||||
* Vector4f some_vector;
|
||||
* };
|
||||
@@ -183,74 +291,110 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
|
||||
*
|
||||
* \sa class ei_new_allocator
|
||||
*/
|
||||
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \
|
||||
void *operator new(size_t size) throw() { \
|
||||
return Eigen::ei_conditional_aligned_malloc<NeedsToAlign>(size); \
|
||||
} \
|
||||
void *operator new[](size_t size) throw() { \
|
||||
return Eigen::ei_conditional_aligned_malloc<NeedsToAlign>(size); \
|
||||
} \
|
||||
void operator delete(void * ptr) { Eigen::ei_conditional_aligned_free<NeedsToAlign>(ptr); } \
|
||||
void operator delete[](void * ptr) { Eigen::ei_conditional_aligned_free<NeedsToAlign>(ptr); } \
|
||||
EIGEN_WORKAROUND_FOR_QT_BUG_CALLING_WRONG_OPERATOR_NEW
|
||||
|
||||
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(true)
|
||||
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar,Size) \
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%16==0))
|
||||
|
||||
/** Deprecated, use the EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro instead in your own class */
|
||||
struct WithAlignedOperatorNew
|
||||
{
|
||||
void *operator new(size_t size) throw()
|
||||
{
|
||||
return ei_aligned_malloc<ei_byte_forcing_aligned_malloc>(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size) throw()
|
||||
{
|
||||
return ei_aligned_malloc<ei_byte_forcing_aligned_malloc>(size);
|
||||
}
|
||||
|
||||
void operator delete(void * ptr) { ei_aligned_free(static_cast<ei_byte_forcing_aligned_malloc *>(ptr), 0); }
|
||||
void operator delete[](void * ptr) { ei_aligned_free(static_cast<ei_byte_forcing_aligned_malloc *>(ptr), 0); }
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
template<typename T, int SizeAtCompileTime,
|
||||
bool NeedsToAlign = (SizeAtCompileTime!=Dynamic) && ((sizeof(T)*SizeAtCompileTime)%16==0)>
|
||||
struct ei_with_aligned_operator_new : public WithAlignedOperatorNew {};
|
||||
|
||||
template<typename T, int SizeAtCompileTime>
|
||||
struct ei_with_aligned_operator_new<T,SizeAtCompileTime,false> {};
|
||||
|
||||
/** \class ei_new_allocator
|
||||
*
|
||||
* \brief stl compatible allocator to use with with fixed-size vector and matrix types
|
||||
*
|
||||
* STL allocator simply wrapping operators new[] and delete[]. Unlike GCC's default new_allocator,
|
||||
* ei_new_allocator call operator new on the type \a T and not the general new operator ignoring
|
||||
* overloaded version of operator new.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* // Vector4f requires 16 bytes alignment:
|
||||
* std::vector<Vector4f,ei_new_allocator<Vector4f> > dataVec4;
|
||||
* // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator:
|
||||
* std::vector<Vector3f> dataVec3;
|
||||
*
|
||||
* struct Foo : WithAlignedOperatorNew {
|
||||
* char dummy;
|
||||
* Vector4f some_vector;
|
||||
* };
|
||||
* std::vector<Foo,ei_new_allocator<Foo> > dataFoo;
|
||||
* \endcode
|
||||
*
|
||||
* \sa class WithAlignedOperatorNew
|
||||
*/
|
||||
template<typename T> class ei_new_allocator
|
||||
/** \class aligned_allocator
|
||||
*
|
||||
* \brief stl compatible allocator to use with with 16 byte aligned types
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* // Matrix4f requires 16 bytes alignment:
|
||||
* std::map< int, Matrix4f, std::less<int>, aligned_allocator<Matrix4f> > my_map_mat4;
|
||||
* // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator:
|
||||
* std::map< int, Vector3f > my_map_vec3;
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
template<class T>
|
||||
class aligned_allocator
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template<typename OtherType>
|
||||
template<class U>
|
||||
struct rebind
|
||||
{ typedef ei_new_allocator<OtherType> other; };
|
||||
{
|
||||
typedef aligned_allocator<U> other;
|
||||
};
|
||||
|
||||
T* address(T& ref) const { return &ref; }
|
||||
const T* address(const T& ref) const { return &ref; }
|
||||
T* allocate(size_t size, const void* = 0) { return new T[size]; }
|
||||
void deallocate(T* ptr, size_t) { delete[] ptr; }
|
||||
size_t max_size() const { return size_t(-1) / sizeof(T); }
|
||||
// FIXME I'm note sure about this construction...
|
||||
void construct(T* ptr, const T& refObj) { ::new(ptr) T(refObj); }
|
||||
void destroy(T* ptr) { ptr->~T(); }
|
||||
pointer address( reference value ) const
|
||||
{
|
||||
return &value;
|
||||
}
|
||||
|
||||
const_pointer address( const_reference value ) const
|
||||
{
|
||||
return &value;
|
||||
}
|
||||
|
||||
aligned_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
aligned_allocator( const aligned_allocator& ) throw()
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
aligned_allocator( const aligned_allocator<U>& ) throw()
|
||||
{
|
||||
}
|
||||
|
||||
~aligned_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
size_type max_size() const throw()
|
||||
{
|
||||
return std::numeric_limits<size_type>::max();
|
||||
}
|
||||
|
||||
pointer allocate( size_type num, const_pointer* hint = 0 )
|
||||
{
|
||||
static_cast<void>( hint ); // suppress unused variable warning
|
||||
return static_cast<pointer>( ei_aligned_malloc( num * sizeof(T) ) );
|
||||
}
|
||||
|
||||
void construct( pointer p, const T& value )
|
||||
{
|
||||
::new( p ) T( value );
|
||||
}
|
||||
|
||||
void destroy( pointer p )
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
void deallocate( pointer p, size_type /*num*/ )
|
||||
{
|
||||
ei_aligned_free( p );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EIGEN_MEMORY_H
|
||||
|
||||
@@ -89,11 +89,11 @@ template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxC
|
||||
class ei_compute_matrix_flags
|
||||
{
|
||||
enum {
|
||||
row_major_bit = Options&Matrix_RowMajor ? RowMajorBit : 0,
|
||||
row_major_bit = Options&RowMajor ? RowMajorBit : 0,
|
||||
inner_max_size = row_major_bit ? MaxCols : MaxRows,
|
||||
is_big = inner_max_size == Dynamic,
|
||||
is_packet_size_multiple = (Cols*Rows) % ei_packet_traits<Scalar>::size == 0,
|
||||
aligned_bit = ((Options&Matrix_AutoAlign) && (is_big || is_packet_size_multiple)) ? AlignedBit : 0,
|
||||
aligned_bit = ((Options&AutoAlign) && (is_big || is_packet_size_multiple)) ? AlignedBit : 0,
|
||||
packet_access_bit = ei_packet_traits<Scalar>::size > 1 && aligned_bit ? PacketAccessBit : 0
|
||||
};
|
||||
|
||||
@@ -117,7 +117,7 @@ template<typename T> struct ei_eval<T,IsDense>
|
||||
typedef Matrix<typename ei_traits<T>::Scalar,
|
||||
ei_traits<T>::RowsAtCompileTime,
|
||||
ei_traits<T>::ColsAtCompileTime,
|
||||
Matrix_AutoAlign | (ei_traits<T>::Flags&RowMajorBit ? Matrix_RowMajor : Matrix_ColMajor),
|
||||
AutoAlign | (ei_traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
|
||||
ei_traits<T>::MaxRowsAtCompileTime,
|
||||
ei_traits<T>::MaxColsAtCompileTime
|
||||
> type;
|
||||
@@ -138,7 +138,7 @@ template<typename T> struct ei_plain_matrix_type
|
||||
typedef Matrix<typename ei_traits<T>::Scalar,
|
||||
ei_traits<T>::RowsAtCompileTime,
|
||||
ei_traits<T>::ColsAtCompileTime,
|
||||
Matrix_AutoAlign | (ei_traits<T>::Flags&RowMajorBit ? Matrix_RowMajor : Matrix_ColMajor),
|
||||
AutoAlign | (ei_traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
|
||||
ei_traits<T>::MaxRowsAtCompileTime,
|
||||
ei_traits<T>::MaxColsAtCompileTime
|
||||
> type;
|
||||
@@ -151,7 +151,7 @@ template<typename T> struct ei_plain_matrix_type_column_major
|
||||
typedef Matrix<typename ei_traits<T>::Scalar,
|
||||
ei_traits<T>::RowsAtCompileTime,
|
||||
ei_traits<T>::ColsAtCompileTime,
|
||||
Matrix_AutoAlign | Matrix_ColMajor,
|
||||
AutoAlign | ColMajor,
|
||||
ei_traits<T>::MaxRowsAtCompileTime,
|
||||
ei_traits<T>::MaxColsAtCompileTime
|
||||
> type;
|
||||
|
||||
@@ -39,10 +39,9 @@
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
class AlignedBox
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
|
||||
{
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1)
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
inline explicit AngleAxis(const AngleAxis<OtherScalarType>& other)
|
||||
{
|
||||
m_axis = other.axis().template cast<Scalar>();
|
||||
m_angle = other.angle();
|
||||
m_angle = Scalar(other.angle());
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
|
||||
@@ -45,10 +45,9 @@
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
class Hyperplane
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
|
||||
{
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1)
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
@@ -41,10 +41,9 @@
|
||||
*/
|
||||
template <typename _Scalar, int _AmbientDim>
|
||||
class ParametrizedLine
|
||||
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim>
|
||||
{
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
|
||||
enum { AmbientDimAtCompileTime = _AmbientDim };
|
||||
typedef _Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
@@ -59,19 +59,19 @@ template<typename _Scalar> struct ei_traits<Quaternion<_Scalar> >
|
||||
|
||||
template<typename _Scalar>
|
||||
class Quaternion : public RotationBase<Quaternion<_Scalar>,3>
|
||||
, public ei_with_aligned_operator_new<_Scalar,4>
|
||||
{
|
||||
typedef RotationBase<Quaternion<_Scalar>,3> Base;
|
||||
typedef Matrix<_Scalar, 4, 1> Coefficients;
|
||||
Coefficients m_coeffs;
|
||||
|
||||
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,4)
|
||||
|
||||
using Base::operator*;
|
||||
|
||||
|
||||
/** the scalar type of the coefficients */
|
||||
typedef _Scalar Scalar;
|
||||
|
||||
/** the type of the Coefficients 4-vector */
|
||||
typedef Matrix<Scalar, 4, 1> Coefficients;
|
||||
/** the type of a 3D vector */
|
||||
typedef Matrix<Scalar,3,1> Vector3;
|
||||
/** the equivalent rotation matrix type */
|
||||
@@ -110,8 +110,11 @@ public:
|
||||
inline Coefficients& coeffs() { return m_coeffs; }
|
||||
|
||||
/** Default constructor and initializing an identity quaternion. */
|
||||
inline Quaternion()
|
||||
{ m_coeffs << 0, 0, 0, 1; }
|
||||
inline Quaternion() {}
|
||||
|
||||
inline Quaternion(ei_constructor_without_unaligned_array_assert)
|
||||
: m_coeffs(ei_constructor_without_unaligned_array_assert()) {}
|
||||
|
||||
|
||||
/** Constructs and initializes the quaternion \f$ w+xi+yj+zk \f$ from
|
||||
* its four coefficients \a w, \a x, \a y and \a z.
|
||||
@@ -149,7 +152,7 @@ public:
|
||||
|
||||
/** \sa Quaternion::Identity(), MatrixBase::setIdentity()
|
||||
*/
|
||||
inline Quaternion& setIdentity() { m_coeffs << 1, 0, 0, 0; return *this; }
|
||||
inline Quaternion& setIdentity() { m_coeffs << 0, 0, 0, 1; return *this; }
|
||||
|
||||
/** \returns the squared norm of the quaternion's coefficients
|
||||
* \sa Quaternion::norm(), MatrixBase::squaredNorm()
|
||||
@@ -214,6 +217,8 @@ public:
|
||||
bool isApprox(const Quaternion& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
|
||||
{ return m_coeffs.isApprox(other.m_coeffs, prec); }
|
||||
|
||||
protected:
|
||||
Coefficients m_coeffs;
|
||||
};
|
||||
|
||||
/** \ingroup GeometryModule
|
||||
@@ -354,7 +359,7 @@ inline Quaternion<Scalar>& Quaternion<Scalar>::setFromTwoVectors(const MatrixBas
|
||||
// set to identity
|
||||
this->w() = 1; this->vec().setZero();
|
||||
}
|
||||
Scalar s = ei_sqrt((1+c)*2);
|
||||
Scalar s = ei_sqrt((Scalar(1)+c)*Scalar(2));
|
||||
Scalar invs = Scalar(1)/s;
|
||||
this->vec() = axis * invs;
|
||||
this->w() = s * Scalar(0.5);
|
||||
@@ -459,7 +464,7 @@ struct ei_quaternion_assign_impl<Other,3,3>
|
||||
int j = (i+1)%3;
|
||||
int k = (j+1)%3;
|
||||
|
||||
t = ei_sqrt(mat.coeff(i,i)-mat.coeff(j,j)-mat.coeff(k,k) + 1.0);
|
||||
t = ei_sqrt(mat.coeff(i,i)-mat.coeff(j,j)-mat.coeff(k,k) + Scalar(1.0));
|
||||
q.coeffs().coeffRef(i) = Scalar(0.5) * t;
|
||||
t = Scalar(0.5)/t;
|
||||
q.w() = (mat.coeff(k,j)-mat.coeff(j,k))*t;
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
template<typename OtherScalarType>
|
||||
inline explicit Rotation2D(const Rotation2D<OtherScalarType>& other)
|
||||
{
|
||||
m_angle = other.angle();
|
||||
m_angle = Scalar(other.angle());
|
||||
}
|
||||
|
||||
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
*/
|
||||
template<typename _Scalar, int _Dim>
|
||||
class Scaling
|
||||
: public ei_with_aligned_operator_new<_Scalar,_Dim>
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim)
|
||||
/** dimension of the space */
|
||||
enum { Dim = _Dim };
|
||||
/** the scalar type of the coefficients */
|
||||
|
||||
@@ -61,10 +61,9 @@ struct ei_transform_product_impl;
|
||||
*/
|
||||
template<typename _Scalar, int _Dim>
|
||||
class Transform
|
||||
: public ei_with_aligned_operator_new<_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1)>
|
||||
{
|
||||
public:
|
||||
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1))
|
||||
enum {
|
||||
Dim = _Dim, ///< space dimension in which the transformation holds
|
||||
HDim = _Dim+1 ///< size of a respective homogeneous vector
|
||||
@@ -95,8 +94,13 @@ public:
|
||||
/** Default constructor without initialization of the coefficients. */
|
||||
inline Transform() { }
|
||||
|
||||
inline Transform(ei_constructor_without_unaligned_array_assert)
|
||||
: m_matrix(ei_constructor_without_unaligned_array_assert()) {}
|
||||
|
||||
inline Transform(const Transform& other)
|
||||
{ m_matrix = other.m_matrix; }
|
||||
{
|
||||
m_matrix = other.m_matrix;
|
||||
}
|
||||
|
||||
inline explicit Transform(const TranslationType& t) { *this = t; }
|
||||
inline explicit Transform(const ScalingType& s) { *this = s; }
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
*/
|
||||
template<typename _Scalar, int _Dim>
|
||||
class Translation
|
||||
: public ei_with_aligned_operator_new<_Scalar,_Dim>
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim)
|
||||
/** dimension of the space */
|
||||
enum { Dim = _Dim };
|
||||
/** the scalar type of the coefficients */
|
||||
|
||||
@@ -282,7 +282,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
int n = nn-1;
|
||||
int low = 0;
|
||||
int high = nn-1;
|
||||
Scalar eps = pow(2.0,-52.0);
|
||||
Scalar eps = ei_pow(Scalar(2),ei_is_same_type<Scalar,float>::ret ? Scalar(-23) : Scalar(-52));
|
||||
Scalar exshift = 0.0;
|
||||
Scalar p=0,q=0,r=0,s=0,z=0,t,w,x,y;
|
||||
|
||||
@@ -328,7 +328,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
else if (l == n-1) // Two roots found
|
||||
{
|
||||
w = matH.coeff(n,n-1) * matH.coeff(n-1,n);
|
||||
p = (matH.coeff(n-1,n-1) - matH.coeff(n,n)) / 2.0;
|
||||
p = (matH.coeff(n-1,n-1) - matH.coeff(n,n)) * Scalar(0.5);
|
||||
q = p * p + w;
|
||||
z = ei_sqrt(ei_abs(q));
|
||||
matH.coeffRef(n,n) = matH.coeff(n,n) + exshift;
|
||||
@@ -405,25 +405,25 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
for (int i = low; i <= n; ++i)
|
||||
matH.coeffRef(i,i) -= x;
|
||||
s = ei_abs(matH.coeff(n,n-1)) + ei_abs(matH.coeff(n-1,n-2));
|
||||
x = y = 0.75 * s;
|
||||
w = -0.4375 * s * s;
|
||||
x = y = Scalar(0.75) * s;
|
||||
w = Scalar(-0.4375) * s * s;
|
||||
}
|
||||
|
||||
// MATLAB's new ad hoc shift
|
||||
if (iter == 30)
|
||||
{
|
||||
s = (y - x) / 2.0;
|
||||
s = Scalar((y - x) / 2.0);
|
||||
s = s * s + w;
|
||||
if (s > 0)
|
||||
{
|
||||
s = ei_sqrt(s);
|
||||
if (y < x)
|
||||
s = -s;
|
||||
s = x - w / ((y - x) / 2.0 + s);
|
||||
s = Scalar(x - w / ((y - x) / 2.0 + s));
|
||||
for (int i = low; i <= n; ++i)
|
||||
matH.coeffRef(i,i) -= s;
|
||||
exshift += s;
|
||||
x = y = w = 0.964;
|
||||
x = y = w = Scalar(0.964);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
if (k != m) {
|
||||
p = matH.coeff(k,k-1);
|
||||
q = matH.coeff(k+1,k-1);
|
||||
r = (notlast ? matH.coeff(k+2,k-1) : 0.0);
|
||||
r = notlast ? matH.coeff(k+2,k-1) : Scalar(0);
|
||||
x = ei_abs(p) + ei_abs(q) + ei_abs(r);
|
||||
if (x != 0.0)
|
||||
{
|
||||
@@ -647,7 +647,7 @@ void EigenSolver<MatrixType>::hqr2(MatrixType& matH)
|
||||
x = matH.coeff(i,i+1);
|
||||
y = matH.coeff(i+1,i);
|
||||
vr = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag() - q * q;
|
||||
vi = (m_eivalues.coeff(i).real() - p) * 2.0 * q;
|
||||
vi = (m_eivalues.coeff(i).real() - p) * Scalar(2) * q;
|
||||
if ((vr == 0.0) && (vi == 0.0))
|
||||
vr = eps * norm * (ei_abs(w) + ei_abs(q) + ei_abs(x) + ei_abs(y) + ei_abs(z));
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ MatrixBase<Derived>::operatorNorm() const
|
||||
template<typename RealScalar, typename Scalar>
|
||||
static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int start, int end, Scalar* matrixQ, int n)
|
||||
{
|
||||
RealScalar td = (diag[end-1] - diag[end])*0.5;
|
||||
RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5);
|
||||
RealScalar e2 = ei_abs2(subdiag[end-1]);
|
||||
RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * ei_sqrt(td*td + e2));
|
||||
RealScalar x = diag[start] - mu;
|
||||
@@ -357,10 +357,12 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, int st
|
||||
subdiag[k - 1] = c * subdiag[k-1] - s * z;
|
||||
|
||||
x = subdiag[k];
|
||||
z = -s * subdiag[k+1];
|
||||
|
||||
if (k < end - 1)
|
||||
{
|
||||
z = -s * subdiag[k+1];
|
||||
subdiag[k + 1] = c * subdiag[k+1];
|
||||
}
|
||||
|
||||
// apply the givens rotation to the unit matrix Q = Q * G
|
||||
// G only modifies the two columns k and k+1
|
||||
|
||||
@@ -208,7 +208,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
m_matU.col(j).end(m-k) += t * m_matU.col(k).end(m-k);
|
||||
}
|
||||
m_matU.col(k).end(m-k) = - m_matU.col(k).end(m-k);
|
||||
m_matU(k,k) = 1.0 + m_matU(k,k);
|
||||
m_matU(k,k) = Scalar(1) + m_matU(k,k);
|
||||
if (k-1>0)
|
||||
m_matU.col(k).start(k-1).setZero();
|
||||
}
|
||||
@@ -242,7 +242,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
// Main iteration loop for the singular values.
|
||||
int pp = p-1;
|
||||
int iter = 0;
|
||||
Scalar eps(pow(2.0,-52.0));
|
||||
Scalar eps = ei_pow(Scalar(2),ei_is_same_type<Scalar,float>::ret ? Scalar(-23) : Scalar(-52));
|
||||
while (p > 0)
|
||||
{
|
||||
int k=0;
|
||||
@@ -260,7 +260,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
// s(k), ..., s(p) are not negligible (qr step).
|
||||
// kase = 4 if e(p-1) is negligible (convergence).
|
||||
|
||||
for (k = p-2; k >= -1; k--)
|
||||
for (k = p-2; k >= -1; --k)
|
||||
{
|
||||
if (k == -1)
|
||||
break;
|
||||
@@ -277,11 +277,11 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
else
|
||||
{
|
||||
int ks;
|
||||
for (ks = p-1; ks >= k; ks--)
|
||||
for (ks = p-1; ks >= k; --ks)
|
||||
{
|
||||
if (ks == k)
|
||||
break;
|
||||
Scalar t( (ks != p ? ei_abs(e[ks]) : 0.) + (ks != k+1 ? ei_abs(e[ks-1]) : 0.));
|
||||
Scalar t = (ks != p ? ei_abs(e[ks]) : Scalar(0)) + (ks != k+1 ? ei_abs(e[ks-1]) : Scalar(0));
|
||||
if (ei_abs(m_sigma[ks]) <= eps*t)
|
||||
{
|
||||
m_sigma[ks] = 0.0;
|
||||
@@ -313,9 +313,9 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
{
|
||||
Scalar f(e[p-2]);
|
||||
e[p-2] = 0.0;
|
||||
for (j = p-2; j >= k; j--)
|
||||
for (j = p-2; j >= k; --j)
|
||||
{
|
||||
Scalar t(hypot(m_sigma[j],f));
|
||||
Scalar t(ei_hypot(m_sigma[j],f));
|
||||
Scalar cs(m_sigma[j]/t);
|
||||
Scalar sn(f/t);
|
||||
m_sigma[j] = t;
|
||||
@@ -344,7 +344,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
e[k-1] = 0.0;
|
||||
for (j = k; j < p; ++j)
|
||||
{
|
||||
Scalar t(hypot(m_sigma[j],f));
|
||||
Scalar t(ei_hypot(m_sigma[j],f));
|
||||
Scalar cs( m_sigma[j]/t);
|
||||
Scalar sn(f/t);
|
||||
m_sigma[j] = t;
|
||||
@@ -375,7 +375,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
Scalar epm1 = e[p-2]/scale;
|
||||
Scalar sk = m_sigma[k]/scale;
|
||||
Scalar ek = e[k]/scale;
|
||||
Scalar b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
|
||||
Scalar b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/Scalar(2);
|
||||
Scalar c = (sp*epm1)*(sp*epm1);
|
||||
Scalar shift = 0.0;
|
||||
if ((b != 0.0) || (c != 0.0))
|
||||
@@ -392,7 +392,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
|
||||
for (j = k; j < p-1; ++j)
|
||||
{
|
||||
Scalar t = hypot(f,g);
|
||||
Scalar t = ei_hypot(f,g);
|
||||
Scalar cs = f/t;
|
||||
Scalar sn = g/t;
|
||||
if (j != k)
|
||||
@@ -410,7 +410,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
m_matV(i,j) = t;
|
||||
}
|
||||
}
|
||||
t = hypot(f,g);
|
||||
t = ei_hypot(f,g);
|
||||
cs = f/t;
|
||||
sn = g/t;
|
||||
m_sigma[j] = t;
|
||||
@@ -439,7 +439,7 @@ void SVD<MatrixType>::compute(const MatrixType& matrix)
|
||||
// Make the singular values positive.
|
||||
if (m_sigma[k] <= 0.0)
|
||||
{
|
||||
m_sigma[k] = (m_sigma[k] < 0.0 ? -m_sigma[k] : 0.0);
|
||||
m_sigma[k] = m_sigma[k] < Scalar(0) ? -m_sigma[k] : Scalar(0);
|
||||
if (wantv)
|
||||
m_matV.col(k).start(pp+1) = -m_matV.col(k).start(pp+1);
|
||||
}
|
||||
|
||||
@@ -33,21 +33,21 @@ class MatrixBase<Derived>::InnerIterator
|
||||
{
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
public:
|
||||
InnerIterator(const Derived& mat, int outer)
|
||||
EIGEN_STRONG_INLINE InnerIterator(const Derived& mat, int outer)
|
||||
: m_matrix(mat), m_inner(0), m_outer(outer), m_end(mat.rows())
|
||||
{}
|
||||
|
||||
Scalar value() const
|
||||
EIGEN_STRONG_INLINE Scalar value() const
|
||||
{
|
||||
return (Derived::Flags&RowMajorBit) ? m_matrix.coeff(m_outer, m_inner)
|
||||
: m_matrix.coeff(m_inner, m_outer);
|
||||
}
|
||||
|
||||
InnerIterator& operator++() { m_inner++; return *this; }
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; }
|
||||
|
||||
int index() const { return m_inner; }
|
||||
EIGEN_STRONG_INLINE int index() const { return m_inner; }
|
||||
|
||||
operator bool() const { return m_inner < m_end && m_inner>=0; }
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; }
|
||||
|
||||
protected:
|
||||
const Derived& m_matrix;
|
||||
@@ -61,7 +61,7 @@ class Transpose<MatrixType>::InnerIterator : public MatrixType::InnerIterator
|
||||
{
|
||||
public:
|
||||
|
||||
InnerIterator(const Transpose& trans, int outer)
|
||||
EIGEN_STRONG_INLINE InnerIterator(const Transpose& trans, int outer)
|
||||
: MatrixType::InnerIterator(trans.m_matrix, outer)
|
||||
{}
|
||||
};
|
||||
@@ -74,7 +74,7 @@ class Block<MatrixType, BlockRows, BlockCols, PacketAccess, _DirectAccessStatus>
|
||||
typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
|
||||
public:
|
||||
|
||||
InnerIterator(const Block& block, int outer)
|
||||
EIGEN_STRONG_INLINE InnerIterator(const Block& block, int outer)
|
||||
: m_iter(block.m_matrix,(Block::Flags&RowMajor) ? block.m_startRow.value() + outer : block.m_startCol.value() + outer),
|
||||
m_start( (Block::Flags&RowMajor) ? block.m_startCol.value() : block.m_startRow.value()),
|
||||
m_end(m_start + ((Block::Flags&RowMajor) ? block.m_blockCols.value() : block.m_blockRows.value())),
|
||||
@@ -84,24 +84,24 @@ class Block<MatrixType, BlockRows, BlockCols, PacketAccess, _DirectAccessStatus>
|
||||
++m_iter;
|
||||
}
|
||||
|
||||
InnerIterator& operator++()
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator++()
|
||||
{
|
||||
++m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Scalar value() const { return m_iter.value(); }
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); }
|
||||
|
||||
int index() const { return m_iter.index() - m_offset; }
|
||||
EIGEN_STRONG_INLINE int index() const { return m_iter.index() - m_offset; }
|
||||
|
||||
operator bool() const { return m_iter && m_iter.index()<m_end; }
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_iter && m_iter.index()<m_end; }
|
||||
|
||||
protected:
|
||||
MatrixTypeIterator m_iter;
|
||||
int m_start;
|
||||
int m_end;
|
||||
int m_offset;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename MatrixType, int BlockRows, int BlockCols, int PacketAccess>
|
||||
class Block<MatrixType, BlockRows, BlockCols, PacketAccess, IsSparse>::InnerIterator
|
||||
@@ -111,7 +111,7 @@ class Block<MatrixType, BlockRows, BlockCols, PacketAccess, IsSparse>::InnerIter
|
||||
typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
|
||||
public:
|
||||
|
||||
InnerIterator(const Block& block, int outer)
|
||||
EIGEN_STRONG_INLINE InnerIterator(const Block& block, int outer)
|
||||
: m_iter(block.m_matrix,(Block::Flags&RowMajor) ? block.m_startRow.value() + outer : block.m_startCol.value() + outer),
|
||||
m_start( (Block::Flags&RowMajor) ? block.m_startCol.value() : block.m_startRow.value()),
|
||||
m_end(m_start + ((Block::Flags&RowMajor) ? block.m_blockCols.value() : block.m_blockRows.value())),
|
||||
@@ -121,17 +121,17 @@ class Block<MatrixType, BlockRows, BlockCols, PacketAccess, IsSparse>::InnerIter
|
||||
++m_iter;
|
||||
}
|
||||
|
||||
InnerIterator& operator++()
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator++()
|
||||
{
|
||||
++m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Scalar value() const { return m_iter.value(); }
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); }
|
||||
|
||||
int index() const { return m_iter.index() - m_offset; }
|
||||
EIGEN_STRONG_INLINE int index() const { return m_iter.index() - m_offset; }
|
||||
|
||||
operator bool() const { return m_iter && m_iter.index()<m_end; }
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_iter && m_iter.index()<m_end; }
|
||||
|
||||
protected:
|
||||
MatrixTypeIterator m_iter;
|
||||
@@ -148,13 +148,13 @@ class CwiseUnaryOp<UnaryOp,MatrixType>::InnerIterator
|
||||
typedef typename _MatrixTypeNested::InnerIterator MatrixTypeIterator;
|
||||
public:
|
||||
|
||||
InnerIterator(const CwiseUnaryOp& unaryOp, int outer)
|
||||
EIGEN_STRONG_INLINE InnerIterator(const CwiseUnaryOp& unaryOp, int outer)
|
||||
: m_iter(unaryOp.m_matrix,outer), m_functor(unaryOp.m_functor), m_id(-1)
|
||||
{
|
||||
this->operator++();
|
||||
}
|
||||
|
||||
InnerIterator& operator++()
|
||||
EIGEN_STRONG_INLINE InnerIterator& operator++()
|
||||
{
|
||||
if (m_iter)
|
||||
{
|
||||
@@ -169,11 +169,11 @@ class CwiseUnaryOp<UnaryOp,MatrixType>::InnerIterator
|
||||
return *this;
|
||||
}
|
||||
|
||||
Scalar value() const { return m_value; }
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_value; }
|
||||
|
||||
int index() const { return m_id; }
|
||||
EIGEN_STRONG_INLINE int index() const { return m_id; }
|
||||
|
||||
operator bool() const { return m_id>=0; }
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; }
|
||||
|
||||
protected:
|
||||
MatrixTypeIterator m_iter;
|
||||
@@ -182,23 +182,54 @@ class CwiseUnaryOp<UnaryOp,MatrixType>::InnerIterator
|
||||
int m_id;
|
||||
};
|
||||
|
||||
template<typename T> struct ei_is_scalar_product { enum { ret = false }; };
|
||||
template<typename T> struct ei_is_scalar_product<ei_scalar_product_op<T> > { enum { ret = true }; };
|
||||
|
||||
template<typename BinaryOp, typename Lhs, typename Rhs, typename Derived>
|
||||
class CwiseBinaryOpInnerIterator;
|
||||
|
||||
template<typename BinaryOp, typename Lhs, typename Rhs>
|
||||
class CwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator
|
||||
: public CwiseBinaryOpInnerIterator<BinaryOp,Lhs,Rhs, typename CwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator>
|
||||
{
|
||||
typedef CwiseBinaryOpInnerIterator<
|
||||
BinaryOp,Lhs,Rhs, typename CwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator> Base;
|
||||
public:
|
||||
typedef typename CwiseBinaryOp::Scalar Scalar;
|
||||
typedef typename ei_traits<CwiseBinaryOp>::_LhsNested _LhsNested;
|
||||
typedef typename _LhsNested::InnerIterator LhsIterator;
|
||||
typedef typename ei_traits<CwiseBinaryOp>::_RhsNested _RhsNested;
|
||||
typedef typename _RhsNested::InnerIterator RhsIterator;
|
||||
// public:
|
||||
EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOp& binOp, int outer)
|
||||
: Base(binOp.m_lhs,binOp.m_rhs,binOp.m_functor,outer)
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename BinaryOp, typename Lhs, typename Rhs, typename Derived>
|
||||
class CwiseBinaryOpInnerIterator
|
||||
{
|
||||
typedef CwiseBinaryOp<BinaryOp,Lhs,Rhs> ExpressionType;
|
||||
typedef typename ExpressionType::Scalar Scalar;
|
||||
typedef typename ei_traits<ExpressionType>::_LhsNested _LhsNested;
|
||||
// typedef typename ei_traits<ExpressionType>::LhsIterator LhsIterator;
|
||||
typedef typename ei_traits<ExpressionType>::_RhsNested _RhsNested;
|
||||
// typedef typename ei_traits<ExpressionType>::RhsIterator RhsIterator;
|
||||
// typedef typename ei_traits<CwiseBinaryOp>::_LhsNested _LhsNested;
|
||||
typedef typename _LhsNested::InnerIterator LhsIterator;
|
||||
// typedef typename ei_traits<CwiseBinaryOp>::_RhsNested _RhsNested;
|
||||
typedef typename _RhsNested::InnerIterator RhsIterator;
|
||||
// enum { IsProduct = ei_is_scalar_product<BinaryOp>::ret };
|
||||
public:
|
||||
|
||||
InnerIterator(const CwiseBinaryOp& binOp, int outer)
|
||||
: m_lhsIter(binOp.m_lhs,outer), m_rhsIter(binOp.m_rhs,outer), m_functor(binOp.m_functor), m_id(-1)
|
||||
EIGEN_STRONG_INLINE CwiseBinaryOpInnerIterator(const _LhsNested& lhs, const _RhsNested& rhs,
|
||||
const BinaryOp& functor, int outer)
|
||||
: m_lhsIter(lhs,outer), m_rhsIter(rhs,outer), m_functor(functor), m_id(-1)
|
||||
{
|
||||
this->operator++();
|
||||
}
|
||||
|
||||
InnerIterator& operator++()
|
||||
EIGEN_STRONG_INLINE Derived& operator++()
|
||||
{
|
||||
if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index()))
|
||||
{
|
||||
@@ -223,14 +254,14 @@ class CwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator
|
||||
{
|
||||
m_id = -1;
|
||||
}
|
||||
return *this;
|
||||
return *static_cast<Derived*>(this);
|
||||
}
|
||||
|
||||
Scalar value() const { return m_value; }
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_value; }
|
||||
|
||||
int index() const { return m_id; }
|
||||
EIGEN_STRONG_INLINE int index() const { return m_id; }
|
||||
|
||||
operator bool() const { return m_id>=0; }
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_id>=0; }
|
||||
|
||||
protected:
|
||||
LhsIterator m_lhsIter;
|
||||
@@ -239,5 +270,65 @@ class CwiseBinaryOp<BinaryOp,Lhs,Rhs>::InnerIterator
|
||||
Scalar m_value;
|
||||
int m_id;
|
||||
};
|
||||
/*
|
||||
template<typename T, typename Lhs, typename Rhs, typename Derived>
|
||||
class CwiseBinaryOpInnerIterator<ei_scalar_product_op<T>,Lhs,Rhs,Derived>
|
||||
{
|
||||
typedef typename CwiseBinaryOp::Scalar Scalar;
|
||||
typedef typename ei_traits<CwiseBinaryOp>::_LhsNested _LhsNested;
|
||||
typedef typename _LhsNested::InnerIterator LhsIterator;
|
||||
typedef typename ei_traits<CwiseBinaryOp>::_RhsNested _RhsNested;
|
||||
typedef typename _RhsNested::InnerIterator RhsIterator;
|
||||
public:
|
||||
|
||||
EIGEN_STRONG_INLINE CwiseBinaryOpInnerIterator(const CwiseBinaryOp& binOp, int outer)
|
||||
: m_lhsIter(binOp.m_lhs,outer), m_rhsIter(binOp.m_rhs,outer), m_functor(binOp.m_functor)//, m_id(-1)
|
||||
{
|
||||
//this->operator++();
|
||||
while (m_lhsIter && m_rhsIter && m_lhsIter.index() != m_rhsIter.index())
|
||||
{
|
||||
if (m_lhsIter.index() < m_rhsIter.index())
|
||||
++m_lhsIter;
|
||||
else
|
||||
++m_rhsIter;
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE Derived& operator++()
|
||||
{
|
||||
// m_id = -1;
|
||||
asm("#beginwhile");
|
||||
while (m_lhsIter && m_rhsIter)
|
||||
{
|
||||
if (m_lhsIter.index() == m_rhsIter.index())
|
||||
{
|
||||
// m_id = m_lhsIter.index();
|
||||
//m_value = m_functor(m_lhsIter.value(), m_rhsIter.value());
|
||||
++m_lhsIter;
|
||||
++m_rhsIter;
|
||||
break;
|
||||
}
|
||||
else if (m_lhsIter.index() < m_rhsIter.index())
|
||||
++m_lhsIter;
|
||||
else
|
||||
++m_rhsIter;
|
||||
}
|
||||
asm("#endwhile");
|
||||
return *static_cast<Derived*>(this);
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); }
|
||||
|
||||
EIGEN_STRONG_INLINE int index() const { return m_lhsIter.index(); }
|
||||
|
||||
EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter && m_rhsIter; }
|
||||
|
||||
protected:
|
||||
LhsIterator m_lhsIter;
|
||||
RhsIterator m_rhsIter;
|
||||
const BinaryOp& m_functor;
|
||||
// Scalar m_value;
|
||||
// int m_id;
|
||||
};*/
|
||||
|
||||
#endif // EIGEN_COREITERATORS_H
|
||||
|
||||
@@ -192,7 +192,7 @@ void SparseLDLT<MatrixType,Backend>::_symbolic(const MatrixType& a)
|
||||
m_matrix.resize(size, size);
|
||||
m_parent.resize(size);
|
||||
m_nonZerosPerCol.resize(size);
|
||||
int * tags = ei_aligned_stack_alloc(int, size);
|
||||
int * tags = ei_aligned_stack_new(int, size);
|
||||
|
||||
const int* Ap = a._outerIndexPtr();
|
||||
const int* Ai = a._innerIndexPtr();
|
||||
@@ -238,7 +238,7 @@ void SparseLDLT<MatrixType,Backend>::_symbolic(const MatrixType& a)
|
||||
Lp[k+1] = Lp[k] + m_nonZerosPerCol[k];
|
||||
|
||||
m_matrix.resizeNonZeros(Lp[size]);
|
||||
ei_aligned_stack_free(tags, int, size);
|
||||
ei_aligned_stack_delete(int, tags, size);
|
||||
}
|
||||
|
||||
template<typename MatrixType, int Backend>
|
||||
@@ -257,9 +257,9 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a)
|
||||
Scalar* Lx = m_matrix._valuePtr();
|
||||
m_diag.resize(size);
|
||||
|
||||
Scalar * y = ei_aligned_stack_alloc(Scalar, size);
|
||||
int * pattern = ei_aligned_stack_alloc(int, size);
|
||||
int * tags = ei_aligned_stack_alloc(int, size);
|
||||
Scalar * y = ei_aligned_stack_new(Scalar, size);
|
||||
int * pattern = ei_aligned_stack_new(int, size);
|
||||
int * tags = ei_aligned_stack_new(int, size);
|
||||
|
||||
const int* P = 0;
|
||||
const int* Pinv = 0;
|
||||
@@ -315,9 +315,9 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a)
|
||||
}
|
||||
}
|
||||
|
||||
ei_aligned_stack_free(y, Scalar, size);
|
||||
ei_aligned_stack_free(pattern, int, size);
|
||||
ei_aligned_stack_free(tags, int, size);
|
||||
ei_aligned_stack_delete(Scalar, y, size);
|
||||
ei_aligned_stack_delete(int, pattern, size);
|
||||
ei_aligned_stack_delete(int, tags, size);
|
||||
|
||||
return ok; /* success, diagonal of D is all nonzero */
|
||||
}
|
||||
|
||||
@@ -361,14 +361,14 @@ class SparseMatrix
|
||||
{
|
||||
EIGEN_DBG_SPARSE(
|
||||
s << "Nonzero entries:\n";
|
||||
for (unsigned int i=0; i<m.nonZeros(); ++i)
|
||||
for (int i=0; i<m.nonZeros(); ++i)
|
||||
{
|
||||
s << "(" << m.m_data.value(i) << "," << m.m_data.index(i) << ") ";
|
||||
}
|
||||
s << std::endl;
|
||||
s << std::endl;
|
||||
s << "Column pointers:\n";
|
||||
for (unsigned int i=0; i<m.cols(); ++i)
|
||||
for (int i=0; i<m.cols(); ++i)
|
||||
{
|
||||
s << m.m_outerIndex[i] << " ";
|
||||
}
|
||||
|
||||
@@ -167,6 +167,49 @@ class SparseMatrixBase : public MatrixBase<Derived>
|
||||
return s;
|
||||
}
|
||||
|
||||
// template<typename OtherDerived>
|
||||
// Scalar dot(const MatrixBase<OtherDerived>& other) const
|
||||
// {
|
||||
// EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
// EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
|
||||
// EIGEN_STATIC_ASSERT((ei_is_same_type<Scalar, typename OtherDerived::Scalar>::ret),
|
||||
// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
|
||||
//
|
||||
// ei_assert(derived().size() == other.size());
|
||||
// // short version, but the assembly looks more complicated because
|
||||
// // of the CwiseBinaryOp iterator complexity
|
||||
// // return res = (derived().cwise() * other.derived().conjugate()).sum();
|
||||
//
|
||||
// // optimized, generic version
|
||||
// typename Derived::InnerIterator i(derived(),0);
|
||||
// typename OtherDerived::InnerIterator j(other.derived(),0);
|
||||
// Scalar res = 0;
|
||||
// while (i && j)
|
||||
// {
|
||||
// if (i.index()==j.index())
|
||||
// {
|
||||
// // std::cerr << i.value() << " * " << j.value() << "\n";
|
||||
// res += i.value() * ei_conj(j.value());
|
||||
// ++i; ++j;
|
||||
// }
|
||||
// else if (i.index()<j.index())
|
||||
// ++i;
|
||||
// else
|
||||
// ++j;
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
// Scalar sum() const
|
||||
// {
|
||||
// Scalar res = 0;
|
||||
// for (typename Derived::InnerIterator iter(*this,0); iter; ++iter)
|
||||
// {
|
||||
// res += iter.value();
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
protected:
|
||||
|
||||
bool m_isRValue;
|
||||
|
||||
@@ -150,7 +150,7 @@ struct ei_sparse_product_selector<Lhs,Rhs,ResultType,ColMajor,ColMajor,ColMajor>
|
||||
float ratioRes = std::min(ratioLhs * avgNnzPerRhsColumn, 1.f);
|
||||
|
||||
res.resize(rows, cols);
|
||||
res.startFill(ratioRes*rows*cols);
|
||||
res.startFill(int(ratioRes*rows*cols));
|
||||
for (int j=0; j<cols; ++j)
|
||||
{
|
||||
// let's do a more accurate determination of the nnz ratio for the current column j of res
|
||||
|
||||
70
Eigen/src/Sparse/SparseRedux.h
Normal file
70
Eigen/src/Sparse/SparseRedux.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_SPARSEREDUX_H
|
||||
#define EIGEN_SPARSEREDUX_H
|
||||
|
||||
|
||||
template<typename Derived, int Vectorization, int Unrolling>
|
||||
struct ei_sum_impl<Derived, Vectorization, Unrolling, IsSparse>
|
||||
{
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
static Scalar run(const Derived& mat)
|
||||
{
|
||||
ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix");
|
||||
Scalar res = 0;
|
||||
for (int j=0; j<mat.outerSize(); ++j)
|
||||
for (typename Derived::InnerIterator iter(mat,j); iter; ++iter)
|
||||
res += iter.value();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Derived1, typename Derived2, int Vectorization, int Unrolling>
|
||||
struct ei_dot_impl<Derived1, Derived2, Vectorization, Unrolling, IsSparse>
|
||||
{
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
static Scalar run(const Derived1& v1, const Derived2& v2)
|
||||
{
|
||||
ei_assert(v1.size()>0 && "you are using a non initialized vector");
|
||||
typename Derived1::InnerIterator i(v1,0);
|
||||
typename Derived2::InnerIterator j(v2,0);
|
||||
Scalar res = 0;
|
||||
while (i && j)
|
||||
{
|
||||
if (i.index()==j.index())
|
||||
{
|
||||
res += i.value() * ei_conj(j.value());
|
||||
++i; ++j;
|
||||
}
|
||||
else if (i.index()<j.index())
|
||||
++i;
|
||||
else
|
||||
++j;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EIGEN_SPARSEREDUX_H
|
||||
@@ -272,6 +272,28 @@ class SparseVector
|
||||
return s;
|
||||
}
|
||||
|
||||
// this specialized version does not seems to be faster
|
||||
// Scalar dot(const SparseVector& other) const
|
||||
// {
|
||||
// int i=0, j=0;
|
||||
// Scalar res = 0;
|
||||
// asm("#begindot");
|
||||
// while (i<nonZeros() && j<other.nonZeros())
|
||||
// {
|
||||
// if (m_data.index(i)==other.m_data.index(j))
|
||||
// {
|
||||
// res += m_data.value(i) * ei_conj(other.m_data.value(j));
|
||||
// ++i; ++j;
|
||||
// }
|
||||
// else if (m_data.index(i)<other.m_data.index(j))
|
||||
// ++i;
|
||||
// else
|
||||
// ++j;
|
||||
// }
|
||||
// asm("#enddot");
|
||||
// return res;
|
||||
// }
|
||||
|
||||
/** Destructor */
|
||||
inline ~SparseVector() {}
|
||||
};
|
||||
|
||||
@@ -114,13 +114,13 @@ struct SluMatrix : SuperMatrix
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Scalar, int Rows, int Cols, int StorageOrder, int MRows, int MCols>
|
||||
struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,StorageOrder,MRows,MCols> >
|
||||
template<typename Scalar, int Rows, int Cols, int Options, int MRows, int MCols>
|
||||
struct SluMatrixMapHelper<Matrix<Scalar,Rows,Cols,Options,MRows,MCols> >
|
||||
{
|
||||
typedef Matrix<Scalar,Rows,Cols,StorageOrder,MRows,MCols> MatrixType;
|
||||
typedef Matrix<Scalar,Rows,Cols,Options,MRows,MCols> MatrixType;
|
||||
static void run(MatrixType& mat, SluMatrix& res)
|
||||
{
|
||||
assert(StorageOrder==0 && "row-major dense matrices is not supported by SuperLU");
|
||||
ei_assert( ((Options&RowMajor)!=RowMajor) && "row-major dense matrices is not supported by SuperLU");
|
||||
res.setStorageType(SLU_DN);
|
||||
res.setScalarType<Scalar>();
|
||||
res.Mtype = SLU_GE;
|
||||
@@ -139,7 +139,7 @@ struct SluMatrixMapHelper<SparseMatrix<Scalar,Flags> >
|
||||
typedef SparseMatrix<Scalar,Flags> MatrixType;
|
||||
static void run(MatrixType& mat, SluMatrix& res)
|
||||
{
|
||||
if (Flags&RowMajorBit)
|
||||
if ((Flags&RowMajorBit)==RowMajorBit)
|
||||
{
|
||||
res.setStorageType(SLU_NR);
|
||||
res.nrow = mat.cols();
|
||||
@@ -181,7 +181,7 @@ template<typename Scalar, int Flags>
|
||||
SparseMatrix<Scalar,Flags> SparseMatrix<Scalar,Flags>::Map(SluMatrix& sluMat)
|
||||
{
|
||||
SparseMatrix res;
|
||||
if (Flags&RowMajorBit)
|
||||
if ((Flags&RowMajorBit)==RowMajorBit)
|
||||
{
|
||||
assert(sluMat.Stype == SLU_NR);
|
||||
res.m_innerSize = sluMat.ncol;
|
||||
@@ -276,7 +276,7 @@ class SparseLU<MatrixType,SuperLU> : public SparseLU<MatrixType>
|
||||
mutable UMatrixType m_u;
|
||||
mutable IntColVectorType m_p;
|
||||
mutable IntRowVectorType m_q;
|
||||
|
||||
|
||||
mutable SparseMatrix<Scalar> m_matrix;
|
||||
mutable SluMatrix m_sluA;
|
||||
mutable SuperMatrix m_sluL, m_sluU;
|
||||
@@ -423,7 +423,7 @@ void SparseLU<MatrixType,SuperLU>::extractData() const
|
||||
int* Ucol = m_u._outerIndexPtr();
|
||||
int* Urow = m_u._innerIndexPtr();
|
||||
Scalar* Uval = m_u._valuePtr();
|
||||
|
||||
|
||||
Ucol[0] = 0;
|
||||
Ucol[0] = 0;
|
||||
|
||||
@@ -434,7 +434,7 @@ void SparseLU<MatrixType,SuperLU>::extractData() const
|
||||
istart = L_SUB_START(fsupc);
|
||||
nsupr = L_SUB_START(fsupc+1) - istart;
|
||||
upper = 1;
|
||||
|
||||
|
||||
/* for each column in the supernode */
|
||||
for (int j = fsupc; j < L_FST_SUPC(k+1); ++j)
|
||||
{
|
||||
|
||||
73
Eigen/src/StdVector/StdVector.h
Normal file
73
Eigen/src/StdVector/StdVector.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2009 Alex Stapleton <alex.stapleton@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_STDVECTOR_H
|
||||
#define EIGEN_STDVECTOR_H
|
||||
|
||||
#define EIGEN_STD_VECTOR_SPECIALIZATION_BODY \
|
||||
typedef Eigen::aligned_allocator<value_type> allocator_type; \
|
||||
typedef vector<value_type, allocator_type > unaligned_base; \
|
||||
typedef typename unaligned_base::size_type size_type; \
|
||||
typedef typename unaligned_base::iterator iterator; \
|
||||
explicit vector(const allocator_type& __a = allocator_type()) : unaligned_base(__a) {} \
|
||||
vector(const vector& c) : unaligned_base(c) {} \
|
||||
vector(size_type num, const value_type& val = value_type()) : unaligned_base(num, val) {}\
|
||||
vector(iterator start, iterator end) : unaligned_base(start, end) {} \
|
||||
vector& operator=(const vector& __x) { \
|
||||
unaligned_base::operator=(__x); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
template <typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols, typename _Alloc>
|
||||
class vector<Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>, _Alloc>
|
||||
: public vector<Eigen::ei_unaligned_type<Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> >,
|
||||
Eigen::aligned_allocator<Eigen::ei_unaligned_type<Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> > > >
|
||||
{
|
||||
public:
|
||||
typedef Eigen::ei_unaligned_type<Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> > value_type;
|
||||
EIGEN_STD_VECTOR_SPECIALIZATION_BODY
|
||||
};
|
||||
|
||||
template <typename _Scalar, int _Dim, typename _Alloc>
|
||||
class vector<Eigen::Transform<_Scalar,_Dim>, _Alloc>
|
||||
: public vector<Eigen::ei_unaligned_type<Eigen::Transform<_Scalar,_Dim> >,
|
||||
Eigen::aligned_allocator<Eigen::ei_unaligned_type<Eigen::Transform<_Scalar,_Dim> > > >
|
||||
{
|
||||
public:
|
||||
typedef Eigen::ei_unaligned_type<Eigen::Transform<_Scalar,_Dim> > value_type;
|
||||
EIGEN_STD_VECTOR_SPECIALIZATION_BODY
|
||||
};
|
||||
|
||||
template <typename _Scalar, typename _Alloc>
|
||||
class vector<Eigen::Quaternion<_Scalar>, _Alloc>
|
||||
: public vector<Eigen::ei_unaligned_type<Eigen::Quaternion<_Scalar> >,
|
||||
Eigen::aligned_allocator<Eigen::ei_unaligned_type<Eigen::Quaternion<_Scalar> > > >
|
||||
{
|
||||
public:
|
||||
typedef Eigen::ei_unaligned_type<Eigen::Quaternion<_Scalar> > value_type;
|
||||
EIGEN_STD_VECTOR_SPECIALIZATION_BODY
|
||||
};
|
||||
|
||||
#endif // EIGEN_STDVECTOR_H
|
||||
76
Eigen/src/StdVector/UnalignedType.h
Normal file
76
Eigen/src/StdVector/UnalignedType.h
Normal file
@@ -0,0 +1,76 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2009 Alex Stapleton <alex.stapleton@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_UNALIGNEDTYPE_H
|
||||
#define EIGEN_UNALIGNEDTYPE_H
|
||||
|
||||
template<typename aligned_type> class ei_unaligned_type;
|
||||
|
||||
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
|
||||
class ei_unaligned_type<Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> >
|
||||
: public Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>
|
||||
{
|
||||
public:
|
||||
typedef Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> aligned_base;
|
||||
ei_unaligned_type() : aligned_base(ei_constructor_without_unaligned_array_assert()) {}
|
||||
ei_unaligned_type(const aligned_base& other) : aligned_base(ei_constructor_without_unaligned_array_assert())
|
||||
{
|
||||
resize(other.rows(), other.cols());
|
||||
ei_assign_impl<ei_unaligned_type,aligned_base,NoVectorization>::run(*this, other);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Scalar, int _Dim>
|
||||
class ei_unaligned_type<Transform<_Scalar,_Dim> >
|
||||
: public Transform<_Scalar,_Dim>
|
||||
{
|
||||
public:
|
||||
typedef Transform<_Scalar,_Dim> aligned_base;
|
||||
typedef typename aligned_base::MatrixType MatrixType;
|
||||
ei_unaligned_type() : aligned_base(ei_constructor_without_unaligned_array_assert()) {}
|
||||
ei_unaligned_type(const aligned_base& other) : aligned_base(ei_constructor_without_unaligned_array_assert())
|
||||
{
|
||||
// no resizing here, it's fixed-size anyway
|
||||
ei_assign_impl<MatrixType,MatrixType,NoVectorization>::run(this->matrix(), other.matrix());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _Scalar>
|
||||
class ei_unaligned_type<Quaternion<_Scalar> >
|
||||
: public Quaternion<_Scalar>
|
||||
{
|
||||
public:
|
||||
typedef Quaternion<_Scalar> aligned_base;
|
||||
typedef typename aligned_base::Coefficients Coefficients;
|
||||
ei_unaligned_type() : aligned_base(ei_constructor_without_unaligned_array_assert()) {}
|
||||
ei_unaligned_type(const aligned_base& other) : aligned_base(ei_constructor_without_unaligned_array_assert())
|
||||
{
|
||||
// no resizing here, it's fixed-size anyway
|
||||
ei_assign_impl<Coefficients,Coefficients,NoVectorization>::run(this->coeffs(), other.coeffs());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // EIGEN_UNALIGNEDTYPE_H
|
||||
@@ -21,9 +21,9 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
int size = SIZE * 8;
|
||||
int size2 = size * size;
|
||||
Scalar* a = ei_aligned_malloc<Scalar>(size2);
|
||||
Scalar* b = ei_aligned_malloc<Scalar>(size2+4)+1;
|
||||
Scalar* c = ei_aligned_malloc<Scalar>(size2);
|
||||
Scalar* a = ei_aligned_new<Scalar>(size2);
|
||||
Scalar* b = ei_aligned_new<Scalar>(size2+4)+1;
|
||||
Scalar* c = ei_aligned_new<Scalar>(size2);
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
|
||||
@@ -16,10 +16,10 @@ if (EIGEN2_INCLUDE_DIR)
|
||||
else (EIGEN2_INCLUDE_DIR)
|
||||
|
||||
find_path(EIGEN2_INCLUDE_DIR NAMES Eigen/Core
|
||||
PATHS
|
||||
PATH_SUFFIXES eigen2
|
||||
HINTS
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
${KDE4_INCLUDE_DIR}
|
||||
PATH_SUFFIXES eigen2
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
@@ -38,16 +38,16 @@ public :
|
||||
typedef typename f77_interface_base<real>::gene_vector gene_vector;
|
||||
|
||||
static void free_matrix(gene_matrix & A, int N){
|
||||
ei_aligned_free(A, 0);
|
||||
ei_aligned_delete(A);
|
||||
}
|
||||
|
||||
static void free_vector(gene_vector & B){
|
||||
ei_aligned_free(B, 0);
|
||||
ei_aligned_delete(B);
|
||||
}
|
||||
|
||||
static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){
|
||||
int N = A_stl.size();
|
||||
A = ei_aligned_malloc<real>(N*N);
|
||||
A = ei_aligned_new<real>(N*N);
|
||||
for (int j=0;j<N;j++)
|
||||
for (int i=0;i<N;i++)
|
||||
A[i+N*j] = A_stl[j][i];
|
||||
@@ -55,7 +55,7 @@ public :
|
||||
|
||||
static inline void vector_from_stl(gene_vector & B, stl_vector & B_stl){
|
||||
int N = B_stl.size();
|
||||
B = ei_aligned_malloc<real>(N);
|
||||
B = ei_aligned_new<real>(N);
|
||||
for (int i=0;i<N;i++)
|
||||
B[i] = B_stl[i];
|
||||
}
|
||||
|
||||
@@ -3,19 +3,29 @@ if (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
|
||||
set(SUPERLU_FIND_QUIETLY TRUE)
|
||||
endif (SUPERLU_INCLUDES AND SUPERLU_LIBRARIES)
|
||||
|
||||
find_path(SUPERLU_INCLUDES
|
||||
NAMES
|
||||
superlu/supermatrix.h
|
||||
PATHS
|
||||
$ENV{SUPERLUDIR}
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
find_package(BLAS)
|
||||
|
||||
find_library(SUPERLU_LIBRARIES superlu PATHS $ENV{SUPERLUDIR} ${LIB_INSTALL_DIR})
|
||||
if(BLAS_FOUND)
|
||||
|
||||
find_path(SUPERLU_INCLUDES
|
||||
NAMES
|
||||
superlu/supermatrix.h
|
||||
PATHS
|
||||
$ENV{SUPERLUDIR}
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
)
|
||||
|
||||
if(SUPERLU_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(SUPERLU_LIBRARIES ${SUPERLU_LIBRARIES} -lgfortran)
|
||||
endif(SUPERLU_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
find_library(SUPERLU_LIBRARIES superlu PATHS $ENV{SUPERLUDIR} ${LIB_INSTALL_DIR})
|
||||
|
||||
if(SUPERLU_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(SUPERLU_LIBRARIES ${SUPERLU_LIBRARIES} -lgfortran)
|
||||
endif(SUPERLU_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
if(SUPERLU_LIBRARIES)
|
||||
set(SUPERLU_LIBRARIES ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
|
||||
endif(SUPERLU_LIBRARIES)
|
||||
|
||||
endif(BLAS_FOUND)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SUPERLU DEFAULT_MSG
|
||||
|
||||
38
doc/FixedSizeVectorizable.dox
Normal file
38
doc/FixedSizeVectorizable.dox
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace Eigen {
|
||||
|
||||
/** \page FixedSizeVectorizable Fixed-size vectorizable Eigen objects
|
||||
|
||||
The goal of this page is to explain what we mean by "fixed-size vectorizable".
|
||||
|
||||
\section summary Executive Summary
|
||||
|
||||
An Eigen object is called "fixed-size vectorizable" if it has fixed size and that size is a multiple of 16 bytes.
|
||||
|
||||
Examples include:
|
||||
\li Eigen::Vector2d
|
||||
\li Eigen::Vector4d
|
||||
\li Eigen::Vector4f
|
||||
\li Eigen::Matrix2d
|
||||
\li Eigen::Matrix2f
|
||||
\li Eigen::Matrix4d
|
||||
\li Eigen::Matrix4f
|
||||
\li Eigen::Transform3d
|
||||
\li Eigen::Transform3f
|
||||
\li Eigen::Quaterniond
|
||||
\li Eigen::Quaternionf
|
||||
|
||||
\section explanation Explanation
|
||||
|
||||
First, "fixed-size" should be clear: an Eigen object has fixed size if its number of rows and its number of columns are fixed at compile-time. So for example Matrix3f has fixed size, but MatrixXf doesn't (the opposite of fixed-size is dynamic-size).
|
||||
|
||||
The array of coefficients of a fixed-size Eigen object is a plain "static array", it is not dynamically allocated. For example, the data behind a Matrix4f is just a "float array[16]".
|
||||
|
||||
Fixed-size objects are typically very small, which means that we want to handle them with zero runtime overhead -- both in terms of memory usage and of speed.
|
||||
|
||||
Now, vectorization (both SSE and AltiVec) works with 128-bit packets. Moreover, for performance reasons, these packets need to be have 128-bit alignment.
|
||||
|
||||
So it turns out that the only way that fixed-size Eigen objects can be vectorized, is if their size is a multiple of 128 bits, or 16 bytes. Eigen will then request 16-byte alignment for these object, and henceforth rely on these objects being aligned so no runtime check for alignment is performed.
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -101,10 +101,10 @@ with size=50, rows=50, columns=1.
|
||||
|
||||
Here is this constructor:
|
||||
\code
|
||||
inline ei_matrix_storage(int size, int rows, int) : m_data(ei_aligned_malloc<T>(size)), m_rows(rows) {}
|
||||
inline ei_matrix_storage(int size, int rows, int) : m_data(ei_aligned_new<T>(size)), m_rows(rows) {}
|
||||
\endcode
|
||||
|
||||
Here, the \a m_data member is the actual array of coefficients of the matrix. As you see, it is dynamically allocated. Rather than calling new[] or malloc(), as you can see, we have our own ei_aligned_malloc defined in src/Core/util/Memory.h. What it does is that if vectorization is enabled, then it uses a platform-specific call to allocate a 128-bit-aligned array, as that is very useful for vectorization with both SSE2 and AltiVec. If vectorization is disabled, it amounts to the standard new[].
|
||||
Here, the \a m_data member is the actual array of coefficients of the matrix. As you see, it is dynamically allocated. Rather than calling new[] or malloc(), as you can see, we have our own ei_aligned_new defined in src/Core/util/Memory.h. What it does is that if vectorization is enabled, then it uses a platform-specific call to allocate a 128-bit-aligned array, as that is very useful for vectorization with both SSE2 and AltiVec. If vectorization is disabled, it amounts to the standard new[].
|
||||
|
||||
As you can see, the constructor also sets the \a m_rows member to \a size. Notice that there is no \a m_columns member: indeed, in this partial specialization of ei_matrix_storage, we know the number of columns at compile-time, since the _Cols template parameter is different from Dynamic. Namely, in our case, _Cols is 1, which is to say that our vector is just a matrix with 1 column. Hence, there is no need to store the number of columns as a runtime variable.
|
||||
|
||||
|
||||
40
doc/PassingByValue.dox
Normal file
40
doc/PassingByValue.dox
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace Eigen {
|
||||
|
||||
/** \page PassingByValue Passing Eigen objects by value to functions
|
||||
|
||||
Passing objects by value is almost always a very bad idea in C++, as this means useless copies, and one should pass them by reference instead.
|
||||
|
||||
With Eigen, this is even more important: passing \ref FixedSizeVectorizable "fixed-size vectorizable Eigen objects" by value is not only inefficient, it can be illegal or make your program crash! And the reason is that these Eigen objects have alignment modifiers that aren't respected when they are passed by value.
|
||||
|
||||
So for example, a function like this, where v is passed by value:
|
||||
|
||||
\code
|
||||
void my_function(Eigen::Vector2d v);
|
||||
\endcode
|
||||
|
||||
needs to be rewritten as follows, passing v by reference:
|
||||
|
||||
\code
|
||||
void my_function(const Eigen::Vector2d& v);
|
||||
\endcode
|
||||
|
||||
Likewise if you have a class having a Eigen object as member:
|
||||
|
||||
\code
|
||||
struct Foo
|
||||
{
|
||||
Eigen::Vector2d v;
|
||||
};
|
||||
void my_function(Foo v);
|
||||
\endcode
|
||||
|
||||
This function also needs to be rewritten like this:
|
||||
\code
|
||||
void my_function(const Foo& v);
|
||||
\endcode
|
||||
|
||||
Note that on the other hand, there is no problem with functions that return objects by value.
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
52
doc/StlContainers.dox
Normal file
52
doc/StlContainers.dox
Normal file
@@ -0,0 +1,52 @@
|
||||
namespace Eigen {
|
||||
|
||||
/** \page StlContainers Using STL Containers with Eigen
|
||||
|
||||
\b Table \b of \b contents
|
||||
- \ref summary
|
||||
- \ref allocator
|
||||
- \ref vector
|
||||
|
||||
\section summary Executive summary
|
||||
|
||||
Using STL containers on \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types" requires taking the following two steps:
|
||||
|
||||
\li A 16-byte-aligned allocator must be used. Eigen does provide one ready for use: aligned_allocator.
|
||||
\li If you want to use the std::vector container, you need to #include <Eigen/StdVector>.
|
||||
|
||||
These issues arise only with \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types". For other Eigen types, such as Vector3f or MatrixXd, no special care is needed when using STL containers.
|
||||
|
||||
\section allocator Using an aligned allocator
|
||||
|
||||
STL containers take an optional template parameter, the allocator type. When using STL containers on \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types", you need tell the container to use an allocator that will always allocate memory at 16-byte-aligned locations. Fortunately, Eigen does provide such an allocator: Eigen::aligned_allocator.
|
||||
|
||||
For example, instead of
|
||||
\code
|
||||
std::map<int, Eigen::Vector4f>
|
||||
\endcode
|
||||
you need to use
|
||||
\code
|
||||
std::map<int, Eigen::Vector4f, std::less<int>, Eigen::aligned_allocator<Eigen::Vector4f> >
|
||||
\endcode
|
||||
Note that here, the 3rd parameter "std::less<int>" is just the default value, we only had to specify it because we needed to specify the allocator type, that is the 4th parameter.
|
||||
|
||||
\section vector The case of std::vector
|
||||
|
||||
The situation with std::vector was even worse (explanation below) so we had to specialize it for Eigen types. The upside is that our specialization takes care of specifying the aligned allocator, so you don't need to worry about it. All you need to do is to #include <Eigen/StdVector>.
|
||||
|
||||
So as soon as you have
|
||||
\code
|
||||
#include<Eigen/StdVector>
|
||||
\endcode
|
||||
you can simply use
|
||||
\code
|
||||
std::vector<Eigen::Vector4f>
|
||||
\endcode
|
||||
without having to worry about anything.
|
||||
|
||||
<span class="note">\b Explanation: The resize() method of std::vector takes a value_type argument (defaulting to value_type()). So with std::vector<Eigen::Vector4f>, some Eigen::Vector4f objects will be passed by value, which discards any alignment modifiers, so a Eigen::Vector4f can be created at an unaligned location. In order to avoid that, the only solution we saw was to specialize std::vector to make it work on a slight modification of, here, Eigen::Vector4f, that is able to deal properly with this situation.
|
||||
</span>
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
149
doc/StructHavingEigenMembers.dox
Normal file
149
doc/StructHavingEigenMembers.dox
Normal file
@@ -0,0 +1,149 @@
|
||||
namespace Eigen {
|
||||
|
||||
/** \page StructHavingEigenMembers Structures Having Eigen Members
|
||||
|
||||
\b Table \b of \b contents
|
||||
- \ref summary
|
||||
- \ref what
|
||||
- \ref how
|
||||
- \ref why
|
||||
- \ref movetotop
|
||||
- \ref bugineigen
|
||||
- \ref conditional
|
||||
|
||||
\section summary Executive Summary
|
||||
|
||||
If you define a structure having members of \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types", you must overload its "operator new" so that it generates 16-bytes-aligned pointers. Fortunately, Eigen provides you with a macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW that does that for you.
|
||||
|
||||
\section what What kind of code needs to be changed?
|
||||
|
||||
The kind of code that needs to be changed is this:
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo *foo = new Foo;
|
||||
\endcode
|
||||
|
||||
In other words: you have a class that has as a member a \ref FixedSizeVectorizable "fixed-size vectorizable Eigen object", and then you dynamically create an object of that class.
|
||||
|
||||
\section how How should such code be modified?
|
||||
|
||||
Very easy, you just need to put a EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro in a public part of your class, like this:
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo *foo = new Foo;
|
||||
\endcode
|
||||
|
||||
This macro makes "new Foo" always return an aligned pointer.
|
||||
|
||||
\section why Why is this needed?
|
||||
|
||||
OK let's say that your code looks like this:
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo *foo = new Foo;
|
||||
\endcode
|
||||
|
||||
A Eigen::Vector2d consists of 2 doubles, which is 128 bits. Which is exactly the size of a SSE packet, which makes it possible to use SSE for all sorts of operations on this vector. But SSE instructions (at least the ones that Eigen uses, which are the fast ones) require 128-bit alignment. Otherwise you get a segmentation fault.
|
||||
|
||||
For this reason, Eigen takes care by itself to require 128-bit alignment for Eigen::Vector2d, by doing two things:
|
||||
\li Eigen requires 128-bit alignment for the Eigen::Vector2d's array (of 2 doubles). With GCC, this is done with a __attribute__ ((aligned(16))).
|
||||
\li Eigen overloads the "operator new" of Eigen::Vector2d so it will always return 128-bit aligned pointers.
|
||||
|
||||
Thus, normally, you don't have to worry about anything, Eigen handles alignment for you...
|
||||
|
||||
... except in one case. When you have a class Foo like above, and you dynamically allocate a new Foo as above, then, since Foo doesn't have aligned "operator new", the returned pointer foo is not necessarily 128-bit aligned.
|
||||
|
||||
The alignment attribute of the member v is then relative to the start of the class, foo. If the foo pointer wasn't aligned, then foo->v won't be aligned either!
|
||||
|
||||
The solution is to let class Foo have an aligned "operator new", as we showed in the previous section.
|
||||
|
||||
\section movetotop Should I then put all the members of Eigen types at the beginning of my class?
|
||||
|
||||
No, that's not needed. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So when you have code like
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
double x;
|
||||
Eigen::Vector2d v;
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
\endcode
|
||||
|
||||
it will work just fine. You do \b not need to rewrite it as
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
Eigen::Vector2d v;
|
||||
double x;
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
\endcode
|
||||
|
||||
\section dynamicsize What about dynamic-size matrices and vectors?
|
||||
|
||||
Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this issue. The issue discussed here is only with fixed-size matrices and vectors.
|
||||
|
||||
\section bugineigen So is this a bug in Eigen?
|
||||
|
||||
No, it's not our bug. It's more like an inherent problem of the C++ language -- though it must be said that any other existing language probably has the same problem. The problem is that there is no way that you can specify an aligned "operator new" that would propagate to classes having you as member data.
|
||||
|
||||
\section conditional What if I want to do this conditionnally (depending on template parameters) ?
|
||||
|
||||
For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false.
|
||||
|
||||
Example:
|
||||
|
||||
\code
|
||||
template<int n> class Foo
|
||||
{
|
||||
typedef Eigen::Matrix<float,n,1> Vector;
|
||||
enum { NeedsToAlign = (sizeof(Vector)%16)==0 };
|
||||
...
|
||||
Vector v;
|
||||
...
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo<4> *foo4 = new Foo<4>; // foo4 is guaranteed to be 128bit-aligned
|
||||
Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarantee
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ So in the basic example,
|
||||
|
||||
\code matrix1 = matrix2 + matrix3; \endcode
|
||||
|
||||
Eigen chooses lazy evaluation. Thus the arrays are traversed only once, producing optimized code. If you really want to force immediate evaluation, use \link MatrixBase::eval() eval() \endlink:
|
||||
Eigen chooses lazy evaluation. Thus the arrays are traversed only once, producing optimized code. If you really want to force immediate evaluation, use \link MatrixBase::eval() eval()\endlink:
|
||||
|
||||
\code matrix1 = (matrix2 + matrix3).eval(); \endcode
|
||||
|
||||
@@ -36,25 +36,25 @@ Here is now a more involved example:
|
||||
|
||||
Eigen chooses lazy evaluation at every stage in that example, which is clearly the correct choice. In fact, lazy evaluation is the "default choice" and Eigen will choose it except in a few circumstances.
|
||||
|
||||
<b>The first circumstance</b> in which Eigen chooses immediate evaluation, is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag \endlink. The most importat example of such an expression is the \link Product matrix product expression \endlink. For example, when you do
|
||||
<b>The first circumstance</b> in which Eigen chooses immediate evaluation, is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag\endlink. The most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
|
||||
|
||||
\code matrix = matrix * matrix; \endcode
|
||||
|
||||
Eigen first evaluates <tt>matrix * matrix</tt> into a temporary matrix, and then copies it into the original \c matrix. This guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products. It also doesn't cost much, as the cost of the matrix product itself is much higher.
|
||||
|
||||
What if you know what you are doing and want to force lazy evaluation? Then use \link MatrixBase::lazy() .lazy() \endlink instead. Here is an example:
|
||||
What if you know what you are doing and want to force lazy evaluation? Then use \link MatrixBase::lazy() .lazy()\endlink instead. Here is an example:
|
||||
|
||||
\code matrix1 = (matrix2 * matrix2).lazy(); \endcode
|
||||
|
||||
Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of lazy() here is to remove the evaluate-before-assigning \link flags flag \endlink and also the evaluate-before-nesting \link flags flag \endlink which we now discuss.
|
||||
Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of lazy() here is to remove the evaluate-before-assigning \link flags flag\endlink and also the evaluate-before-nesting \link flags flag\endlink which we now discuss.
|
||||
|
||||
<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag \endlink. Again, the most importat example of such an expression is the \link Product matrix product expression \endlink. For example, when you do
|
||||
<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
|
||||
|
||||
\code matrix1 = matrix2 + matrix3 * matrix4; \endcode
|
||||
|
||||
the product <tt>matrix3 * matrix4</tt> gets evaluated immediately into a temporary matrix. Indeed, experiments showed that it is often beneficial for performance to evaluate immediately matrix products when they are nested into bigger expressions.
|
||||
|
||||
Again, \link MatrixBase::lazy() .lazy() \endlink can be used to force lazy evaluation here.
|
||||
Again, \link MatrixBase::lazy() .lazy()\endlink can be used to force lazy evaluation here.
|
||||
|
||||
<b>The third circumstance</b> in which Eigen chooses immediate evaluation, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary. Indeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example:
|
||||
|
||||
|
||||
@@ -2,124 +2,75 @@ namespace Eigen {
|
||||
|
||||
/** \page UnalignedArrayAssert Explanation of the assertion on unaligned arrays
|
||||
|
||||
Hello! You are seeing this webpage because your program terminated on an assertion failure like this one:
|
||||
<pre>
|
||||
my_program: path/to/eigen2/Eigen/src/Core/MatrixStorage.h:44:
|
||||
Eigen::ei_matrix_array<T, Size, MatrixOptions, Align>::ei_matrix_array()
|
||||
[with T = double, int Size = 2, int MatrixOptions = 2, bool Align = true]:
|
||||
Assertion `(reinterpret_cast<size_t>(array) & 0xf) == 0 && "this assertion
|
||||
is explained here: http://eigen.tuxfamily.org/api/UnalignedArrayAssert.html
|
||||
**** READ THIS WEB PAGE !!! ****"' failed.
|
||||
</pre>
|
||||
|
||||
There are 3 known causes for this issue. Please read on to understand them and learn how to fix them.
|
||||
|
||||
\b Table \b of \b contents
|
||||
- \ref what
|
||||
- \ref how
|
||||
- \ref why
|
||||
- \ref movetotop
|
||||
- \ref bugineigen
|
||||
- \ref c1
|
||||
- \ref c2
|
||||
- \ref c3
|
||||
- \ref explanation
|
||||
|
||||
<hr>
|
||||
\section c1 Cause 1: Structures having Eigen objects as members
|
||||
|
||||
\section what What kind of code made this assertion fail?
|
||||
|
||||
If you saw the assertion failure that links to this page, then you probably have done something like that in your code:
|
||||
If you have code like this,
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
...
|
||||
//...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
//...
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
//...
|
||||
Foo *foo = new Foo;
|
||||
\endcode
|
||||
|
||||
In other words: you have probably in your code a class that has as a member a vectorizable fixed-size Eigen object, and you then dynamically allocated an object of that class.
|
||||
then you need to read this separate page: \ref StructHavingEigenMembers "Structures Having Eigen Members".
|
||||
|
||||
By "vectorizable fixed-size Eigen object" we mean an Eigen matrix or vector of fixed size, and whose size is a multiple of 128 bits. Examples include:
|
||||
\li Eigen::Vector2d
|
||||
\li Eigen::Vector4d
|
||||
\li Eigen::Vector4f
|
||||
\li Eigen::Matrix2d
|
||||
\li Eigen::Matrix2f
|
||||
\li Eigen::Matrix4d
|
||||
\li Eigen::Matrix4f
|
||||
\li Eigen::Transform3d
|
||||
\li Eigen::Transform3f
|
||||
Note that here, Eigen::Vector2d is only used as an example, more generally the issue arises for all \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types".
|
||||
|
||||
\section how How to fix this bug?
|
||||
\section c2 Cause 2: STL Containers
|
||||
|
||||
Very easy, you just need to let your class Foo publicly inherit Eigen::WithAlignedOperatorNew, like this:
|
||||
If you use STL Containers such as std::vector, std::map, ..., with Eigen objects, like this,
|
||||
|
||||
\code
|
||||
class Foo : public Eigen::WithAlignedOperatorNew
|
||||
{
|
||||
...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo *foo = new Foo;
|
||||
std::vector<Eigen::Matrix2f> my_vector;
|
||||
std::map<int, Eigen::Matrix2f> my_map;
|
||||
\endcode
|
||||
|
||||
With this, you should be out of trouble.
|
||||
then you need to read this separate page: \ref StlContainers "Using STL Containers with Eigen".
|
||||
|
||||
\section why So can you explain what's happening here?
|
||||
Note that here, Eigen::Matrix2f is only used as an example, more generally the issue arises for all \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types".
|
||||
|
||||
OK let's say that your code looks like this:
|
||||
\section c3 Cause 3: Passing Eigen objects by value
|
||||
|
||||
If some function in your code is getting an Eigen object passed by value, like this,
|
||||
|
||||
\code
|
||||
class Foo
|
||||
{
|
||||
...
|
||||
Eigen::Vector2d v;
|
||||
...
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
Foo *foo = new Foo;
|
||||
void func(Eigen::Vector4d v);
|
||||
\endcode
|
||||
|
||||
A Eigen::Vector2d consists of 2 doubles, which is 128 bits. Which is exactly the size of a SSE packet, which makes it possible to use SSE for all sorts of operations on this vector. But SSE instructions (at least the ones that Eigen uses, which are the fast ones) require 128-bit alignment. Otherwise you get a segmentation fault.
|
||||
then you need to read this separate page: \ref PassingByValue "Passing Eigen objects by value to functions".
|
||||
|
||||
For this reason, Eigen takes care by itself to require 128-bit alignment for Eigen::Vector2d, by doing two things:
|
||||
\li Eigen requires 128-bit alignment for the Eigen::Vector2d's array (of 2 doubles). With GCC, this is done with a __attribute__ ((aligned(16))).
|
||||
\li Eigen overloads the "operator new" of Eigen::Vector2d so it will always return 128-bit aligned pointers.
|
||||
Note that here, Eigen::Vector4d is only used as an example, more generally the issue arises for all \ref FixedSizeVectorizable "fixed-size vectorizable Eigen types".
|
||||
|
||||
Thus, normally, you don't have to worry about anything, Eigen handles alignment for you...
|
||||
\section explanation General explanation of this assertion
|
||||
|
||||
... except in one case. When you have a class Foo like above, and you dynamically allocate a new Foo as above, then, since Foo doesn't have aligned "operator new", the returned pointer foo is not necessarily 128-bit aligned.
|
||||
\ref FixedSizeVectorizable "fixed-size vectorizable Eigen objects" must absolutely be created at 16-byte-aligned locations, otherwise SIMD instructions adressing them will crash.
|
||||
|
||||
The alignment attribute of the member v is then relative to the start of the class, foo. If the foo pointer wasn't aligned, then foo->v won't be aligned either!
|
||||
Eigen normally takes care of these alignment issues for you, by setting an alignment attribute on them and by overloading their "operator new".
|
||||
|
||||
The solution is to let class Foo have an aligned "operator new", as we showed in the previous section.
|
||||
|
||||
\section movetotop Should I then put all the members of Eigen types at the beginning of my class?
|
||||
|
||||
No, that's not needed. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So when you have code like
|
||||
|
||||
\code
|
||||
class Foo : public Eigen::WithAlignedOperatorNew
|
||||
{
|
||||
double x;
|
||||
Eigen::Vector2d v;
|
||||
};
|
||||
\endcode
|
||||
|
||||
it will work just fine. You do \b not need to rewrite it as
|
||||
|
||||
\code
|
||||
class Foo : public Eigen::WithAlignedOperatorNew
|
||||
{
|
||||
Eigen::Vector2d v;
|
||||
double x;
|
||||
};
|
||||
\endcode
|
||||
|
||||
\section dynamicsize What about dynamic-size matrices and vectors?
|
||||
|
||||
Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this bug. The bug discussed here is only with fixed-size matrices and vectors.
|
||||
|
||||
\section bugineigen So is this a bug in Eigen?
|
||||
|
||||
No, it's not our bug. It's more like an inherent problem of the C++ language -- though it must be said that any other existing language probably has the same problem. The problem is that there is no way that you can specify an aligned "operator new" that would propagate to classes having you as member data.
|
||||
However there are a few corner cases where these alignment settings get overridden: they are the possible causes for this assertion.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
4
doc/snippets/Cwise_slash_equal.cpp
Normal file
4
doc/snippets/Cwise_slash_equal.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
Vector3d v(3,2,4);
|
||||
Vector3d w(5,4,2);
|
||||
v.cwise() /= w;
|
||||
cout << v << endl;
|
||||
4
doc/snippets/Cwise_times_equal.cpp
Normal file
4
doc/snippets/Cwise_times_equal.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
Vector3d v(1,2,3);
|
||||
Vector3d w(2,3,0);
|
||||
v.cwise() *= w;
|
||||
cout << v << endl;
|
||||
@@ -7,14 +7,17 @@ else(GSL_FOUND)
|
||||
endif(GSL_FOUND)
|
||||
|
||||
set(SPARSE_LIBS "")
|
||||
set(EIGEN_TESTED_BACKENDS "")
|
||||
set(EIGEN_MISSING_BACKENDS "")
|
||||
|
||||
find_package(Taucs)
|
||||
if(TAUCS_FOUND)
|
||||
add_definitions("-DEIGEN_TAUCS_SUPPORT")
|
||||
include_directories(${TAUCS_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${TAUCS_LIBRARIES})
|
||||
set(EIGEN_TESTED_BACKENDS ${EIGEN_TESTED_BACKENDS} Taucs)
|
||||
else(TAUCS_FOUND)
|
||||
message("TAUCS not found, this optional backend won't be tested")
|
||||
set(EIGEN_MISSING_BACKENDS ${EIGEN_MISSING_BACKENDS} Taucs)
|
||||
endif(TAUCS_FOUND)
|
||||
|
||||
find_package(Cholmod)
|
||||
@@ -22,21 +25,24 @@ if(CHOLMOD_FOUND)
|
||||
add_definitions("-DEIGEN_CHOLMOD_SUPPORT")
|
||||
include_directories(${CHOLMOD_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES})
|
||||
set(EIGEN_TESTED_BACKENDS ${EIGEN_TESTED_BACKENDS} Cholmod)
|
||||
else(CHOLMOD_FOUND)
|
||||
message("CHOLMOD not found, this optional backend won't be tested")
|
||||
set(EIGEN_MISSING_BACKENDS ${EIGEN_MISSING_BACKENDS} Cholmod)
|
||||
endif(CHOLMOD_FOUND)
|
||||
|
||||
if(NOT MSVC)
|
||||
option(EIGEN_TEST_NO_FORTRAN "Disable Fortran" OFF)
|
||||
if(NOT MSVC AND NOT EIGEN_TEST_NO_FORTRAN)
|
||||
enable_language(Fortran OPTIONAL)
|
||||
endif(NOT MSVC)
|
||||
endif(NOT MSVC AND NOT EIGEN_TEST_NO_FORTRAN)
|
||||
|
||||
find_package(Umfpack)
|
||||
if(UMFPACK_FOUND)
|
||||
add_definitions("-DEIGEN_UMFPACK_SUPPORT")
|
||||
include_directories(${UMFPACK_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES})
|
||||
set(EIGEN_TESTED_BACKENDS ${EIGEN_TESTED_BACKENDS} UmfPack)
|
||||
else(UMFPACK_FOUND)
|
||||
message("UMFPACK not found, this optional backend won't be tested")
|
||||
set(EIGEN_MISSING_BACKENDS ${EIGEN_MISSING_BACKENDS} UmfPack)
|
||||
endif(UMFPACK_FOUND)
|
||||
|
||||
find_package(SuperLU)
|
||||
@@ -44,16 +50,18 @@ if(SUPERLU_FOUND)
|
||||
add_definitions("-DEIGEN_SUPERLU_SUPPORT")
|
||||
include_directories(${SUPERLU_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES})
|
||||
set(EIGEN_TESTED_BACKENDS ${EIGEN_TESTED_BACKENDS} SuperLU)
|
||||
else(SUPERLU_FOUND)
|
||||
message("SUPERLU not found, this optional backend won't be tested")
|
||||
set(EIGEN_MISSING_BACKENDS ${EIGEN_MISSING_BACKENDS} SuperLU)
|
||||
endif(SUPERLU_FOUND)
|
||||
|
||||
find_package(GoogleHash)
|
||||
if(GOOGLEHASH_FOUND)
|
||||
add_definitions("-DEIGEN_GOOGLEHASH_SUPPORT")
|
||||
include_directories(${GOOGLEHASH_INCLUDES})
|
||||
set(EIGEN_TESTED_BACKENDS ${EIGEN_TESTED_BACKENDS} GoogleHash)
|
||||
else(GOOGLEHASH_FOUND)
|
||||
message("Google's hash library not found, those map implementations won't be tested")
|
||||
set(EIGEN_MISSING_BACKENDS ${EIGEN_MISSING_BACKENDS} GoogleHash)
|
||||
endif(GOOGLEHASH_FOUND)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
@@ -146,7 +154,6 @@ macro(ei_add_test testname)
|
||||
|
||||
endmacro(ei_add_test)
|
||||
|
||||
|
||||
enable_testing()
|
||||
|
||||
if(TEST_LIB)
|
||||
@@ -160,6 +167,7 @@ ei_add_test(nomalloc)
|
||||
ei_add_test(mixingtypes)
|
||||
ei_add_test(packetmath)
|
||||
ei_add_test(unalignedassert)
|
||||
ei_add_test(vectorization_logic)
|
||||
ei_add_test(basicstuff)
|
||||
ei_add_test(linearstructure)
|
||||
ei_add_test(cwiseop)
|
||||
@@ -186,6 +194,60 @@ ei_add_test(hyperplane)
|
||||
ei_add_test(parametrizedline)
|
||||
ei_add_test(alignedbox)
|
||||
ei_add_test(regression)
|
||||
ei_add_test(sparse_basic " " "${SPARSE_LIBS}")
|
||||
ei_add_test(stdvector)
|
||||
ei_add_test(sparse_basic)
|
||||
ei_add_test(sparse_vector)
|
||||
ei_add_test(sparse_solvers " " "${SPARSE_LIBS}")
|
||||
|
||||
# print a summary of the different options
|
||||
message("************************************************************")
|
||||
message("*** Eigen's unit tests configuration summary ***")
|
||||
message("************************************************************")
|
||||
if(GSL_FOUND)
|
||||
message("Comparison with GSL: ON")
|
||||
else(GSL_FOUND)
|
||||
message("Comparison with GSL: OFF")
|
||||
endif(GSL_FOUND)
|
||||
|
||||
message("Enabled backends: ${EIGEN_TESTED_BACKENDS}")
|
||||
message("Disabled backends: ${EIGEN_MISSING_BACKENDS}")
|
||||
|
||||
if(EIGEN_TEST_SSE2)
|
||||
message("SSE2: ON")
|
||||
else(EIGEN_TEST_SSE2)
|
||||
message("SSE2: AUTO")
|
||||
endif(EIGEN_TEST_SSE2)
|
||||
|
||||
if(EIGEN_TEST_SSE3)
|
||||
message("SSE3: ON")
|
||||
else(EIGEN_TEST_SSE3)
|
||||
message("SSE3: AUTO")
|
||||
endif(EIGEN_TEST_SSE3)
|
||||
|
||||
if(EIGEN_TEST_SSSE3)
|
||||
message("SSSE3: ON")
|
||||
else(EIGEN_TEST_SSSE3)
|
||||
message("SSSE3: AUTO")
|
||||
endif(EIGEN_TEST_SSSE3)
|
||||
|
||||
if(EIGEN_TEST_ALTIVEC)
|
||||
message("Altivec: ON")
|
||||
else(EIGEN_TEST_ALTIVEC)
|
||||
message("Altivec: AUTO")
|
||||
endif(EIGEN_TEST_ALTIVEC)
|
||||
|
||||
if(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
|
||||
message("Explicit vec: OFF")
|
||||
else(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
|
||||
message("Explicit vec: AUTO")
|
||||
endif(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
|
||||
|
||||
message("CXX: ${CMAKE_CXX_COMPILER}")
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version COMMAND head -n 1 OUTPUT_VARIABLE EIGEN_CXX_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
message("CXX_VERSION: ${EIGEN_CXX_VERSION_STRING}")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
message("CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
|
||||
message("Sparse lib flags: ${SPARSE_LIBS}")
|
||||
|
||||
message("************************************************************")
|
||||
|
||||
@@ -39,7 +39,7 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
|
||||
RealScalar largerEps = test_precision<RealScalar>();
|
||||
if (ei_is_same_type<RealScalar,float>::ret)
|
||||
largerEps = 1e-3f;
|
||||
largerEps = RealScalar(1e-3f);
|
||||
|
||||
MatrixType m1 = MatrixType::Random(rows, cols),
|
||||
m2 = MatrixType::Random(rows, cols),
|
||||
|
||||
@@ -48,7 +48,7 @@ template<typename BoxType> void alignedbox(const BoxType& _box)
|
||||
|
||||
b0.extend(p0);
|
||||
b0.extend(p1);
|
||||
VERIFY(b0.contains(p0*s1+(1.-s1)*p1));
|
||||
VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
|
||||
VERIFY(!b0.contains(p0 + (1+s1)*(p1-p0)));
|
||||
|
||||
(b2 = b0).extend(b1);
|
||||
|
||||
@@ -73,6 +73,9 @@ template<typename MatrixType> void cwiseops(const MatrixType& m)
|
||||
|
||||
VERIFY_IS_APPROX(m2, m2.cwise() * mones);
|
||||
VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1);
|
||||
m3 = m1;
|
||||
m3.cwise() *= m2;
|
||||
VERIFY_IS_APPROX(m3, m1.cwise() * m2);
|
||||
|
||||
VERIFY_IS_APPROX(mones, m2.cwise()/m2);
|
||||
if(NumTraits<Scalar>::HasFloatingPoint)
|
||||
@@ -87,6 +90,9 @@ template<typename MatrixType> void cwiseops(const MatrixType& m)
|
||||
// VERIFY_IS_APPROX(m1.cwise().pow(0.5), m1.cwise().sqrt());
|
||||
// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
|
||||
VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
|
||||
m3 = m1;
|
||||
m3.cwise() /= m2;
|
||||
VERIFY_IS_APPROX(m3, m1.cwise() / m2);
|
||||
}
|
||||
|
||||
// check min
|
||||
|
||||
@@ -24,39 +24,67 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
// test compilation with both a struct and a class...
|
||||
struct MyStruct : WithAlignedOperatorNew
|
||||
void check_handmade_aligned_malloc()
|
||||
{
|
||||
for(int i = 1; i < 1000; i++)
|
||||
{
|
||||
char *p = (char*)ei_handmade_aligned_malloc(i);
|
||||
VERIFY(size_t(p)%16==0);
|
||||
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
|
||||
for(int j = 0; j < i; j++) p[j]=0;
|
||||
ei_handmade_aligned_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void check_aligned_malloc()
|
||||
{
|
||||
for(int i = 1; i < 1000; i++)
|
||||
{
|
||||
char *p = (char*)ei_aligned_malloc(i);
|
||||
VERIFY(size_t(p)%16==0);
|
||||
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
|
||||
for(int j = 0; j < i; j++) p[j]=0;
|
||||
ei_aligned_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void check_aligned_new()
|
||||
{
|
||||
for(int i = 1; i < 1000; i++)
|
||||
{
|
||||
float *p = ei_aligned_new<float>(i);
|
||||
VERIFY(size_t(p)%16==0);
|
||||
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
|
||||
for(int j = 0; j < i; j++) p[j]=0;
|
||||
ei_aligned_delete(p,i);
|
||||
}
|
||||
}
|
||||
|
||||
void check_aligned_stack_alloc()
|
||||
{
|
||||
for(int i = 1; i < 1000; i++)
|
||||
{
|
||||
float *p = ei_aligned_stack_new(float,i);
|
||||
VERIFY(size_t(p)%16==0);
|
||||
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
|
||||
for(int j = 0; j < i; j++) p[j]=0;
|
||||
ei_aligned_stack_delete(float,p,i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// test compilation with both a struct and a class...
|
||||
struct MyStruct
|
||||
{
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
char dummychar;
|
||||
Vector4f avec;
|
||||
};
|
||||
|
||||
class MyClassA : public WithAlignedOperatorNew
|
||||
{
|
||||
public:
|
||||
char dummychar;
|
||||
Vector4f avec;
|
||||
};
|
||||
|
||||
// ..as well as with some other base classes
|
||||
|
||||
class MyBaseClass
|
||||
{
|
||||
public:
|
||||
char dummychar;
|
||||
float afloat;
|
||||
};
|
||||
|
||||
class MyClassB : public WithAlignedOperatorNew, public MyBaseClass
|
||||
{
|
||||
public:
|
||||
char dummychar;
|
||||
Vector4f avec;
|
||||
};
|
||||
|
||||
class MyClassC : public MyBaseClass, public WithAlignedOperatorNew
|
||||
class MyClassA
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
char dummychar;
|
||||
Vector4f avec;
|
||||
};
|
||||
@@ -70,8 +98,12 @@ template<typename T> void check_dynaligned()
|
||||
|
||||
void test_dynalloc()
|
||||
{
|
||||
// low level dynamic memory allocation
|
||||
CALL_SUBTEST(check_handmade_aligned_malloc());
|
||||
CALL_SUBTEST(check_aligned_malloc());
|
||||
CALL_SUBTEST(check_aligned_new());
|
||||
CALL_SUBTEST(check_aligned_stack_alloc());
|
||||
|
||||
#ifdef EIGEN_VECTORIZE
|
||||
for (int i=0; i<g_repeat*100; ++i)
|
||||
{
|
||||
CALL_SUBTEST( check_dynaligned<Vector4f>() );
|
||||
@@ -85,8 +117,6 @@ void test_dynalloc()
|
||||
{
|
||||
MyStruct foo0; VERIFY(size_t(foo0.avec.data())%16==0);
|
||||
MyClassA fooA; VERIFY(size_t(fooA.avec.data())%16==0);
|
||||
MyClassB fooB; VERIFY(size_t(fooB.avec.data())%16==0);
|
||||
MyClassC fooC; VERIFY(size_t(fooC.avec.data())%16==0);
|
||||
}
|
||||
|
||||
// dynamic allocation, single object
|
||||
@@ -94,12 +124,8 @@ void test_dynalloc()
|
||||
{
|
||||
MyStruct *foo0 = new MyStruct(); VERIFY(size_t(foo0->avec.data())%16==0);
|
||||
MyClassA *fooA = new MyClassA(); VERIFY(size_t(fooA->avec.data())%16==0);
|
||||
MyClassB *fooB = new MyClassB(); VERIFY(size_t(fooB->avec.data())%16==0);
|
||||
MyClassC *fooC = new MyClassC(); VERIFY(size_t(fooC->avec.data())%16==0);
|
||||
delete foo0;
|
||||
delete fooA;
|
||||
delete fooB;
|
||||
delete fooC;
|
||||
}
|
||||
|
||||
// dynamic allocation, array
|
||||
@@ -108,29 +134,8 @@ void test_dynalloc()
|
||||
{
|
||||
MyStruct *foo0 = new MyStruct[N]; VERIFY(size_t(foo0->avec.data())%16==0);
|
||||
MyClassA *fooA = new MyClassA[N]; VERIFY(size_t(fooA->avec.data())%16==0);
|
||||
MyClassB *fooB = new MyClassB[N]; VERIFY(size_t(fooB->avec.data())%16==0);
|
||||
MyClassC *fooC = new MyClassC[N]; VERIFY(size_t(fooC->avec.data())%16==0);
|
||||
delete[] foo0;
|
||||
delete[] fooA;
|
||||
delete[] fooB;
|
||||
delete[] fooC;
|
||||
}
|
||||
|
||||
// std::vector
|
||||
for (int i=0; i<g_repeat*100; ++i)
|
||||
{
|
||||
std::vector<Vector4f, ei_new_allocator<Vector4f> > vecs(N);
|
||||
for (int j=0; j<N; ++j)
|
||||
{
|
||||
VERIFY(size_t(vecs[j].data())%16==0);
|
||||
}
|
||||
std::vector<MyStruct,ei_new_allocator<MyStruct> > foos(N);
|
||||
for (int j=0; j<N; ++j)
|
||||
{
|
||||
VERIFY(size_t(foos[j].avec.data())%16==0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EIGEN_VECTORIZE
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ template<typename Scalar> void geometry(void)
|
||||
if (ei_is_same_type<Scalar,float>::ret)
|
||||
largeEps = 1e-3f;
|
||||
|
||||
Quaternionx q1, q2;
|
||||
Vector3 v0 = Vector3::Random(),
|
||||
v1 = Vector3::Random(),
|
||||
v2 = Vector3::Random();
|
||||
@@ -69,6 +68,13 @@ template<typename Scalar> void geometry(void)
|
||||
(v0.cross(v1).cross(v0)).normalized();
|
||||
VERIFY(m.isUnitary());
|
||||
|
||||
// Quaternion: Identity(), setIdentity();
|
||||
Quaternionx q1, q2;
|
||||
q2.setIdentity();
|
||||
VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
|
||||
q1.coeffs().setRandom();
|
||||
VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
|
||||
|
||||
// unitOrthogonal
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().dot(u0), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
|
||||
|
||||
16
test/map.cpp
16
test/map.cpp
@@ -31,8 +31,8 @@ template<typename VectorType> void map_class(const VectorType& m)
|
||||
int size = m.size();
|
||||
|
||||
// test Map.h
|
||||
Scalar* array1 = ei_aligned_malloc<Scalar>(size);
|
||||
Scalar* array2 = ei_aligned_malloc<Scalar>(size);
|
||||
Scalar* array1 = ei_aligned_new<Scalar>(size);
|
||||
Scalar* array2 = ei_aligned_new<Scalar>(size);
|
||||
Scalar* array3 = new Scalar[size+1];
|
||||
Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
|
||||
|
||||
@@ -45,8 +45,8 @@ template<typename VectorType> void map_class(const VectorType& m)
|
||||
VERIFY_IS_APPROX(ma1, ma2);
|
||||
VERIFY_IS_APPROX(ma1, ma3);
|
||||
|
||||
ei_aligned_free(array1, size);
|
||||
ei_aligned_free(array2, size);
|
||||
ei_aligned_delete(array1, size);
|
||||
ei_aligned_delete(array2, size);
|
||||
delete[] array3;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ template<typename VectorType> void map_static_methods(const VectorType& m)
|
||||
int size = m.size();
|
||||
|
||||
// test Map.h
|
||||
Scalar* array1 = ei_aligned_malloc<Scalar>(size);
|
||||
Scalar* array2 = ei_aligned_malloc<Scalar>(size);
|
||||
Scalar* array1 = ei_aligned_new<Scalar>(size);
|
||||
Scalar* array2 = ei_aligned_new<Scalar>(size);
|
||||
Scalar* array3 = new Scalar[size+1];
|
||||
Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
|
||||
|
||||
@@ -71,8 +71,8 @@ template<typename VectorType> void map_static_methods(const VectorType& m)
|
||||
VERIFY_IS_APPROX(ma1, ma2);
|
||||
VERIFY_IS_APPROX(ma1, ma3);
|
||||
|
||||
ei_aligned_free(array1, size);
|
||||
ei_aligned_free(array2, size);
|
||||
ei_aligned_delete(array1, size);
|
||||
ei_aligned_delete(array2, size);
|
||||
delete[] array3;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,7 @@ void test_meta()
|
||||
VERIFY(( ei_is_same_type<float,ei_unpointer<float* const >::type >::ret));
|
||||
|
||||
VERIFY(ei_meta_sqrt<1>::ret == 1);
|
||||
#define VERIFY_META_SQRT(X) \
|
||||
std::cerr << ei_meta_sqrt<X>::ret << " == " << int(ei_sqrt(double(X))) << "\n"; \
|
||||
VERIFY(ei_meta_sqrt<X>::ret == int(ei_sqrt(double(X))))
|
||||
#define VERIFY_META_SQRT(X) VERIFY(ei_meta_sqrt<X>::ret == int(ei_sqrt(double(X))))
|
||||
VERIFY_META_SQRT(2);
|
||||
VERIFY_META_SQRT(3);
|
||||
VERIFY_META_SQRT(4);
|
||||
|
||||
@@ -25,28 +25,13 @@
|
||||
|
||||
// this hack is needed to make this file compiles with -pedantic (gcc)
|
||||
#define throw(X)
|
||||
// discard vectorization since the global operator new is not called in that case
|
||||
#define EIGEN_DONT_VECTORIZE 1
|
||||
// discard stack allocation as that too bypasses the global operator new
|
||||
// discard stack allocation as that too bypasses malloc
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 0
|
||||
// any heap allocation will raise an assert
|
||||
#define EIGEN_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void* operator new[] (size_t n)
|
||||
{
|
||||
ei_assert(false && "operator new should never be called with fixed size path");
|
||||
// the following is in case assertion are disabled
|
||||
std::cerr << "operator new should never be called with fixed size path" << std::endl;
|
||||
exit(2);
|
||||
void* p = malloc(n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete[](void* p) throw()
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void nomalloc(const MatrixType& m)
|
||||
{
|
||||
/* this test check no dynamic memory allocation are issued with fixed-size matrices
|
||||
|
||||
@@ -58,7 +58,7 @@ initSparse(double density,
|
||||
std::vector<Vector2i>* zeroCoords = 0,
|
||||
std::vector<Vector2i>* nonzeroCoords = 0)
|
||||
{
|
||||
sparseMat.startFill(refMat.rows()*refMat.cols()*density);
|
||||
sparseMat.startFill(int(refMat.rows()*refMat.cols()*density));
|
||||
for(int j=0; j<refMat.cols(); j++)
|
||||
{
|
||||
for(int i=0; i<refMat.rows(); i++)
|
||||
@@ -89,4 +89,28 @@ initSparse(double density,
|
||||
sparseMat.endFill();
|
||||
}
|
||||
|
||||
template<typename Scalar> void
|
||||
initSparse(double density,
|
||||
Matrix<Scalar,Dynamic,1>& refVec,
|
||||
SparseVector<Scalar>& sparseVec,
|
||||
std::vector<int>* zeroCoords = 0,
|
||||
std::vector<int>* nonzeroCoords = 0)
|
||||
{
|
||||
sparseVec.reserve(int(refVec.size()*density));
|
||||
sparseVec.setZero();
|
||||
for(int i=0; i<refVec.size(); i++)
|
||||
{
|
||||
Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
|
||||
if (v!=Scalar(0))
|
||||
{
|
||||
sparseVec.fill(i) = v;
|
||||
if (nonzeroCoords)
|
||||
nonzeroCoords->push_back(i);
|
||||
}
|
||||
else if (zeroCoords)
|
||||
zeroCoords->push_back(i);
|
||||
refVec[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EIGEN_TESTSPARSE_H
|
||||
|
||||
92
test/sparse_vector.cpp
Normal file
92
test/sparse_vector.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "sparse.h"
|
||||
|
||||
template<typename Scalar> void sparse_vector(int rows, int cols)
|
||||
{
|
||||
double densityMat = std::max(8./(rows*cols), 0.01);
|
||||
double densityVec = std::max(8./float(rows), 0.1);
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
typedef SparseVector<Scalar> SparseVectorType;
|
||||
typedef SparseMatrix<Scalar> SparseMatrixType;
|
||||
Scalar eps = 1e-6;
|
||||
|
||||
SparseMatrixType m1(rows,cols);
|
||||
SparseVectorType v1(rows), v2(rows), v3(rows);
|
||||
DenseMatrix refM1 = DenseMatrix::Zero(rows, cols);
|
||||
DenseVector refV1 = DenseVector::Random(rows),
|
||||
refV2 = DenseVector::Random(rows),
|
||||
refV3 = DenseVector::Random(rows);
|
||||
|
||||
std::vector<int> zerocoords, nonzerocoords;
|
||||
initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
|
||||
initSparse<Scalar>(densityMat, refM1, m1);
|
||||
|
||||
initSparse<Scalar>(densityVec, refV2, v2);
|
||||
initSparse<Scalar>(densityVec, refV3, v3);
|
||||
|
||||
Scalar s1 = ei_random<Scalar>();
|
||||
|
||||
// test coeff and coeffRef
|
||||
for (unsigned int i=0; i<zerocoords.size(); ++i)
|
||||
{
|
||||
VERIFY_IS_MUCH_SMALLER_THAN( v1.coeff(zerocoords[i]), eps );
|
||||
VERIFY_RAISES_ASSERT( v1.coeffRef(zerocoords[i]) = 5 );
|
||||
}
|
||||
{
|
||||
VERIFY(int(nonzerocoords.size()) == v1.nonZeros());
|
||||
int j=0;
|
||||
for (typename SparseVectorType::InnerIterator it(v1); it; ++it,++j)
|
||||
{
|
||||
VERIFY(nonzerocoords[j]==it.index());
|
||||
VERIFY(it.value()==v1[it.index()]);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(v1, refV1);
|
||||
|
||||
v1.coeffRef(nonzerocoords[0]) = Scalar(5);
|
||||
refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
|
||||
VERIFY_IS_APPROX(v1, refV1);
|
||||
|
||||
VERIFY_IS_APPROX(v1+v2, refV1+refV2);
|
||||
VERIFY_IS_APPROX(v1+v2+v3, refV1+refV2+refV3);
|
||||
|
||||
VERIFY_IS_APPROX(v1*s1-v2, refV1*s1-refV2);
|
||||
|
||||
std::cerr << v1.dot(v2) << " == " << refV1.dot(refV2) << "\n";
|
||||
VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2));
|
||||
|
||||
}
|
||||
|
||||
void test_sparse_vector()
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST( sparse_vector<double>(8, 8) );
|
||||
// CALL_SUBTEST( sparse_vector<std::complex<double> >(16, 16) );
|
||||
CALL_SUBTEST( sparse_vector<double>(299, 535) );
|
||||
}
|
||||
}
|
||||
|
||||
163
test/stdvector.cpp
Normal file
163
test/stdvector.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/StdVector>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
template<typename MatrixType>
|
||||
void check_stdvector_matrix(const MatrixType& m)
|
||||
{
|
||||
int rows = m.rows();
|
||||
int cols = m.cols();
|
||||
MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
|
||||
std::vector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
|
||||
v[5] = x;
|
||||
w[6] = v[5];
|
||||
VERIFY_IS_APPROX(w[6], v[5]);
|
||||
v = w;
|
||||
for(int i = 0; i < 20; i++)
|
||||
{
|
||||
VERIFY_IS_APPROX(w[i], v[i]);
|
||||
}
|
||||
|
||||
v.resize(21);
|
||||
v[20].set(x);
|
||||
VERIFY_IS_APPROX(v[20], x);
|
||||
v.resize(22,y);
|
||||
VERIFY_IS_APPROX(v[21], y);
|
||||
v.push_back(x);
|
||||
VERIFY_IS_APPROX(v[22], x);
|
||||
VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
|
||||
|
||||
// do a lot of push_back such that the vector gets internally resized
|
||||
// (with memory reallocation)
|
||||
MatrixType* ref = &w[0];
|
||||
for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
|
||||
v.push_back(w[i%w.size()]);
|
||||
for(unsigned int i=23; i<v.size(); ++i)
|
||||
{
|
||||
VERIFY(v[i]==w[(i-23)%w.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TransformType>
|
||||
void check_stdvector_transform(const TransformType&)
|
||||
{
|
||||
typedef typename TransformType::MatrixType MatrixType;
|
||||
TransformType x(MatrixType::Random()), y(MatrixType::Random());
|
||||
std::vector<TransformType> v(10), w(20, y);
|
||||
v[5] = x;
|
||||
w[6] = v[5];
|
||||
VERIFY_IS_APPROX(w[6], v[5]);
|
||||
v = w;
|
||||
for(int i = 0; i < 20; i++)
|
||||
{
|
||||
VERIFY_IS_APPROX(w[i], v[i]);
|
||||
}
|
||||
|
||||
v.resize(21);
|
||||
v[20] = x;
|
||||
VERIFY_IS_APPROX(v[20], x);
|
||||
v.resize(22,y);
|
||||
VERIFY_IS_APPROX(v[21], y);
|
||||
v.push_back(x);
|
||||
VERIFY_IS_APPROX(v[22], x);
|
||||
VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
|
||||
|
||||
// do a lot of push_back such that the vector gets internally resized
|
||||
// (with memory reallocation)
|
||||
TransformType* ref = &w[0];
|
||||
for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
|
||||
v.push_back(w[i%w.size()]);
|
||||
for(unsigned int i=23; i<v.size(); ++i)
|
||||
{
|
||||
VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename QuaternionType>
|
||||
void check_stdvector_quaternion(const QuaternionType&)
|
||||
{
|
||||
typedef typename QuaternionType::Coefficients Coefficients;
|
||||
QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
|
||||
std::vector<QuaternionType> v(10), w(20, y);
|
||||
v[5] = x;
|
||||
w[6] = v[5];
|
||||
VERIFY_IS_APPROX(w[6], v[5]);
|
||||
v = w;
|
||||
for(int i = 0; i < 20; i++)
|
||||
{
|
||||
VERIFY_IS_APPROX(w[i], v[i]);
|
||||
}
|
||||
|
||||
v.resize(21);
|
||||
v[20] = x;
|
||||
VERIFY_IS_APPROX(v[20], x);
|
||||
v.resize(22,y);
|
||||
VERIFY_IS_APPROX(v[21], y);
|
||||
v.push_back(x);
|
||||
VERIFY_IS_APPROX(v[22], x);
|
||||
VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
|
||||
|
||||
// do a lot of push_back such that the vector gets internally resized
|
||||
// (with memory reallocation)
|
||||
QuaternionType* ref = &w[0];
|
||||
for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
|
||||
v.push_back(w[i%w.size()]);
|
||||
for(unsigned int i=23; i<v.size(); ++i)
|
||||
{
|
||||
VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
|
||||
}
|
||||
}
|
||||
|
||||
void test_stdvector()
|
||||
{
|
||||
// some non vectorizable fixed sizes
|
||||
CALL_SUBTEST(check_stdvector_matrix(Vector2f()));
|
||||
CALL_SUBTEST(check_stdvector_matrix(Matrix3f()));
|
||||
CALL_SUBTEST(check_stdvector_matrix(Matrix3d()));
|
||||
|
||||
// some vectorizable fixed sizes
|
||||
CALL_SUBTEST(check_stdvector_matrix(Matrix2f()));
|
||||
CALL_SUBTEST(check_stdvector_matrix(Vector4f()));
|
||||
CALL_SUBTEST(check_stdvector_matrix(Matrix4f()));
|
||||
CALL_SUBTEST(check_stdvector_matrix(Matrix4d()));
|
||||
|
||||
// some dynamic sizes
|
||||
CALL_SUBTEST(check_stdvector_matrix(MatrixXd(1,1)));
|
||||
CALL_SUBTEST(check_stdvector_matrix(VectorXd(20)));
|
||||
CALL_SUBTEST(check_stdvector_matrix(RowVectorXf(20)));
|
||||
CALL_SUBTEST(check_stdvector_matrix(MatrixXcf(10,10)));
|
||||
|
||||
// some Transform
|
||||
CALL_SUBTEST(check_stdvector_transform(Transform2f()));
|
||||
CALL_SUBTEST(check_stdvector_transform(Transform3f()));
|
||||
CALL_SUBTEST(check_stdvector_transform(Transform3d()));
|
||||
//CALL_SUBTEST(check_stdvector_transform(Transform4d()));
|
||||
|
||||
// some Quaternion
|
||||
CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
|
||||
CALL_SUBTEST(check_stdvector_quaternion(Quaternionf()));
|
||||
}
|
||||
205
test/testsuite.cmake
Normal file
205
test/testsuite.cmake
Normal file
@@ -0,0 +1,205 @@
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# Usage:
|
||||
# - create a new folder, let's call it cdash
|
||||
# - in that folder, do:
|
||||
# ctest -S path/to/eigen2/test/testsuite.cmake[,option1=value1[,option2=value2]]
|
||||
#
|
||||
# Options:
|
||||
# - EIGEN_CXX: compiler, eg.: g++-4.2
|
||||
# default: default c++ compiler
|
||||
# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc.
|
||||
# default: hostname
|
||||
# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that:
|
||||
# <OS_name>-<OS_version>-<arch>-<compiler-version>
|
||||
# with:
|
||||
# <OS_name> = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc.
|
||||
# <OS_version> = 11.1, XP, vista, leopard, etc.
|
||||
# <arch> = i386, x86_64, ia64, powerpc, etc.
|
||||
# <compiler-version> = gcc-4.3.2, icc-11.0, MSVC-2008, etc.
|
||||
# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec
|
||||
# default: SSE2 for x86_64 systems, novec otherwise
|
||||
# - EIGEN_CMAKE_DIR: path to cmake executable
|
||||
# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous
|
||||
# default: Nightly
|
||||
# - EIGEN_WORK_DIRECTORY: directory used to download the source files and make the builds
|
||||
# default: folder which contains this script
|
||||
# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on)
|
||||
# default: <EIGEN_WORK_DIRECTORY>/src
|
||||
# - CTEST_BINARY_DIRECTORY: build directory
|
||||
# default: <EIGEN_WORK_DIRECTORY>/nightly-<EIGEN_CXX>
|
||||
#
|
||||
# Here is an example running several compilers on a linux system:
|
||||
# #!/bin/bash
|
||||
# EIGEN_ARCH=`uname -m`
|
||||
# EIGEN_SITE=`hostname`
|
||||
# EIGEN_OS_VERSION=opensuse-11.1
|
||||
# COMMON=/home/gael/Coding/eigen2/test/testsuite.cmake,EIGEN_WORK_DIRECTORY=/home/gael/Coding/eigen2/cdash,EIGEN_SITE=$EIGEN_SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$EIGEN_OS_VERSION-$EIGEN_ARCH
|
||||
# ctest -S $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4
|
||||
# ctest -S $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1
|
||||
# ctest -S $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3
|
||||
# ctest -S $COMMON-icc-11.0,EIGEN_CXX=icpc
|
||||
#
|
||||
####################################################################
|
||||
|
||||
# process the arguments
|
||||
|
||||
set(ARGLIST ${CTEST_SCRIPT_ARG})
|
||||
while(${ARGLIST} MATCHES ".+.*")
|
||||
|
||||
# pick first
|
||||
string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST})
|
||||
SET(TOP ${CMAKE_MATCH_1})
|
||||
|
||||
# remove first
|
||||
string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST})
|
||||
SET(ARGLIST ${CMAKE_MATCH_1})
|
||||
|
||||
# decompose as a pair key=value
|
||||
string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP})
|
||||
SET(KEY ${CMAKE_MATCH_1})
|
||||
|
||||
string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP})
|
||||
SET(VALUE ${CMAKE_MATCH_1})
|
||||
|
||||
# set the variable to the specified value
|
||||
if(VALUE)
|
||||
SET(${KEY} ${VALUE})
|
||||
else(VALUE)
|
||||
SET(${KEY} ON)
|
||||
endif(VALUE)
|
||||
|
||||
endwhile(${ARGLIST} MATCHES ".+.*")
|
||||
|
||||
####################################################################
|
||||
# Automatically set some user variables if they have not been defined manually
|
||||
####################################################################
|
||||
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||
|
||||
if(NOT EIGEN_SITE)
|
||||
site_name(EIGEN_SITE)
|
||||
endif(NOT EIGEN_SITE)
|
||||
|
||||
if(NOT EIGEN_CMAKE_DIR)
|
||||
SET(EIGEN_CMAKE_DIR "")
|
||||
endif(NOT EIGEN_CMAKE_DIR)
|
||||
|
||||
if(NOT EIGEN_BUILD_STRING)
|
||||
|
||||
# let's try to find all information we need to make the build string ourself
|
||||
|
||||
# OS
|
||||
# if(CYGWIN)
|
||||
# SET(EIGEN_OS_VERSION cygwin)
|
||||
# elseif(WIN32)
|
||||
# SET(EIGEN_OS_VERSION windows)
|
||||
# elseif(UNIX)
|
||||
# SET(EIGEN_OS_VERSION unix)
|
||||
# elseif(APPLE)
|
||||
# SET(EIGEN_OS_VERSION osx)
|
||||
# else(CYGWIN)
|
||||
build_name(EIGEN_OS_VERSION)
|
||||
# endif(CYGWIN)
|
||||
|
||||
# arch
|
||||
set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR})
|
||||
if(WIN32)
|
||||
set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE})
|
||||
else(WIN32)
|
||||
execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(WIN32)
|
||||
|
||||
set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX})
|
||||
|
||||
endif(NOT EIGEN_BUILD_STRING)
|
||||
|
||||
if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
|
||||
set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION})
|
||||
endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
|
||||
|
||||
if(NOT EIGEN_WORK_DIRECTORY)
|
||||
set(EIGEN_WORK_DIRECTORY ${CTEST_SCRIPT_DIRECTORY})
|
||||
endif(NOT EIGEN_WORK_DIRECTORY)
|
||||
|
||||
if(NOT CTEST_SOURCE_DIRECTORY)
|
||||
SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIRECTORY}/src")
|
||||
endif(NOT CTEST_SOURCE_DIRECTORY)
|
||||
|
||||
if(NOT CTEST_BINARY_DIRECTORY)
|
||||
SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIRECTORY}/nightly_${EIGEN_CXX}")
|
||||
endif(NOT CTEST_BINARY_DIRECTORY)
|
||||
|
||||
if(NOT EIGEN_MODE)
|
||||
set(EIGEN_MODE Nightly)
|
||||
endif(NOT EIGEN_MODE)
|
||||
|
||||
## mandatory variables (the default should be ok in most cases):
|
||||
|
||||
SET (CTEST_CVS_COMMAND "svn")
|
||||
SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} co svn://anonsvn.kde.org/home/kde/trunk/kdesupport/eigen2 \"${CTEST_SOURCE_DIRECTORY}\"")
|
||||
|
||||
# which ctest command to use for running the dashboard
|
||||
SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}")
|
||||
# what cmake command to use for configuring this dashboard
|
||||
SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_BUILD_TESTS=on ")
|
||||
|
||||
####################################################################
|
||||
# The values in this section are optional you can either
|
||||
# have them or leave them commented out
|
||||
####################################################################
|
||||
|
||||
# this make sure we get consistent outputs
|
||||
SET($ENV{LC_MESSAGES} "en_EN")
|
||||
|
||||
# should ctest wipe the binary tree before running
|
||||
SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
|
||||
SET(CTEST_BACKUP_AND_RESTORE TRUE)
|
||||
|
||||
# this is the initial cache to use for the binary tree, be careful to escape
|
||||
# any quotes inside of this string if you use it
|
||||
if(WIN32)
|
||||
#message(SEND_ERROR "win32")
|
||||
set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake")
|
||||
SET (CTEST_INITIAL_CACHE "
|
||||
MAKECOMMAND:STRING=nmake -i
|
||||
CMAKE_MAKE_PROGRAM:FILEPATH=nmake
|
||||
CMAKE_GENERATOR:INTERNAL=NMake Makefiles
|
||||
BUILDNAME:STRING=${EIGEN_BUILD_STRING}
|
||||
SITE:STRING=${EIGEN_SITE}
|
||||
")
|
||||
else(WIN32)
|
||||
SET (CTEST_INITIAL_CACHE "
|
||||
BUILDNAME:STRING=${EIGEN_BUILD_STRING}
|
||||
SITE:STRING=${EIGEN_SITE}
|
||||
")
|
||||
endif(WIN32)
|
||||
|
||||
# MAKECOMMAND:STRING=nmake -i
|
||||
# CMAKE_MAKE_PROGRAM:FILEPATH=make
|
||||
# CMAKE_GENERATOR:INTERNAL=Makefiles
|
||||
SET (CTEST_INITIAL_CACHE "
|
||||
BUILDNAME:STRING=opensuse-11_1-x86_64-${EIGEN_CXX}
|
||||
SITE:STRING=pc-gael
|
||||
CVSCOMMAND:FILEPATH=/usr/bin/svn"
|
||||
)
|
||||
|
||||
# set any extra environment variables to use during the execution of the script here:
|
||||
|
||||
if(EIGEN_CXX)
|
||||
set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}")
|
||||
endif(EIGEN_CXX)
|
||||
|
||||
if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
|
||||
if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
|
||||
set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON")
|
||||
elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3)
|
||||
set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON")
|
||||
elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec)
|
||||
set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON")
|
||||
elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec)
|
||||
set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON")
|
||||
else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
|
||||
message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec")
|
||||
endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
|
||||
endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
|
||||
@@ -55,21 +55,30 @@ struct Bad6
|
||||
Matrix<double, 3, 4> m; // bad: same reason
|
||||
};
|
||||
|
||||
struct Good7 : Eigen::WithAlignedOperatorNew
|
||||
struct Good7
|
||||
{
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
Vector2d m;
|
||||
float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
|
||||
};
|
||||
|
||||
struct Good8 : Eigen::WithAlignedOperatorNew
|
||||
struct Good8
|
||||
{
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work
|
||||
Matrix4f m;
|
||||
};
|
||||
|
||||
struct Good9
|
||||
{
|
||||
Matrix<float,2,2,Matrix_DontAlign> m; // good: no alignment requested
|
||||
Matrix<float,2,2,DontAlign> m; // good: no alignment requested
|
||||
float f;
|
||||
};
|
||||
|
||||
template<bool Align> struct Depends
|
||||
{
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
|
||||
Vector2d m;
|
||||
float f;
|
||||
};
|
||||
|
||||
@@ -89,7 +98,7 @@ void check_unalignedassert_bad()
|
||||
float buf[sizeof(T)+16];
|
||||
float *unaligned = buf;
|
||||
while((reinterpret_cast<size_t>(unaligned)&0xf)==0) ++unaligned; // make sure unaligned is really unaligned
|
||||
T *x = new(static_cast<void*>(unaligned)) T;
|
||||
T *x = ::new(static_cast<void*>(unaligned)) T;
|
||||
x->~T();
|
||||
}
|
||||
|
||||
@@ -104,6 +113,8 @@ void unalignedassert()
|
||||
check_unalignedassert_good<Good7>();
|
||||
check_unalignedassert_good<Good8>();
|
||||
check_unalignedassert_good<Good9>();
|
||||
check_unalignedassert_good<Depends<true> >();
|
||||
VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Depends<false> >());
|
||||
}
|
||||
|
||||
void test_unalignedassert()
|
||||
|
||||
103
test/vectorization_logic.cpp
Normal file
103
test/vectorization_logic.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "main.h"
|
||||
#include <typeinfo>
|
||||
|
||||
template<typename Dst, typename Src>
|
||||
bool test_assign(const Dst&, const Src&, int vectorization, int unrolling)
|
||||
{
|
||||
return ei_assign_traits<Dst,Src>::Vectorization==vectorization
|
||||
&& ei_assign_traits<Dst,Src>::Unrolling==unrolling;
|
||||
}
|
||||
|
||||
template<typename Xpr>
|
||||
bool test_sum(const Xpr&, int vectorization, int unrolling)
|
||||
{
|
||||
return ei_sum_traits<Xpr>::Vectorization==vectorization
|
||||
&& ei_sum_traits<Xpr>::Unrolling==unrolling;
|
||||
}
|
||||
|
||||
void test_vectorization_logic()
|
||||
{
|
||||
|
||||
#ifdef EIGEN_VECTORIZE
|
||||
|
||||
VERIFY(test_assign(Vector4f(),Vector4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector4f(),Vector4f()+Vector4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector4f(),Vector4f().cwise() * Vector4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix4f(),Matrix4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
VERIFY(test_assign(Matrix4f(),Matrix4f()+Matrix4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
VERIFY(test_assign(Matrix4f(),Matrix4f().cwise() * Matrix4f(),
|
||||
InnerVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix<float,16,16>(),Matrix<float,16,16>()+Matrix<float,16,16>(),
|
||||
InnerVectorization,InnerUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix<float,16,16,DontAlign>(),Matrix<float,16,16>()+Matrix<float,16,16>(),
|
||||
NoVectorization,InnerUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix<float,6,2>(),Matrix<float,6,2>().cwise() / Matrix<float,6,2>(),
|
||||
LinearVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix<float,17,17>(),Matrix<float,17,17>()+Matrix<float,17,17>(),
|
||||
NoVectorization,InnerUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix<float,4,4>(),Matrix<float,17,17>().block<4,4>(2,3)+Matrix<float,17,17>().block<4,4>(10,4),
|
||||
NoVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_assign(MatrixXf(10,10),MatrixXf(20,20).block(10,10,2,3),
|
||||
SliceVectorization,NoUnrolling));
|
||||
|
||||
|
||||
VERIFY(test_sum(VectorXf(10),
|
||||
LinearVectorization,NoUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<float,5,2>(),
|
||||
NoVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<float,6,2>(),
|
||||
LinearVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<float,16,16>(),
|
||||
LinearVectorization,NoUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<float,16,16>().block<4,4>(1,2),
|
||||
NoVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<float,16,16>().block<8,1>(1,2),
|
||||
LinearVectorization,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_sum(Matrix<double,7,3>(),
|
||||
NoVectorization,CompleteUnrolling));
|
||||
|
||||
#endif // EIGEN_VECTORIZE
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user