From f0be175bdc5811e91139184cbfe864efd8fb65d0 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 8 Oct 2007 07:17:54 +0000 Subject: [PATCH] add dot product, extend meta unrolling everywhere --- src/Core.h | 1 + src/Core/CopyHelper.h | 47 +++++++++++++----------- src/Core/Dot.h | 83 +++++++++++++++++++++++++++++++++++++++++++ src/Core/MatrixOps.h | 59 +++++++++++++++++++++++++----- src/Core/Object.h | 17 +++++---- src/Core/Trace.h | 31 +++++++++------- 6 files changed, 190 insertions(+), 48 deletions(-) create mode 100644 src/Core/Dot.h diff --git a/src/Core.h b/src/Core.h index 6b6bc7b12..874a8f5e1 100644 --- a/src/Core.h +++ b/src/Core.h @@ -12,3 +12,4 @@ #include "Core/Transpose.h" #include "Core/Conjugate.h" #include "Core/Trace.h" +#include "Core/Dot.h" diff --git a/src/Core/CopyHelper.h b/src/Core/CopyHelper.h index 04ce37ec6..ccd754c12 100644 --- a/src/Core/CopyHelper.h +++ b/src/Core/CopyHelper.h @@ -27,37 +27,44 @@ #ifndef EI_COPYHELPER_H #define EI_COPYHELPER_H -template class EiCopyHelperUnroller +template struct EiCopyHelperUnroller { - static const int col = (UnrollCount-1) / Rows; - static const int row = (UnrollCount-1) % Rows; + static const int col = (UnrollCount-1) / Rows; + static const int row = (UnrollCount-1) % Rows; - public: - template - static void run(Derived1 &dst, const Derived2 &src) - { - EiCopyHelperUnroller::run(dst, src); - dst.write(row, col) = src.read(row, col); - } + template + static void run(Derived1 &dst, const Derived2 &src) + { + EiCopyHelperUnroller::run(dst, src); + dst.write(row, col) = src.read(row, col); + } }; -template class EiCopyHelperUnroller<0, Rows> +template struct EiCopyHelperUnroller<0, Rows> { - public: - template - static void run(Derived1 &dst, const Derived2 &src) - { - EI_UNUSED(dst); - EI_UNUSED(src); - } + template + static void run(Derived1 &dst, const Derived2 &src) + { + dst.write(0, 0) = src.read(0, 0); + } +}; + +template struct EiCopyHelperUnroller +{ + template + static void run(Derived1 &dst, const Derived2 &src) + { + EI_UNUSED(dst); + EI_UNUSED(src); + } }; template template void EiObject::_copy_helper(const EiObject& other) { - if(UnrollCount > 0 && UnrollCount <= EI_LOOP_UNROLLING_LIMIT) - EiCopyHelperUnroller::run(*this, other); + if(SizeAtCompileTime != EiDynamic && SizeAtCompileTime <= EI_LOOP_UNROLLING_LIMIT) + EiCopyHelperUnroller::run(*this, other); else for(int i = 0; i < rows(); i++) for(int j = 0; j < cols(); j++) diff --git a/src/Core/Dot.h b/src/Core/Dot.h new file mode 100644 index 000000000..2e0f3958b --- /dev/null +++ b/src/Core/Dot.h @@ -0,0 +1,83 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2006-2007 Benoit Jacob +// +// Eigen is free software; 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 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 General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along +// with Eigen; if not, write to the Free Software Foundation, Inc., 51 +// Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. This exception does not invalidate any other reasons why a work +// based on this file might be covered by the GNU General Public License. + +#ifndef EI_DOT_H +#define EI_DOT_H + +template +struct EiDotUnroller +{ + static void run(const Derived1 &v1, const Derived2& v2, typename Derived1::Scalar &dot) + { + const int i = Index - 1; + if(i == Size - 1) + dot = v1[i] * EiConj(v2[i]); + else + dot += v1[i] * EiConj(v2[i]); + EiDotUnroller::run(v1, v2, dot); + } +}; + +template +struct EiDotUnroller<0, Size, Derived1, Derived2> +{ + static void run(const Derived1 &v1, const Derived2& v2, typename Derived1::Scalar &dot) + { + EI_UNUSED(v1); + EI_UNUSED(v2); + EI_UNUSED(dot); + } +}; + +template +struct EiDotUnroller +{ + static void run(const Derived1 &v1, const Derived2& v2, typename Derived1::Scalar &dot) + { + EI_UNUSED(v1); + EI_UNUSED(v2); + EI_UNUSED(dot); + } +}; + +template +template +Scalar EiObject::dot(const OtherDerived& other) const +{ + assert(IsVector && OtherDerived::IsVector && size() == other.size()); + Scalar res; + if(SizeAtCompileTime != EiDynamic && SizeAtCompileTime <= 16) + EiDotUnroller + ::run(*static_cast(this), other, res); + else + { + res = (*this)[0] * EiConj(other[0]); + for(int i = 1; i < size(); i++) + res += (*this)[i]* EiConj(other[i]); + } + return res; +} + +#endif // EI_DOT_H diff --git a/src/Core/MatrixOps.h b/src/Core/MatrixOps.h index 54803a95c..167296527 100644 --- a/src/Core/MatrixOps.h +++ b/src/Core/MatrixOps.h @@ -105,6 +105,49 @@ template class EiDifference const RhsRef m_rhs; }; +template +struct EiMatrixProductUnroller +{ + static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, + typename Lhs::Scalar &res) + { + const int i = Index - 1; + if(i == Size - 1) + res = lhs.read(row, i) * rhs.read(i, col); + else + res += lhs.read(row, i) * rhs.read(i, col); + EiMatrixProductUnroller::run(row, col, lhs, rhs, res); + } +}; + +template +struct EiMatrixProductUnroller<0, Size, Lhs, Rhs> +{ + static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, + typename Lhs::Scalar &res) + { + EI_UNUSED(row); + EI_UNUSED(col); + EI_UNUSED(lhs); + EI_UNUSED(rhs); + EI_UNUSED(res); + } +}; + +template +struct EiMatrixProductUnroller +{ + static void run(int row, int col, const Lhs& lhs, const Rhs& rhs, + typename Lhs::Scalar &res) + { + EI_UNUSED(row); + EI_UNUSED(col); + EI_UNUSED(lhs); + EI_UNUSED(rhs); + EI_UNUSED(res); + } +}; + template class EiMatrixProduct : public EiObject > { @@ -136,17 +179,17 @@ template class EiMatrixProduct Scalar _read(int row, int col) const { - if(Lhs::ColsAtCompileTime == 3) - { - return m_lhs(row,0) * m_rhs(0,col) + m_lhs(row,1) * m_rhs(1,col) + m_lhs(row,2) * m_rhs(2,col); - } + Scalar res; + if(Lhs::ColsAtCompileTime != EiDynamic && Lhs::ColsAtCompileTime <= 16) + EiMatrixProductUnroller + ::run(row, col, m_lhs, m_rhs, res); else { - Scalar x = static_cast(0); - for(int i = 0; i < m_lhs.cols(); i++) - x += m_lhs.read(row, i) * m_rhs.read(i, col); - return x; + res = m_lhs(row, 0) * m_rhs(0, col); + for(int i = 1; i < m_lhs.cols(); i++) + res += m_lhs(row, i) * m_rhs(i, col); } + return res; } protected: diff --git a/src/Core/Object.h b/src/Core/Object.h index 610505707..14b1647fc 100644 --- a/src/Core/Object.h +++ b/src/Core/Object.h @@ -29,11 +29,11 @@ template class EiObject { static const int RowsAtCompileTime = Derived::RowsAtCompileTime, - ColsAtCompileTime = Derived::ColsAtCompileTime; - static const bool HasDynamicSize = RowsAtCompileTime != EiDynamic - && ColsAtCompileTime != EiDynamic; - static const int UnrollCount = HasDynamicSize ? - RowsAtCompileTime * ColsAtCompileTime : 0; + ColsAtCompileTime = Derived::ColsAtCompileTime, + SizeAtCompileTime + = RowsAtCompileTime == EiDynamic || ColsAtCompileTime == EiDynamic + ? EiDynamic : RowsAtCompileTime * ColsAtCompileTime; + static const bool IsVector = RowsAtCompileTime == 1 || ColsAtCompileTime == 1; template void _copy_helper(const EiObject& other); @@ -88,6 +88,9 @@ template class EiObject EiTranspose > adjoint() const { return conjugate().transpose(); } Scalar trace() const; + template + Scalar dot(const OtherDerived& other) const; + template EiMatrixProduct lazyMul(const EiObject& other) const EI_ALWAYS_INLINE; @@ -121,14 +124,14 @@ template class EiObject Scalar operator[](int index) const { - assert(RowsAtCompileTime == 1 || ColsAtCompileTime == 1); + assert(IsVector); if(RowsAtCompileTime == 1) return read(0, index); else return read(index, 0); } Scalar& operator[](int index) { - assert(RowsAtCompileTime == 1 || ColsAtCompileTime == 1); + assert(IsVector); if(RowsAtCompileTime == 1) return write(0, index); else return write(index, 0); } diff --git a/src/Core/Trace.h b/src/Core/Trace.h index c61944afd..e78618ebe 100644 --- a/src/Core/Trace.h +++ b/src/Core/Trace.h @@ -1,7 +1,6 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. Eigen itself is part of the KDE project. // -// Copyright (C) 2007 Michael Olbrich // Copyright (C) 2006-2007 Benoit Jacob // // Eigen is free software; you can redistribute it and/or modify it under the @@ -27,25 +26,31 @@ #ifndef EI_TRACE_H #define EI_TRACE_H -template struct EiTraceUnroller +template struct EiTraceUnroller { - typedef typename Derived::Scalar Scalar; - - static void run(const Derived &mat, Scalar &trace) + static void run(const Derived &mat, typename Derived::Scalar &trace) { - if(CurrentRow == Rows - 1) - trace = mat(CurrentRow, CurrentRow); + const int i = Index - 1; + if(i == Rows - 1) + trace = mat(i, i); else - trace += mat(CurrentRow, CurrentRow); - EiTraceUnroller::run(mat, trace); + trace += mat(i, i); + EiTraceUnroller::run(mat, trace); } }; -template struct EiTraceUnroller<-1, Rows, Derived> +template struct EiTraceUnroller<0, Rows, Derived> { - typedef typename Derived::Scalar Scalar; + static void run(const Derived &mat, typename Derived::Scalar &trace) + { + EI_UNUSED(mat); + EI_UNUSED(trace); + } +}; - static void run(const Derived &mat, Scalar &trace) +template struct EiTraceUnroller +{ + static void run(const Derived &mat, typename Derived::Scalar &trace) { EI_UNUSED(mat); EI_UNUSED(trace); @@ -58,7 +63,7 @@ Scalar EiObject::trace() const assert(rows() == cols()); Scalar res; if(RowsAtCompileTime != EiDynamic && RowsAtCompileTime <= 16) - EiTraceUnroller + EiTraceUnroller ::run(*static_cast(this), res); else {