Compare commits

...

13 Commits

Author SHA1 Message Date
Benoit Jacob
1eec8488a2 oops, placement new should take a void* 2009-01-05 19:56:32 +00:00
Benoit Jacob
9dcde48980 we also had to overload the placement new... issue uncovered by Tim when
doing QVector<Vector3d>...
2009-01-05 19:49:07 +00:00
Benoit Jacob
215ce5bdc1 forgot to install the LeastSquares header 2009-01-05 19:12:35 +00:00
Benoit Jacob
10f9478f35 release beta5, fix a doc typo 2009-01-05 19:00:10 +00:00
Benoit Jacob
9c8a653c0b gaaaaaaaaaaaaaaaaaah
can't believe that 3 people wasted so much time because of a missing &
!!!!!
and this time MSVC didn't catch it so it was really copying the vector
on the stack at an unaligned location!
2009-01-05 18:33:39 +00:00
Benoit Jacob
8551505436 problem solved, we really want public inheritance and it is only
automatic when the _child_ class is a struct.
2009-01-05 18:21:44 +00:00
Benoit Jacob
1b88042880 the empty base class optimization is not standard. Most compilers implement a basic form of it; however MSVC won't implement it if there is more than one empty base class.
For that reason, we shouldn't give Matrix two empty base classes, since sizeof(Matrix) must be optimal.
So we overload operator new and delete manually rather than inheriting an empty struct for doing that.
2009-01-05 16:46:19 +00:00
Benoit Jacob
7db3f2f72a *fix compilation with MSVC 2005 in the Transform::construct_from_matrix
*fix warnings with MSVC 2005: converting M_PI to float gives loss-of-precision warnings
2009-01-05 14:47:38 +00:00
Armin Berres
dae7f065d4 didn't meant to commit the fortran check. but anyway, unfortunately it doesn't work the way iot should. the test fails and cmake will terminate if it doesn't find a fortran compiler 2009-01-05 14:40:27 +00:00
Armin Berres
ab660a4d29 inherit from ei_with_aligned_operator_new even with disabled vectorization 2009-01-05 14:35:07 +00:00
Benoit Jacob
986f301233 *add PartialRedux::cross() with unit test
*add transform-from-matrices test
*undo an unwanted change in Matrix
2009-01-05 14:26:34 +00:00
Benoit Jacob
d316d4f393 fix compilation on apple: _mm_malloc was undefined. the fix is to just use malloc since on apple it already returns aligned ptrs 2009-01-05 13:15:27 +00:00
Benoit Jacob
e1ee876daa fix segfault due to non-aligned packets 2009-01-04 23:23:32 +00:00
16 changed files with 109 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
project(Eigen)
set(EIGEN_VERSION_NUMBER "2.0-beta4")
set(EIGEN_VERSION_NUMBER "2.0-beta5")
#if the svnversion program is absent, this will leave the SVN_REVISION string empty,
#but won't stop CMake.

View File

@@ -1,4 +1,4 @@
set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression)
set(Eigen_HEADERS Core LU Cholesky QR Geometry Sparse Array SVD Regression LeastSquares)
if(EIGEN_BUILD_LIB)
set(Eigen_SRCS

View File

@@ -172,6 +172,8 @@ template<typename ExpressionType, int Direction> class PartialRedux
> Type;
};
typedef typename ExpressionType::PlainMatrixType CrossReturnType;
inline PartialRedux(const ExpressionType& matrix) : m_matrix(matrix) {}
/** \internal */
@@ -245,6 +247,32 @@ template<typename ExpressionType, int Direction> class PartialRedux
const typename ReturnType<ei_member_any>::Type any() const
{ return _expression(); }
/** \returns a 3x3 matrix expression of the cross product
* of each column or row of the referenced expression with the \a other vector.
*
* \geometry_module
*
* \sa MatrixBase::cross() */
template<typename OtherDerived>
const CrossReturnType cross(const MatrixBase<OtherDerived>& other) const
{
EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(CrossReturnType,3,3)
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,3)
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)
if(Direction==Vertical)
return (CrossReturnType()
<< _expression().col(0).cross(other),
_expression().col(1).cross(other),
_expression().col(2).cross(other)).finished();
else
return (CrossReturnType()
<< _expression().row(0).cross(other),
_expression().row(1).cross(other),
_expression().row(2).cross(other)).finished();
}
protected:
ExpressionTypeNested m_matrix;
};

