* add unit-tests to check allowed and forbiddent mixing of different scalar types

* fix issues in Product revealed by this test
* in Dot.h forbid mixing of different types (at least for now, might allow real.dot(complex) in the future).
This commit is contained in:
Benoit Jacob 2008-12-22 19:17:44 +00:00
parent f5a05e7ed1
commit 4336cf3833
5 changed files with 110 additions and 22 deletions

View File

@ -437,6 +437,8 @@ template<typename OtherDerived>
EIGEN_STRONG_INLINE Derived& MatrixBase<Derived> EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>
::operator=(const MatrixBase<OtherDerived>& other) ::operator=(const MatrixBase<OtherDerived>& other)
{ {
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)
return ei_assign_selector<Derived,OtherDerived>::run(derived(), other.derived()); return ei_assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
} }

View File

@ -266,6 +266,9 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested) EIGEN_STATIC_ASSERT_VECTOR_ONLY(_Nested)
EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested) EIGEN_STATIC_ASSERT_VECTOR_ONLY(_OtherNested)
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested) EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(_Nested,_OtherNested)
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()); ei_assert(size() == other.size());
return ei_dot_impl<_Nested, _OtherNested>::run(derived(), other.derived()); return ei_dot_impl<_Nested, _OtherNested>::run(derived(), other.derived());

View File

