added a static assertion mechanism

(see notes in Core/util/StaticAssert.h for details)
This commit is contained in:
Gael Guennebaud 2008-06-04 11:16:11 +00:00
parent 60726f91a9
commit 48262b9734
9 changed files with 188 additions and 61 deletions

View File

@ -40,6 +40,7 @@ namespace Eigen {
#include "src/Core/util/Constants.h"
#include "src/Core/util/ForwardDeclarations.h"
#include "src/Core/util/Meta.h"
#include "src/Core/util/StaticAssert.h"
} // namespace Eigen

View File

@ -115,6 +115,7 @@ template<typename OtherDerived>
inline Derived& MatrixBase<Derived>
::lazyAssign(const MatrixBase<OtherDerived>& other)
{
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
ei_assert(rows() == other.rows() && cols() == other.cols());
ei_assignment_impl<Derived, OtherDerived>::run(derived(),other.derived());
return derived();

View File

@ -217,7 +217,7 @@ template<typename Derived>
inline Block<Derived> MatrixBase<Derived>
::block(int start, int size)
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(), RowsAtCompileTime == 1 ? 0 : start,
ColsAtCompileTime == 1 ? 0 : start,
RowsAtCompileTime == 1 ? 1 : size,
@ -229,7 +229,7 @@ template<typename Derived>
inline const Block<Derived> MatrixBase<Derived>
::block(int start, int size) const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(), RowsAtCompileTime == 1 ? 0 : start,
ColsAtCompileTime == 1 ? 0 : start,
RowsAtCompileTime == 1 ? 1 : size,
@ -254,7 +254,7 @@ inline const Block<Derived> MatrixBase<Derived>
template<typename Derived>
inline Block<Derived> MatrixBase<Derived>::start(int size)
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(), 0, 0,
RowsAtCompileTime == 1 ? 1 : size,
ColsAtCompileTime == 1 ? 1 : size);
@ -264,7 +264,7 @@ inline Block<Derived> MatrixBase<Derived>::start(int size)
template<typename Derived>
inline const Block<Derived> MatrixBase<Derived>::start(int size) const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(), 0, 0,
RowsAtCompileTime == 1 ? 1 : size,
ColsAtCompileTime == 1 ? 1 : size);
@ -288,7 +288,7 @@ inline const Block<Derived> MatrixBase<Derived>::start(int size) const
template<typename Derived>
inline Block<Derived> MatrixBase<Derived>::end(int size)
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(),
RowsAtCompileTime == 1 ? 0 : rows() - size,
ColsAtCompileTime == 1 ? 0 : cols() - size,
@ -300,7 +300,7 @@ inline Block<Derived> MatrixBase<Derived>::end(int size)
template<typename Derived>
inline const Block<Derived> MatrixBase<Derived>::end(int size) const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived>(derived(),
RowsAtCompileTime == 1 ? 0 : rows() - size,
ColsAtCompileTime == 1 ? 0 : cols() - size,
@ -324,7 +324,7 @@ template<int Size>
inline typename MatrixBase<Derived>::template SubVectorReturnType<Size>::Type
MatrixBase<Derived>::start()
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
(ColsAtCompileTime == 1 ? 1 : Size)>(derived(), 0, 0);
}
@ -335,7 +335,7 @@ template<int Size>
inline const typename MatrixBase<Derived>::template SubVectorReturnType<Size>::Type
MatrixBase<Derived>::start() const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived, (RowsAtCompileTime == 1 ? 1 : Size),
(ColsAtCompileTime == 1 ? 1 : Size)>(derived(), 0, 0);
}
@ -356,7 +356,7 @@ template<int Size>
inline typename MatrixBase<Derived>::template SubVectorReturnType<Size>::Type
MatrixBase<Derived>::end()
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived, RowsAtCompileTime == 1 ? 1 : Size,
ColsAtCompileTime == 1 ? 1 : Size>
(derived(),
@ -370,7 +370,7 @@ template<int Size>
inline const typename MatrixBase<Derived>::template SubVectorReturnType<Size>::Type
MatrixBase<Derived>::end() const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
return Block<Derived, RowsAtCompileTime == 1 ? 1 : Size,
ColsAtCompileTime == 1 ? 1 : Size>
(derived(),

View File

@ -115,7 +115,7 @@ template<typename Derived>
inline const typename ei_traits<Derived>::Scalar MatrixBase<Derived>
::coeff(int index) const
{
ei_internal_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
if(RowsAtCompileTime == 1)
{
ei_internal_assert(index >= 0 && index < cols());
@ -139,7 +139,7 @@ template<typename Derived>
inline const typename ei_traits<Derived>::Scalar MatrixBase<Derived>
::operator[](int index) const
{
ei_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
if(RowsAtCompileTime == 1)
{
ei_assert(index >= 0 && index < cols());
@ -170,7 +170,7 @@ template<typename Derived>
inline typename ei_traits<Derived>::Scalar& MatrixBase<Derived>
::coeffRef(int index)
{
ei_internal_assert(IsVectorAtCompileTime);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
if(RowsAtCompileTime == 1)
{
ei_internal_assert(index >= 0 && index < cols());

View File

@ -79,9 +79,10 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
Nested nested(derived());
OtherNested otherNested(other.derived());
ei_assert(_Nested::IsVectorAtCompileTime
&& _OtherNested::IsVectorAtCompileTime
&& nested.size() == otherNested.size());
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested);
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested);
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested);
ei_assert(nested.size() == otherNested.size());
Scalar res;
const bool unroll = SizeAtCompileTime
* (_Nested::CoeffReadCost + _OtherNested::CoeffReadCost + NumTraits<Scalar>::MulCost)

View File

@ -2,15 +2,16 @@
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
// 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
// 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
// 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
@ -18,13 +19,16 @@
// 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
// 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_FUZZY_H
#define EIGEN_FUZZY_H
template<typename Derived, typename OtherDerived=Derived, bool IsVector=Derived::IsVectorAtCompileTime>
struct ei_fuzzy_selector;
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
* determined by \a prec.
*
@ -48,21 +52,7 @@ bool MatrixBase<Derived>::isApprox(
typename NumTraits<Scalar>::Real prec
) const
{
ei_assert(rows() == other.rows() && cols() == other.cols());
if(IsVectorAtCompileTime)
{
return((*this - other).norm2() <= std::min(norm2(), other.norm2()) * prec * prec);
}
else
{
typename Derived::Nested nested(derived());
typename OtherDerived::Nested otherNested(other.derived());
for(int i = 0; i < cols(); i++)
if((nested.col(i) - otherNested.col(i)).norm2()
> std::min(nested.col(i).norm2(), otherNested.col(i).norm2()) * prec * prec)
return false;
return true;
}
return ei_fuzzy_selector<Derived,OtherDerived>::isApprox(derived(), other.derived(), prec);
}
/** \returns \c true if the norm of \c *this is much smaller than \a other,
@ -81,18 +71,7 @@ bool MatrixBase<Derived>::isMuchSmallerThan(
typename NumTraits<Scalar>::Real prec
) const
{
if(IsVectorAtCompileTime)
{
return(norm2() <= ei_abs2(other * prec));
}
else
{
typename Derived::Nested nested(*this);
for(int i = 0; i < cols(); i++)
if(nested.col(i).norm2() > ei_abs2(other * prec))
return false;
return true;
}
return ei_fuzzy_selector<Derived>::isMuchSmallerThan(derived(), other, prec);
}
/** \returns \c true if the norm of \c *this is much smaller than the norm of \a other,
@ -112,20 +91,67 @@ bool MatrixBase<Derived>::isMuchSmallerThan(
typename NumTraits<Scalar>::Real prec
) const
{
ei_assert(rows() == other.rows() && cols() == other.cols());
if(IsVectorAtCompileTime)
return ei_fuzzy_selector<Derived,OtherDerived>::isMuchSmallerThan(derived(), other.derived(), prec);
}
template<typename Derived, typename OtherDerived>
struct ei_fuzzy_selector<Derived,OtherDerived,true>
{
typedef typename Derived::RealScalar RealScalar;
static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
{
return(norm2() <= other.norm2() * prec * prec);
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived);
ei_assert(self.size() == other.size());
return((self - other).norm2() <= std::min(self.norm2(), other.norm2()) * prec * prec);
}
else
static bool isMuchSmallerThan(const Derived& self, const RealScalar& other, RealScalar prec)
{
typename Derived::Nested nested(*this);
return(self.norm2() <= ei_abs2(other * prec));
}
static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
{
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived);
ei_assert(self.size() == other.size());
return(self.norm2() <= other.norm2() * prec * prec);
}
};
template<typename Derived, typename OtherDerived>
struct ei_fuzzy_selector<Derived,OtherDerived,false>
{
typedef typename Derived::RealScalar RealScalar;
static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
{
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
typename Derived::Nested nested(self);
typename OtherDerived::Nested otherNested(other);
for(int i = 0; i < cols(); i++)
for(int i = 0; i < self.cols(); i++)
if((nested.col(i) - otherNested.col(i)).norm2()
> std::min(nested.col(i).norm2(), otherNested.col(i).norm2()) * prec * prec)
return false;
return true;
}
static bool isMuchSmallerThan(const Derived& self, const RealScalar& other, RealScalar prec)
{
typename Derived::Nested nested(self);
for(int i = 0; i < self.cols(); i++)
if(nested.col(i).norm2() > ei_abs2(other * prec))
return false;
return true;
}
static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
{
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived);
ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
typename Derived::Nested nested(self);
typename OtherDerived::Nested otherNested(other);
for(int i = 0; i < self.cols(); i++)
if(nested.col(i).norm2() > otherNested.col(i).norm2() * prec * prec)
return false;
return true;
}
}
};
#endif // EIGEN_FUZZY_H

View File

@ -73,7 +73,6 @@ template<typename T> struct ei_is_same_type<T,T> { enum { ret = 1 }; };
struct ei_meta_true {};
struct ei_meta_false {};
/** \internal
* Convenient struct to get the result type of a unary or binary functor.
*

View File

@ -0,0 +1,99 @@
// 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>
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.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_STATIC_ASSERT_H
#define EIGEN_STATIC_ASSERT_H
/* Some notes on Eigen's static assertion mechanism:
*
* - in EIGEN_STATIC_ASSERT(CONDITION,MSG) the parameter CONDITION must be a compile time boolean
* expression, and MSG an enum listed in struct ei_static_assert<true>
*
* - define EIGEN_NO_STATIC_ASSERT to disable them (and save compilation time)
* in that case, the static assertion is converted to the following runtime assert:
* ei_assert(CONDITION && "MSG")
*
* - currently EIGEN_STATIC_ASSERT can only be used in function scope
*
*/
#ifndef EIGEN_NO_STATIC_ASSERT
#ifdef __GXX_EXPERIMENTAL_CXX0X__
// if native static_assert is enabled, let's use it
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG)
#else // CXX0X
template<bool condition>
struct ei_static_assert {};
template<>
struct ei_static_assert<true>
{
enum {
you_tried_calling_a_vector_method_on_a_matrix,
you_mixed_vectors_of_different_sizes,
you_mixed_matrices_of_different_sizes
};
};
#define EIGEN_STATIC_ASSERT(CONDITION,MSG) \
if (ei_static_assert<CONDITION ? true : false>::MSG) {}
#endif // CXX0X
#else // EIGEN_NO_STATIC_ASSERT
#define EIGEN_STATIC_ASSERT(CONDITION,MSG) ei_assert((CONDITION) && #MSG)
#endif // EIGEN_NO_STATIC_ASSERT
// static assertion failling if the type \a TYPE is not a vector type
#define EIGEN_STATIC_ASSERT_VECTOR_ONLY(TYPE) EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime,you_tried_calling_a_vector_method_on_a_matrix)
// static assertion failling if the two vector expression types are not compatible (same fixed-size or dynamic size)
#define EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(TYPE0,TYPE1) \
EIGEN_STATIC_ASSERT( \
(int(TYPE0::SizeAtCompileTime)==Eigen::Dynamic \
|| int(TYPE1::SizeAtCompileTime)==Eigen::Dynamic \
|| int(TYPE0::SizeAtCompileTime)==int(TYPE1::SizeAtCompileTime)),\
you_mixed_vectors_of_different_sizes)
// static assertion failling if the two matrix expression types are not compatible (same fixed-size or dynamic size)
#define EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
EIGEN_STATIC_ASSERT( \
((int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
|| int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \
|| int(TYPE0::RowsAtCompileTime)==int(TYPE1::RowsAtCompileTime)) \
&& (int(TYPE0::ColsAtCompileTime)==Eigen::Dynamic \
|| int(TYPE1::ColsAtCompileTime)==Eigen::Dynamic \
|| int(TYPE0::ColsAtCompileTime)==int(TYPE1::ColsAtCompileTime))),\
you_mixed_matrices_of_different_sizes)
#endif // EIGEN_STATIC_ASSERT_H

View File

@ -50,11 +50,11 @@ template<typename _MatrixType> class Tridiagonalization
typedef Matrix<Scalar, SizeMinusOne, 1> CoeffVectorType;
typedef typename NestByValue<DiagonalCoeffs<MatrixType> >::RealReturnType DiagonalType;
typedef typename NestByValue<DiagonalCoeffs<MatrixType> >::RealReturnType DiagonalReturnType;
typedef typename NestByValue<DiagonalCoeffs<
NestByValue<Block<
MatrixType,SizeMinusOne,SizeMinusOne> > > >::RealReturnType SubDiagonalType;
MatrixType,SizeMinusOne,SizeMinusOne> > > >::RealReturnType SubDiagonalReturnType;
Tridiagonalization()
{}
@ -107,8 +107,8 @@ template<typename _MatrixType> class Tridiagonalization
const MatrixType& packedMatrix(void) const { return m_matrix; }
MatrixType matrixQ(void) const;
const DiagonalType diagonal(void) const;
const SubDiagonalType subDiagonal(void) const;
const DiagonalReturnType diagonal(void) const;
const SubDiagonalReturnType subDiagonal(void) const;
private:
@ -188,7 +188,7 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType&
}
if (NumTraits<Scalar>::IsComplex)
{
// householder transformation on the remaining single scalar
// Householder transformation on the remaining single scalar
int i = n-2;
Scalar v0 = matA.col(i).coeff(i+1);
RealScalar beta = ei_abs(v0);
@ -226,7 +226,7 @@ Tridiagonalization<MatrixType>::matrixQ(void) const
/** \returns an expression of the diagonal vector */
template<typename MatrixType>
const typename Tridiagonalization<MatrixType>::DiagonalType
const typename Tridiagonalization<MatrixType>::DiagonalReturnType
Tridiagonalization<MatrixType>::diagonal(void) const
{
return m_matrix.diagonal().nestByValue().real();
@ -234,7 +234,7 @@ Tridiagonalization<MatrixType>::diagonal(void) const
/** \returns an expression of the sub-diagonal vector */
template<typename MatrixType>
const typename Tridiagonalization<MatrixType>::SubDiagonalType
const typename Tridiagonalization<MatrixType>::SubDiagonalReturnType
Tridiagonalization<MatrixType>::subDiagonal(void) const
{
int n = m_matrix.rows();