* support for matrix-scalar quotient with integer scalar types.

* added cache efficient matrix-matrix product.
   - provides a huge speed-up for large matrices.
   - currently it is enabled when an explicit unrolling is not possible.
This commit is contained in:
Gael Guennebaud
2008-03-21 20:26:14 +00:00
parent 0ef1efdbdb
commit 4342f024d9
7 changed files with 116 additions and 22 deletions

View File

@@ -65,6 +65,7 @@ struct ei_product_unroller<Index, 0, Lhs, Rhs>
*
* \param Lhs the type of the left-hand side
* \param Rhs the type of the right-hand side
* \param EvalMode internal use only
*
* This class represents an expression of the product of two matrices.
* It is the return type of MatrixBase::lazyProduct(), which is used internally by
@@ -72,8 +73,8 @@ struct ei_product_unroller<Index, 0, Lhs, Rhs>
*
* \sa class Sum, class Difference
*/
template<typename Lhs, typename Rhs>
struct ei_traits<Product<Lhs, Rhs> >
template<typename Lhs, typename Rhs, int EvalMode>
struct ei_traits<Product<Lhs, Rhs, EvalMode> >
{
typedef typename Lhs::Scalar Scalar;
enum {
@@ -84,8 +85,19 @@ struct ei_traits<Product<Lhs, Rhs> >
};
};
template<typename Lhs, typename Rhs> class Product : ei_no_assignment_operator,
public MatrixBase<Product<Lhs, Rhs> >
template<typename Lhs, typename Rhs>
struct ei_product_eval_mode
{
enum {
SizeAtCompileTime = MatrixBase<Product<Lhs,Rhs,UnrolledDotProduct> >::SizeAtCompileTime,
EvalMode = ( EIGEN_UNROLLED_LOOPS
&& SizeAtCompileTime != Dynamic
&& SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT) ? UnrolledDotProduct : CacheOptimal,
};
};
template<typename Lhs, typename Rhs, int EvalMode> class Product : ei_no_assignment_operator,
public MatrixBase<Product<Lhs, Rhs, EvalMode> >
{
public:
@@ -97,6 +109,10 @@ template<typename Lhs, typename Rhs> class Product : ei_no_assignment_operator,
assert(lhs.cols() == rhs.rows());
}
/** \internal */
template<typename DestDerived>
void _cacheOptimalEval(DestDerived& res) const;
private:
int _rows() const { return m_lhs.rows(); }
@@ -156,7 +172,7 @@ template<typename OtherDerived>
const Eval<Product<Derived, OtherDerived> >
MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
{
return lazyProduct(other).eval();
return (*this).lazyProduct(other).eval();
}
/** replaces \c *this by \c *this * \a other.
@@ -171,4 +187,39 @@ MatrixBase<Derived>::operator*=(const MatrixBase<OtherDerived> &other)
return *this = *this * other;
}
template<typename Derived>
template<typename Derived1, typename Derived2>
Derived& MatrixBase<Derived>::operator=(const Product<Derived1,Derived2,CacheOptimal>& product)
{
product._cacheOptimalEval(*this);
return (*this).derived();
}
template<typename Lhs, typename Rhs, int EvalMode>
template<typename DestDerived>
void Product<Lhs,Rhs,EvalMode>::_cacheOptimalEval(DestDerived& res) const
{
res.setZero();
const int cols4 = m_lhs.cols()&0xfffffffC;
for (int k=0; k<m_rhs.cols(); ++k)
{
int j=0;
for (; j<cols4; j+=4)
{
const Scalar tmp0 = m_rhs.coeff(j ,k);
const Scalar tmp1 = m_rhs.coeff(j+1,k);
const Scalar tmp2 = m_rhs.coeff(j+2,k);
const Scalar tmp3 = m_rhs.coeff(j+3,k);
for (int i=0; i<m_lhs.rows(); ++i)
res.coeffRef(i,k) += tmp0 * m_lhs.coeff(i,j) + tmp1 * m_lhs.coeff(i,j+1) + tmp2 * m_lhs.coeff(i,j+2) + tmp3 * m_lhs.coeff(i,j+3);
}
for (; j<m_lhs.cols(); ++j)
{
const Scalar tmp = m_rhs.coeff(j,k);
for (int i=0; i<m_lhs.rows(); ++i)
res.coeffRef(i,k) += tmp * m_lhs.coeff(i,j);
}
}
}
#endif // EIGEN_PRODUCT_H