@ -30,7 +30,7 @@
*** Forward declarations *** *** Forward declarations ***
***************************/ ***************************/
template<int VectorizationMode, int Index, typename Lhs, typename Rhs> template<int VectorizationMode, int Index, typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl; struct ei_product_coeff_impl;
template<int StorageOrder, int Index, typename Lhs, typename Rhs, typename PacketScalar, int LoadMode> template<int StorageOrder, int Index, typename Lhs, typename Rhs, typename PacketScalar, int LoadMode>
@ -94,6 +94,7 @@ template<typename Lhs, typename Rhs> struct ei_product_mode
|| Rhs::MaxColsAtCompileTime >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ) || Rhs::MaxColsAtCompileTime >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD )
&& (!(Rhs::IsVectorAtCompileTime && (Lhs::Flags&RowMajorBit) && (!(Lhs::Flags&DirectAccessBit)))) && (!(Rhs::IsVectorAtCompileTime && (Lhs::Flags&RowMajorBit) && (!(Lhs::Flags&DirectAccessBit))))
&& (!(Lhs::IsVectorAtCompileTime && (!(Rhs::Flags&RowMajorBit)) && (!(Rhs::Flags&DirectAccessBit)))) && (!(Lhs::IsVectorAtCompileTime && (!(Rhs::Flags&RowMajorBit)) && (!(Rhs::Flags&DirectAccessBit))))
&& (ei_is_same_type<typename Lhs::Scalar, typename Rhs::Scalar>::ret)
? CacheFriendlyProduct ? CacheFriendlyProduct
: NormalProduct }; : NormalProduct };
}; };
@ -120,7 +121,7 @@ struct ei_traits<Product<LhsNested, RhsNested, ProductMode> >
// clean the nested types: // clean the nested types:
typedef typename ei_cleantype<LhsNested>::type _LhsNested; typedef typename ei_cleantype<LhsNested>::type _LhsNested;
typedef typename ei_cleantype<RhsNested>::type _RhsNested; typedef typename ei_cleantype<RhsNested>::type _RhsNested;
typedef typename _LhsNested::Scalar Scalar; typedef typename ei_scalar_product_traits<typename _LhsNested::Scalar, typename _RhsNested::Scalar>::ReturnType Scalar;
enum { enum {
LhsCoeffReadCost = _LhsNested::CoeffReadCost, LhsCoeffReadCost = _LhsNested::CoeffReadCost,
@ -189,7 +190,7 @@ template<typename LhsNested, typename RhsNested, int ProductMode> class Product
typedef ei_product_coeff_impl<CanVectorizeInner ? InnerVectorization : NoVectorization, typedef ei_product_coeff_impl<CanVectorizeInner ? InnerVectorization : NoVectorization,
Unroll ? InnerSize-1 : Dynamic, Unroll ? InnerSize-1 : Dynamic,
_LhsNested, _RhsNested> ScalarCoeffImpl; _LhsNested, _RhsNested, Scalar> ScalarCoeffImpl;
public: public:
@ -312,29 +313,29 @@ MatrixBase<Derived>::operator*=(const MatrixBase<OtherDerived> &other)
*** Scalar path - no vectorization *** *** Scalar path - no vectorization ***
**************************************/ **************************************/
template<int Index, typename Lhs, typename Rhs> template<int Index, typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<NoVectorization, Index, Lhs, Rhs> struct ei_product_coeff_impl<NoVectorization, Index, Lhs, Rhs, RetScalar>
{ {
EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
{ {
ei_product_coeff_impl<NoVectorization, Index-1, Lhs, Rhs>::run(row, col, lhs, rhs, res); ei_product_coeff_impl<NoVectorization, Index-1, Lhs, Rhs, RetScalar>::run(row, col, lhs, rhs, res);
res += lhs.coeff(row, Index) * rhs.coeff(Index, col); res += lhs.coeff(row, Index) * rhs.coeff(Index, col);
} }
}; };
template<typename Lhs, typename Rhs> template<typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<NoVectorization, 0, Lhs, Rhs> struct ei_product_coeff_impl<NoVectorization, 0, Lhs, Rhs, RetScalar>
{ {
EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
{ {
res = lhs.coeff(row, 0) * rhs.coeff(0, col); res = lhs.coeff(row, 0) * rhs.coeff(0, col);
} }
}; };
template<typename Lhs, typename Rhs> template<typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<NoVectorization, Dynamic, Lhs, Rhs> struct ei_product_coeff_impl<NoVectorization, Dynamic, Lhs, Rhs, RetScalar>
{ {
EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar& res) EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, RetScalar& res)
{ {
ei_assert(lhs.cols()>0 && "you are using a non initialized matrix"); ei_assert(lhs.cols()>0 && "you are using a non initialized matrix");
res = lhs.coeff(row, 0) * rhs.coeff(0, col); res = lhs.coeff(row, 0) * rhs.coeff(0, col);
@ -344,10 +345,10 @@ struct ei_product_coeff_impl<NoVectorization, Dynamic, Lhs, Rhs>
}; };
// prevent buggy user code from causing an infinite recursion // prevent buggy user code from causing an infinite recursion
template<typename Lhs, typename Rhs> template<typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<NoVectorization, -1, Lhs, Rhs> struct ei_product_coeff_impl<NoVectorization, -1, Lhs, Rhs, RetScalar>
{ {
EIGEN_STRONG_INLINE static void run(int, int, const Lhs&, const Rhs&, typename Lhs::Scalar&) {} EIGEN_STRONG_INLINE static void run(int, int, const Lhs&, const Rhs&, RetScalar&) {}
}; };
/******************************************* /*******************************************
@ -374,16 +375,16 @@ struct ei_product_coeff_vectorized_unroller<0, Lhs, Rhs, PacketScalar>
} }
}; };
template<int Index, typename Lhs, typename Rhs> template<int Index, typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<InnerVectorization, Index, Lhs, Rhs> struct ei_product_coeff_impl<InnerVectorization, Index, Lhs, Rhs, RetScalar>
{ {
typedef typename Lhs::PacketScalar PacketScalar; typedef typename Lhs::PacketScalar PacketScalar;
enum { PacketSize = ei_packet_traits<typename Lhs::Scalar>::size }; enum { PacketSize = ei_packet_traits<typename Lhs::Scalar>::size };
EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
{ {
PacketScalar pres; PacketScalar pres;
ei_product_coeff_vectorized_unroller<Index+1-PacketSize, Lhs, Rhs, PacketScalar>::run(row, col, lhs, rhs, pres); ei_product_coeff_vectorized_unroller<Index+1-PacketSize, Lhs, Rhs, PacketScalar>::run(row, col, lhs, rhs, pres);
ei_product_coeff_impl<NoVectorization,Index,Lhs,Rhs>::run(row, col, lhs, rhs, res); ei_product_coeff_impl<NoVectorization,Index,Lhs,Rhs,RetScalar>::run(row, col, lhs, rhs, res);
res = ei_predux(pres); res = ei_predux(pres);
} }
}; };
@ -438,8 +439,8 @@ struct ei_product_coeff_vectorized_dyn_selector<Lhs,Rhs,1,1>
} }
}; };
template<typename Lhs, typename Rhs> template<typename Lhs, typename Rhs, typename RetScalar>
struct ei_product_coeff_impl<InnerVectorization, Dynamic, Lhs, Rhs> struct ei_product_coeff_impl<InnerVectorization, Dynamic, Lhs, Rhs, RetScalar>
{ {
EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res) EIGEN_STRONG_INLINE static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
{ {

View File

@ -157,6 +157,7 @@ ei_add_test(meta)
ei_add_test(sizeof) ei_add_test(sizeof)
ei_add_test(dynalloc) ei_add_test(dynalloc)
ei_add_test(nomalloc) ei_add_test(nomalloc)
ei_add_test(mixingtypes)
ei_add_test(packetmath) ei_add_test(packetmath)
ei_add_test(basicstuff) ei_add_test(basicstuff)
ei_add_test(linearstructure) ei_add_test(linearstructure)

81
test/mixingtypes.cpp Normal file
View File

@ -0,0 +1,81 @@
// 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) 2008 Benoit Jacob <jacob.benoit.1@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/>.
#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
#include "main.h"
template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
{
typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
Mat_f mf(size,size);
Mat_d md(size,size);
Mat_cf mcf(size,size);
Mat_cd mcd(size,size);
Vec_f vf(size,1);
Vec_d vd(size,1);
Vec_cf vcf(size,1);
Vec_cd vcd(size,1);
mf+mf;
VERIFY_RAISES_ASSERT(mf+md);
VERIFY_RAISES_ASSERT(mf+mcf);
VERIFY_RAISES_ASSERT(vf=vd);
VERIFY_RAISES_ASSERT(vf+=vd);
VERIFY_RAISES_ASSERT(mcd=md);
mf*mf;
md*mcd;
mcd*md;
mf*vcf;
mcf*vf;
mcf *= mf;
vcd = md*vcd;
vcf = mcf*vf;
VERIFY_RAISES_ASSERT(mf*md);
VERIFY_RAISES_ASSERT(mcf*mcd);
VERIFY_RAISES_ASSERT(mcf*vcd);
VERIFY_RAISES_ASSERT(vcf = mf*vf);
vf.dot(vf);
VERIFY_RAISES_ASSERT(vd.dot(vf));
VERIFY_RAISES_ASSERT(vcf.dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h
} // especially as that might be rewritten as cwise product .sum() which would make that automatic.
void test_mixingtypes()
{
// check that our operator new is indeed called:
CALL_SUBTEST(mixingtypes<3>());
CALL_SUBTEST(mixingtypes<4>());
CALL_SUBTEST(mixingtypes<Dynamic>(20));
}