aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/Core/Product.h
diff options
context:
space:
mode:
Diffstat (limited to 'Eigen/src/Core/Product.h')
-rw-r--r--Eigen/src/Core/Product.h169
1 files changed, 97 insertions, 72 deletions
diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h
index 57f7811c8..3bb73fa5f 100644
--- a/Eigen/src/Core/Product.h
+++ b/Eigen/src/Core/Product.h
@@ -45,20 +45,22 @@
*
* \sa ProductReturnType, MatrixBase::operator*(const MatrixBase<OtherDerived>&)
*/
-template<typename Lhs, typename Rhs, int ProductType = ei_product_type<Lhs,Rhs>::value>
+template<typename Lhs, typename Rhs, int ProductType = internal::product_type<Lhs,Rhs>::value>
class GeneralProduct;
-template<int Rows, int Cols, int Depth> struct ei_product_type_selector;
-
enum {
Large = 2,
Small = 3
};
-template<typename Lhs, typename Rhs> struct ei_product_type
+namespace internal {
+
+template<int Rows, int Cols, int Depth> struct product_type_selector;
+
+template<typename Lhs, typename Rhs> struct product_type
{
- typedef typename ei_cleantype<Lhs>::type _Lhs;
- typedef typename ei_cleantype<Rhs>::type _Rhs;
+ typedef typename cleantype<Lhs>::type _Lhs;
+ typedef typename cleantype<Rhs>::type _Rhs;
enum {
Rows = _Lhs::MaxRowsAtCompileTime,
Cols = _Rhs::MaxColsAtCompileTime,
@@ -73,11 +75,11 @@ private:
cols_select = Cols == Dynamic || Cols >=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ? Large : (Cols==1 ? 1 : Small),
depth_select = Depth == Dynamic || Depth>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD ? Large : (Depth==1 ? 1 : Small)
};
- typedef ei_product_type_selector<rows_select, cols_select, depth_select> product_type_selector;
+ typedef product_type_selector<rows_select, cols_select, depth_select> selector;
public:
enum {
- value = product_type_selector::ret
+ value = selector::ret
};
#ifdef EIGEN_DEBUG_PRODUCT
static void debug()
@@ -93,32 +95,35 @@ public:
#endif
};
+
/* The following allows to select the kind of product at compile time
* based on the three dimensions of the product.
* This is a compile time mapping from {1,Small,Large}^3 -> {product types} */
// FIXME I'm not sure the current mapping is the ideal one.
-template<int M, int N> struct ei_product_type_selector<M,N,1> { enum { ret = OuterProduct }; };
-template<int Depth> struct ei_product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; };
-template<> struct ei_product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; };
-template<> struct ei_product_type_selector<Small,1, Small> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Small,Small,Small> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Small, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Small, Large, 1> { enum { ret = LazyCoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Large, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; };
-template<> struct ei_product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Large,1, Small> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Large,1, Large> { enum { ret = GemvProduct }; };
-template<> struct ei_product_type_selector<Small,1, Large> { enum { ret = CoeffBasedProductMode }; };
-template<> struct ei_product_type_selector<Small,Small,Large> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Large,Small,Large> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Small,Large,Large> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Large,Large,Large> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Large,Small,Small> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Small,Large,Small> { enum { ret = GemmProduct }; };
-template<> struct ei_product_type_selector<Large,Large,Small> { enum { ret = GemmProduct }; };
+template<int M, int N> struct product_type_selector<M,N,1> { enum { ret = OuterProduct }; };
+template<int Depth> struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; };
+template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; };
+template<> struct product_type_selector<Small,1, Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small,Small,Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
+template<> struct product_type_selector<Small, Large, 1> { enum { ret = LazyCoeffBasedProductMode }; };
+template<> struct product_type_selector<Large, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
+template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; };
+template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Large,1, Small> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Large,1, Large> { enum { ret = GemvProduct }; };
+template<> struct product_type_selector<Small,1, Large> { enum { ret = CoeffBasedProductMode }; };
+template<> struct product_type_selector<Small,Small,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Small,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Small,Large,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Large,Large> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Small,Small> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Small,Large,Small> { enum { ret = GemmProduct }; };
+template<> struct product_type_selector<Large,Large,Small> { enum { ret = GemmProduct }; };
+
+} // end namespace internal
/** \class ProductReturnType
* \ingroup Core_Module
@@ -127,7 +132,7 @@ template<> struct ei_product_type_selector<Large,Large,Small> { en
*
* \param Lhs the type of the left-hand side
* \param Rhs the type of the right-hand side
- * \param ProductMode the type of the product (determined automatically by ei_product_mode)
+ * \param ProductMode the type of the product (determined automatically by internal::product_mode)
*
* This class defines the typename Type representing the optimized product expression
* between two matrix expressions. In practice, using ProductReturnType<Lhs,Rhs>::Type
@@ -141,8 +146,8 @@ template<typename Lhs, typename Rhs, int ProductType>
struct ProductReturnType
{
// TODO use the nested type to reduce instanciations ????
-// typedef typename ei_nested<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
-// typedef typename ei_nested<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
+// typedef typename internal::nested<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
+// typedef typename internal::nested<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
typedef GeneralProduct<Lhs/*Nested*/, Rhs/*Nested*/, ProductType> Type;
};
@@ -150,16 +155,16 @@ struct ProductReturnType
template<typename Lhs, typename Rhs>
struct ProductReturnType<Lhs,Rhs,CoeffBasedProductMode>
{
- typedef typename ei_nested<Lhs, Rhs::ColsAtCompileTime, typename ei_plain_matrix_type<Lhs>::type >::type LhsNested;
- typedef typename ei_nested<Rhs, Lhs::RowsAtCompileTime, typename ei_plain_matrix_type<Rhs>::type >::type RhsNested;
+ typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
+ typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
typedef CoeffBasedProduct<LhsNested, RhsNested, EvalBeforeAssigningBit | EvalBeforeNestingBit> Type;
};
template<typename Lhs, typename Rhs>
struct ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
{
- typedef typename ei_nested<Lhs, Rhs::ColsAtCompileTime, typename ei_plain_matrix_type<Lhs>::type >::type LhsNested;
- typedef typename ei_nested<Rhs, Lhs::RowsAtCompileTime, typename ei_plain_matrix_type<Rhs>::type >::type RhsNested;
+ typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
+ typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
typedef CoeffBasedProduct<LhsNested, RhsNested, NestByRefBit> Type;
};
@@ -179,21 +184,25 @@ struct LazyProductReturnType : public ProductReturnType<Lhs,Rhs,LazyCoeffBasedPr
// product ends up to a row-vector times col-vector product... To tackle this use
// case, we could have a specialization for Block<MatrixType,1,1> with: operator=(Scalar x);
+namespace internal {
+
template<typename Lhs, typename Rhs>
-struct ei_traits<GeneralProduct<Lhs,Rhs,InnerProduct> >
- : ei_traits<Matrix<typename ei_scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> >
+struct traits<GeneralProduct<Lhs,Rhs,InnerProduct> >
+ : traits<Matrix<typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> >
{};
+}
+
template<typename Lhs, typename Rhs>
class GeneralProduct<Lhs, Rhs, InnerProduct>
- : ei_no_assignment_operator,
- public Matrix<typename ei_scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1>
+ : internal::no_assignment_operator,
+ public Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1>
{
- typedef Matrix<typename ei_scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> Base;
+ typedef Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> Base;
public:
GeneralProduct(const Lhs& lhs, const Rhs& rhs)
{
- EIGEN_STATIC_ASSERT((ei_is_same_type<typename Lhs::RealScalar, typename Rhs::RealScalar>::ret),
+ EIGEN_STATIC_ASSERT((internal::is_same_type<typename Lhs::RealScalar, typename Rhs::RealScalar>::ret),
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
@@ -210,13 +219,17 @@ class GeneralProduct<Lhs, Rhs, InnerProduct>
/***********************************************************************
* Implementation of Outer Vector Vector Product
***********************************************************************/
-template<int StorageOrder> struct ei_outer_product_selector;
+
+namespace internal {
+template<int StorageOrder> struct outer_product_selector;
template<typename Lhs, typename Rhs>
-struct ei_traits<GeneralProduct<Lhs,Rhs,OuterProduct> >
- : ei_traits<ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> >
+struct traits<GeneralProduct<Lhs,Rhs,OuterProduct> >
+ : traits<ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> >
{};
+}
+
template<typename Lhs, typename Rhs>
class GeneralProduct<Lhs, Rhs, OuterProduct>
: public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs>
@@ -226,17 +239,19 @@ class GeneralProduct<Lhs, Rhs, OuterProduct>
GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
{
- EIGEN_STATIC_ASSERT((ei_is_same_type<typename Lhs::RealScalar, typename Rhs::RealScalar>::ret),
+ EIGEN_STATIC_ASSERT((internal::is_same_type<typename Lhs::RealScalar, typename Rhs::RealScalar>::ret),
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
}
template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
{
- ei_outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha);
+ internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha);
}
};
-template<> struct ei_outer_product_selector<ColMajor> {
+namespace internal {
+
+template<> struct outer_product_selector<ColMajor> {
template<typename ProductType, typename Dest>
static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
typedef typename Dest::Index Index;
@@ -248,7 +263,7 @@ template<> struct ei_outer_product_selector<ColMajor> {
}
};
-template<> struct ei_outer_product_selector<RowMajor> {
+template<> struct outer_product_selector<RowMajor> {
template<typename ProductType, typename Dest>
static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
typedef typename Dest::Index Index;
@@ -260,6 +275,8 @@ template<> struct ei_outer_product_selector<RowMajor> {
}
};
+} // end namespace internal
+
/***********************************************************************
* Implementation of General Matrix Vector Product
***********************************************************************/
@@ -271,13 +288,17 @@ template<> struct ei_outer_product_selector<RowMajor> {
* Therefore we need a lower level meta selector.
* Furthermore, if the matrix is the rhs, then the product has to be transposed.
*/
+namespace internal {
+
template<typename Lhs, typename Rhs>
-struct ei_traits<GeneralProduct<Lhs,Rhs,GemvProduct> >
- : ei_traits<ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs> >
+struct traits<GeneralProduct<Lhs,Rhs,GemvProduct> >
+ : traits<ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs> >
{};
template<int Side, int StorageOrder, bool BlasCompatible>
-struct ei_gemv_selector;
+struct gemv_selector;
+
+} // end namespace internal
template<typename Lhs, typename Rhs>
class GeneralProduct<Lhs, Rhs, GemvProduct>
@@ -291,37 +312,39 @@ class GeneralProduct<Lhs, Rhs, GemvProduct>
GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
{
-// EIGEN_STATIC_ASSERT((ei_is_same_type<typename Lhs::Scalar, typename Rhs::Scalar>::ret),
+// EIGEN_STATIC_ASSERT((internal::is_same_type<typename Lhs::Scalar, typename Rhs::Scalar>::ret),
// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
}
enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight };
- typedef typename ei_meta_if<int(Side)==OnTheRight,_LhsNested,_RhsNested>::ret MatrixType;
+ typedef typename internal::meta_if<int(Side)==OnTheRight,_LhsNested,_RhsNested>::ret MatrixType;
template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
{
- ei_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
- ei_gemv_selector<Side,(int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
- bool(ei_blas_traits<MatrixType>::HasUsableDirectAccess)>::run(*this, dst, alpha);
+ eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
+ internal::gemv_selector<Side,(int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
+ bool(internal::blas_traits<MatrixType>::HasUsableDirectAccess)>::run(*this, dst, alpha);
}
};
+namespace internal {
+
// The vector is on the left => transposition
template<int StorageOrder, bool BlasCompatible>
-struct ei_gemv_selector<OnTheLeft,StorageOrder,BlasCompatible>
+struct gemv_selector<OnTheLeft,StorageOrder,BlasCompatible>
{
template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
{
Transpose<Dest> destT(dest);
enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor };
- ei_gemv_selector<OnTheRight,OtherStorageOrder,BlasCompatible>
+ gemv_selector<OnTheRight,OtherStorageOrder,BlasCompatible>
::run(GeneralProduct<Transpose<typename ProductType::_RhsNested>,Transpose<typename ProductType::_LhsNested>, GemvProduct>
(prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha);
}
};
-template<> struct ei_gemv_selector<OnTheRight,ColMajor,true>
+template<> struct gemv_selector<OnTheRight,ColMajor,true>
{
template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
@@ -344,15 +367,15 @@ template<> struct ei_gemv_selector<OnTheRight,ColMajor,true>
* RhsBlasTraits::extractScalarFactor(prod.rhs());
enum {
- // FIXME find a way to allow an inner stride on the result if ei_packet_traits<Scalar>::size==1
+ // FIXME find a way to allow an inner stride on the result if packet_traits<Scalar>::size==1
EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1,
ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex)
};
- bool alphaIsCompatible = (!ComplexByReal) || (ei_imag(actualAlpha)==RealScalar(0));
+ bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0));
bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible;
- RhsScalar compatibleAlpha = ei_get_factor<ResScalar,RhsScalar>::run(actualAlpha);
+ RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::run(actualAlpha);
ResScalar* actualDest;
if (evalToDest)
@@ -371,7 +394,7 @@ template<> struct ei_gemv_selector<OnTheRight,ColMajor,true>
MappedDest(actualDest, dest.size()) = dest;
}
- ei_general_matrix_vector_product
+ general_matrix_vector_product
<Index,LhsScalar,ColMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
actualLhs.rows(), actualLhs.cols(),
&actualLhs.const_cast_derived().coeffRef(0,0), actualLhs.outerStride(),
@@ -390,7 +413,7 @@ template<> struct ei_gemv_selector<OnTheRight,ColMajor,true>
}
};
-template<> struct ei_gemv_selector<OnTheRight,RowMajor,true>
+template<> struct gemv_selector<OnTheRight,RowMajor,true>
{
template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
@@ -412,9 +435,9 @@ template<> struct ei_gemv_selector<OnTheRight,RowMajor,true>
* RhsBlasTraits::extractScalarFactor(prod.rhs());
enum {
- // FIXME I think here we really have to check for ei_packet_traits<Scalar>::size==1
+ // FIXME I think here we really have to check for packet_traits<Scalar>::size==1
// because in this case it is fine to have an inner stride
- DirectlyUseRhs = ((ei_packet_traits<RhsScalar>::size==1) || (_ActualRhsType::Flags&ActualPacketAccessBit))
+ DirectlyUseRhs = ((packet_traits<RhsScalar>::size==1) || (_ActualRhsType::Flags&ActualPacketAccessBit))
&& (!(_ActualRhsType::Flags & RowMajorBit))
};
@@ -427,7 +450,7 @@ template<> struct ei_gemv_selector<OnTheRight,RowMajor,true>
Map<typename _ActualRhsType::PlainObject>(rhs_data, actualRhs.size()) = actualRhs;
}
- ei_general_matrix_vector_product
+ general_matrix_vector_product
<Index,LhsScalar,RowMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
actualLhs.rows(), actualLhs.cols(),
&actualLhs.const_cast_derived().coeffRef(0,0), actualLhs.outerStride(),
@@ -439,7 +462,7 @@ template<> struct ei_gemv_selector<OnTheRight,RowMajor,true>
}
};
-template<> struct ei_gemv_selector<OnTheRight,ColMajor,false>
+template<> struct gemv_selector<OnTheRight,ColMajor,false>
{
template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
@@ -452,7 +475,7 @@ template<> struct ei_gemv_selector<OnTheRight,ColMajor,false>
}
};
-template<> struct ei_gemv_selector<OnTheRight,RowMajor,false>
+template<> struct gemv_selector<OnTheRight,RowMajor,false>
{
template<typename ProductType, typename Dest>
static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
@@ -465,6 +488,8 @@ template<> struct ei_gemv_selector<OnTheRight,RowMajor,false>
}
};
+} // end namespace internal
+
/***************************************************************************
* Implementation of matrix base methods
***************************************************************************/
@@ -500,7 +525,7 @@ MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
#ifdef EIGEN_DEBUG_PRODUCT
- ei_product_type<Derived,OtherDerived>::debug();
+ internal::product_type<Derived,OtherDerived>::debug();
#endif
return typename ProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
}