View File

@@ -306,7 +306,7 @@ inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<
*
* \only_for_vectors
*
* \sa dot(), normSquared()
* \sa dot(), squaredNorm()
*/
template<typename Derived>
inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const

View File

@@ -117,17 +117,9 @@ struct ei_traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
};
};
template<typename T, int Rows, int Cols, int Options,
bool NeedsToAlign = ((Options&Matrix_AutoAlign) == Matrix_AutoAlign) && Rows!=Dynamic && Cols!=Dynamic && ((sizeof(T)*Rows*Cols)%16==0)>
struct ei_matrix_with_aligned_operator_new : WithAlignedOperatorNew {};
template<typename T, int Rows, int Cols, int Options>
struct ei_matrix_with_aligned_operator_new<T, Rows, Cols, Options, false> {};
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Matrix
: public MatrixBase<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
, public ei_matrix_with_aligned_operator_new<_Scalar, _Rows, _Cols, _Options>
{
public:
EIGEN_GENERIC_PUBLIC_INTERFACE(Matrix)
@@ -140,6 +132,33 @@ class Matrix
protected:
ei_matrix_storage<Scalar, MaxSizeAtCompileTime, RowsAtCompileTime, ColsAtCompileTime, Options> m_storage;
public:
enum { NeedsToAlign = (Options&Matrix_AutoAlign) == Matrix_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_STRONG_INLINE int rows() const { return m_storage.rows(); }

View File

@@ -56,6 +56,8 @@ inline T* ei_aligned_malloc(size_t size)
#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
@@ -71,7 +73,7 @@ inline T* ei_aligned_malloc(size_t size)
// 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];
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
@@ -95,6 +97,8 @@ inline void ei_aligned_free(T* ptr, size_t size)
while(size) ptr[--size].~T();
#if defined(__linux)
free(ptr);
#elif defined(__APPLE__)
free(ptr);
#elif defined(_MSC_VER)
_aligned_free(ptr);
#else
@@ -169,7 +173,7 @@ 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 : WithAlignedOperatorNew {
* struct Foo : public WithAlignedOperatorNew {
* char dummy;
* Vector4f some_vector;
* };
@@ -197,7 +201,7 @@ struct WithAlignedOperatorNew
template<typename T, int SizeAtCompileTime,
bool NeedsToAlign = (SizeAtCompileTime!=Dynamic) && ((sizeof(T)*SizeAtCompileTime)%16==0)>
struct ei_with_aligned_operator_new : WithAlignedOperatorNew {};
struct ei_with_aligned_operator_new : public WithAlignedOperatorNew {};
template<typename T, int SizeAtCompileTime>
struct ei_with_aligned_operator_new<T,SizeAtCompileTime,false> {};

View File

@@ -39,9 +39,7 @@
*/
template <typename _Scalar, int _AmbientDim>
class AlignedBox
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
#endif
{
public:
@@ -59,7 +57,7 @@ public:
{ setNull(); }
/** Constructs a box with extremities \a _min and \a _max. */
inline AlignedBox(const VectorType& _min, const VectorType _max) : m_min(_min), m_max(_max) {}
inline AlignedBox(const VectorType& _min, const VectorType& _max) : m_min(_min), m_max(_max) {}
/** Constructs a box containing a single point \a p. */
inline explicit AlignedBox(const VectorType& p) : m_min(p), m_max(p) {}

View File

@@ -45,9 +45,7 @@
*/
template <typename _Scalar, int _AmbientDim>
class Hyperplane
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
#endif
{
public:

View File

@@ -41,9 +41,7 @@
*/
template <typename _Scalar, int _AmbientDim>
class ParametrizedLine
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_AmbientDim>
#endif
{
public:

View File

@@ -59,9 +59,7 @@ template<typename _Scalar> struct ei_traits<Quaternion<_Scalar> >
template<typename _Scalar>
class Quaternion : public RotationBase<Quaternion<_Scalar>,3>
#ifdef EIGEN_VECTORIZE
, public ei_with_aligned_operator_new<_Scalar,4>
#endif
{
typedef RotationBase<Quaternion<_Scalar>,3> Base;
typedef Matrix<_Scalar, 4, 1> Coefficients;

View File

@@ -41,9 +41,7 @@
*/
template<typename _Scalar, int _Dim>
class Scaling
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_Dim>
#endif
{
public:
/** dimension of the space */

View File

@@ -61,9 +61,7 @@ struct ei_transform_product_impl;
*/
template<typename _Scalar, int _Dim>
class Transform
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1)>
#endif
{
public:
@@ -108,7 +106,7 @@ public:
inline Transform& operator=(const Transform& other)
{ m_matrix = other.m_matrix; return *this; }
template<typename OtherDerived, bool select = OtherDerived::RowsAtCompileTime == Dim>
template<typename OtherDerived, bool BigMatrix> // MSVC 2005 will commit suicide if BigMatrix has a default value
struct construct_from_matrix
{
static inline void run(Transform *transform, const MatrixBase<OtherDerived>& other)
@@ -132,7 +130,7 @@ public:
template<typename OtherDerived>
inline explicit Transform(const MatrixBase<OtherDerived>& other)
{
construct_from_matrix<OtherDerived>::run(this, other);
construct_from_matrix<OtherDerived, int(OtherDerived::RowsAtCompileTime) == Dim>::run(this, other);
}
/** Set \c *this from a (Dim+1)^2 matrix. */

View File

@@ -41,9 +41,7 @@
*/
template<typename _Scalar, int _Dim>
class Translation
#ifdef EIGEN_VECTORIZE
: public ei_with_aligned_operator_new<_Scalar,_Dim>
#endif
{
public:
/** dimension of the space */

View File

@@ -16,7 +16,7 @@ namespace Eigen {
If you saw the assertion failure that links to this page, then you probably have done something like that in your code:
\code
struct Foo
class Foo
{
...
Eigen::Vector2d v;
@@ -28,7 +28,7 @@ struct Foo
Foo *foo = new Foo;
\endcode
In other words: you have probably in your code a structure that has as a member a vectorizable fixed-size Eigen object, and you then dynamically allocated an object of that structure.
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.
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
@@ -43,10 +43,10 @@ By "vectorizable fixed-size Eigen object" we mean an Eigen matrix or vector of f
\section how How to fix this bug?
Very easy, you just need to let your struct Foo inherit Eigen::WithAlignedOperatorNew, like this:
Very easy, you just need to let your class Foo publicly inherit Eigen::WithAlignedOperatorNew, like this:
\code
struct Foo : Eigen::WithAlignedOperatorNew
class Foo : public Eigen::WithAlignedOperatorNew
{
...
Eigen::Vector2d v;
@@ -65,7 +65,7 @@ With this, you should be out of trouble.
OK let's say that your code looks like this:
\code
struct Foo
class Foo
{
...
Eigen::Vector2d v;
@@ -85,18 +85,18 @@ For this reason, Eigen takes care by itself to require 128-bit alignment for Eig
Thus, normally, you don't have to worry about anything, Eigen handles alignment for you...
... except in one case. When you have a struct 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.
... 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 struct, foo. If the foo pointer wasn't aligned, then foo->v won't be aligned either!
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 struct Foo have an aligned "operator new", as we showed in the previous section.
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 struct?
\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 struct. So when you have code like
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
struct Foo : Eigen::WithAlignedOperatorNew
class Foo : public Eigen::WithAlignedOperatorNew
{
double x;
Eigen::Vector2d v;
@@ -106,7 +106,7 @@ struct Foo : Eigen::WithAlignedOperatorNew
it will work just fine. You do \b not need to rewrite it as
\code
struct Foo : Eigen::WithAlignedOperatorNew
class Foo : public Eigen::WithAlignedOperatorNew
{
Eigen::Vector2d v;
double x;

View File

@@ -59,7 +59,7 @@ template<typename Scalar> void geometry(void)
Vector2 u0 = Vector2::Random();
Matrix3 matrot1;
Scalar a = ei_random<Scalar>(-M_PI, M_PI);
Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
// cross product
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
@@ -77,7 +77,7 @@ template<typename Scalar> void geometry(void)
VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
VERIFY_IS_APPROX(-v0, AngleAxisx(M_PI, v0.unitOrthogonal()) * v0);
VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
@@ -88,8 +88,8 @@ template<typename Scalar> void geometry(void)
// angular distance
Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
if (refangle>M_PI)
refangle = 2.*M_PI - refangle;
if (refangle>Scalar(M_PI))
refangle = 2.*Scalar(M_PI) - refangle;
VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
// rotation matrix conversion
@@ -138,7 +138,7 @@ template<typename Scalar> void geometry(void)
// TODO complete the tests !
a = 0;
while (ei_abs(a)<0.1)
a = ei_random<Scalar>(-0.4*M_PI, 0.4*M_PI);
a = ei_random<Scalar>(-0.4*Scalar(M_PI), 0.4*Scalar(M_PI));
q1 = AngleAxisx(a, v0.normalized());
Transform3 t0, t1, t2;
t0.setIdentity();
@@ -181,7 +181,14 @@ template<typename Scalar> void geometry(void)
// More transform constructors, operator=, operator*=
Scalar a3 = ei_random<Scalar>(-M_PI, M_PI);
Matrix3 mat3 = Matrix3::Random();
Matrix4 mat4;
mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
Transform3 tmat3(mat3), tmat4(mat4);
tmat4.matrix()(3,3) = Scalar(1);
VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
Vector3 v3 = Vector3::Random().normalized();
AngleAxisx aa3(a3, v3);
Transform3 t3(aa3);
@@ -388,6 +395,18 @@ template<typename Scalar> void geometry(void)
VERIFY_EULER(2,0,2, Z,X,Z);
VERIFY_EULER(2,1,0, Z,Y,X);
VERIFY_EULER(2,1,2, Z,Y,Z);
// colwise/rowwise cross product
mat3.setRandom();
Vector3 vec3 = Vector3::Random();
Matrix3 mcross;
int i = ei_random<int>(0,2);
mcross = mat3.colwise().cross(vec3);
VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
mcross = mat3.rowwise().cross(vec3);
VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
}
void test_geometry()

View File

@@ -61,10 +61,10 @@ template<typename Scalar> void packetmath()
const int PacketSize = ei_packet_traits<Scalar>::size;
const int size = PacketSize*4;
Scalar data1[ei_packet_traits<Scalar>::size*4];
Scalar data2[ei_packet_traits<Scalar>::size*4];
Packet packets[PacketSize*2];
Scalar ref[ei_packet_traits<Scalar>::size*4];
EIGEN_ALIGN_128 Scalar data1[ei_packet_traits<Scalar>::size*4];
EIGEN_ALIGN_128 Scalar data2[ei_packet_traits<Scalar>::size*4];
EIGEN_ALIGN_128 Packet packets[PacketSize*2];
EIGEN_ALIGN_128 Scalar ref[ei_packet_traits<Scalar>::size*4];
for (int i=0; i<size; ++i)
{
data1[i] = ei_random<Scalar>();