blob: 8651d2293621c0c68562d1b99487e66fdd823925 [file]
/*
* $Id: tvmet.cc,v 1.3 2003/10/21 19:37:06 opetzold Exp $
*
* This file shows the basic principle used by tvmet. Therefore
* you will not find promotion etc. here.
*/
extern "C" int printf(const char*, ...);
#ifndef restrict
#define restrict __restrict__
#endif
template<unsigned Rows, unsigned Cols> class Matrix;
struct XprNull { explicit XprNull() { } };
static inline
double operator+(const double& lhs, XprNull) { return lhs; }
struct Fcnl_Assign { static inline void apply_on(double& restrict lhs, double rhs) { lhs = rhs; } };
template<unsigned Rows, unsigned Cols,
unsigned RowStride, unsigned ColStride>
struct MetaMatrix
{
enum {
doRows = (RowStride < Rows - 1) ? 1 : 0,
doCols = (ColStride < Cols - 1) ? 1 : 0
};
template<class E1, class E2, class Fcnl>
static inline
void assign2(E1& lhs, const E2& rhs, const Fcnl& fn) {
fn.apply_on( lhs(RowStride, ColStride), rhs(RowStride, ColStride) );
MetaMatrix<Rows * doCols, Cols * doCols, RowStride * doCols, (ColStride+1) * doCols>::assign2(lhs, rhs, fn);
}
template<class E1, class E2, class Fcnl>
static inline
void assign(E1& lhs, const E2& rhs, const Fcnl& fn) {
MetaMatrix<Rows, Cols, RowStride, 0>::assign2(lhs, rhs, fn);
MetaMatrix<Rows * doRows, Cols * doRows, (RowStride+1) * doRows, 0>::assign(lhs, rhs, fn);
}
};
template<>
struct MetaMatrix<0, 0, 0, 0>
{
template<class E1, class E2, class Fcnl>
static inline void assign2(E1&, const E2&, const Fcnl&) { }
template<class E1, class E2, class Fcnl>
static inline void assign(E1&, const E2&, const Fcnl&) { }
};
template<unsigned Rows1, unsigned Cols1,
unsigned Cols2,
unsigned RowStride1, unsigned ColStride1,
unsigned RowStride2, unsigned ColStride2,
unsigned K>
struct MetaGemm
{
enum { doIt = (K != Cols1 - 1) };
template<class E1, class E2>
static inline
double prod(const E1& lhs, const E2& rhs, unsigned i, unsigned j) {
return lhs(i, K) * rhs(K, j)
+ MetaGemm<Rows1 * doIt, Cols1 * doIt,
Cols2 * doIt, RowStride1 * doIt, ColStride1 * doIt,
RowStride2 * doIt, ColStride2 * doIt, (K+1) * doIt>::prod(lhs, rhs, i, j);
}
};
template<>
struct MetaGemm<0,0,0,0,0,0,0,0>
{
template<class E1, class E2>
static inline XprNull prod(const E1&, const E2&, unsigned, unsigned) { return XprNull(); }
};
template<class E1, class E2,
unsigned Rows1, unsigned Cols1,
unsigned Cols2,
unsigned RowStride1, unsigned ColStride1,
unsigned RowStride2, unsigned ColStride2>
struct XprMMProduct
{
explicit XprMMProduct(const E1& lhs, const E2& rhs) : m_lhs(lhs), m_rhs(rhs) { }
double operator()(unsigned i, unsigned j) const {
return MetaGemm<
Rows1, Cols1,
Cols2,
RowStride1, ColStride1,
RowStride2, ColStride2, 0>::prod(m_lhs, m_rhs, i, j);
}
// void assign_to(Matrix<Rows1, Cols2>& rhs) const {
// MetaMatrix<Rows1, Cols2, 0, 0>::assign(rhs, *this, Fcnl_Assign());
// }
private:
const E1 m_lhs;
const E2 m_rhs;
};
template<class E>
struct XprMatrixTranspose
{
explicit XprMatrixTranspose(const E& e) : m_expr(e) { }
double operator()(unsigned i, unsigned j) const { return m_expr(j, i); }
// template<unsigned Rows, unsigned Cols>
// void assign_to(Matrix<Rows, Cols>& rhs) const {
// MetaMatrix<Rows, Cols, 0, 0>::assign(rhs, *this, Fcnl_Assign());
// }
private:
const E m_expr;
};
template<class E, unsigned Rows, unsigned Cols>
struct XprMatrix
{
explicit XprMatrix(const E& e) : m_expr(e) { }
double operator()(unsigned i, unsigned j) const { return m_expr(i, j); }
void assign_to(Matrix<Rows, Cols>& rhs) const {
MetaMatrix<Rows, Cols, 0, 0>::assign(rhs, *this, Fcnl_Assign());
}
private:
const E m_expr;
};
template<unsigned Rows, unsigned Cols,
unsigned RowStride, unsigned ColStride>
struct MatrixConstReference
{
explicit MatrixConstReference(const Matrix<Rows, Cols>& rhs) : m_data(rhs.m_data) { }
double operator()(unsigned i, unsigned j) const {
return m_data[i * RowStride + j * ColStride];
}
private:
const double* restrict m_data;
};
template<unsigned Rows, unsigned Cols>
struct Matrix
{
explicit Matrix() { m_data = new double [Rows*Cols]; }
template<class E>
explicit Matrix(const XprMatrix<E, Rows, Cols>& rhs) {
m_data = new double [Rows*Cols];
MetaMatrix<Rows, Cols, 0, 0>::assign(*this, rhs, Fcnl_Assign());
}
~Matrix() { delete [] m_data; }
double& restrict operator()(unsigned i, unsigned j) { return m_data[i * Cols + j]; }
double operator()(unsigned i, unsigned j) const { return m_data[i * Cols + j]; }
MatrixConstReference<Rows,Cols,Cols,1> const_ref() const {
return MatrixConstReference<Rows,Cols,Cols,1>(*this);
}
Matrix& operator=(const Matrix<Rows, Cols>& rhs) {
rhs.assign_to(*this);
return *this;
}
void assign_to(Matrix<Rows, Cols>& rhs) const {
MetaMatrix<Rows, Cols, 0, 0>::assign(rhs, *this, Fcnl_Assign());
}
template <class E>
Matrix& operator=(const XprMatrix<E, Rows, Cols>& rhs) {
rhs.assign_to(*this);
return *this;
}
template <class E>
void assign_to(XprMatrix<E, Rows, Cols>& rhs) const {
MetaMatrix<Rows, Cols, 0, 0>::assign(rhs, *this, Fcnl_Assign());
}
void print() const {
printf("[\n");
for(unsigned i = 0; i != Rows; ++i) {
printf("\t[");
for(unsigned j = 0; j != Cols; ++j)
printf("\t%+4.2f", this->operator()(i, j));
printf("]\n");
}
printf("]\n");
}
double* m_data;
};
template<unsigned Rows1, unsigned Cols1,
unsigned Cols2>
inline
XprMatrix<
XprMMProduct<
MatrixConstReference<Rows1, Cols1, Cols1, 1>,
MatrixConstReference<Cols1, Cols2, Cols2, 1>,
Rows1, Cols1, // M1(Rows1, Cols1)
Cols2, // M2(Cols1, Cols2)
Cols1, 1, // Stride M1
Cols2, 1 // Stride M2
>,
Rows1, Cols2 // return Dim
>
prod(const Matrix<Rows1, Cols1>& lhs, const Matrix<Cols1, Cols2>& rhs) {
typedef XprMMProduct<
MatrixConstReference<Rows1, Cols1, Cols1, 1>,
MatrixConstReference<Cols1, Cols2, Cols2, 1>,
Rows1, Cols1,
Cols2,
Cols1, 1,
Cols2, 1
> expr_type;
return XprMatrix<expr_type, Rows1, Cols2>(
expr_type(lhs.const_ref(), rhs.const_ref()));
}
template<class E1, unsigned Rows1, unsigned Cols1, unsigned Cols2>
inline
XprMatrix<
XprMMProduct<
XprMatrix<E1, Rows1, Cols1>,
MatrixConstReference<Cols1, Cols2, Cols2, 1>,
Rows1, Cols1, Cols2,
Cols1, 1, Cols2, 1
>,
Rows1, Cols2
>
prod(const XprMatrix<E1, Rows1, Cols1>& lhs, const Matrix<Cols1, Cols2>& rhs) {
typedef XprMMProduct<
XprMatrix<E1, Rows1, Cols1>,
MatrixConstReference<Cols1, Cols2, Cols2, 1>,
Rows1, Cols1, Cols2,
Cols1, 1, Cols2, 1
> expr_type;
return XprMatrix<expr_type, Rows1, Cols2>(expr_type(lhs, rhs.const_ref()));
}
template<unsigned Rows, unsigned Cols>
inline
XprMatrix<
XprMatrixTranspose<
MatrixConstReference<Rows, Cols, Cols, 1>
>,
Cols, Rows
>
trans(const Matrix<Rows, Cols>& rhs) {
typedef XprMatrixTranspose<
MatrixConstReference<Rows, Cols, Cols, 1>
> expr_type;
return XprMatrix<expr_type, Cols, Rows>(expr_type(rhs.const_ref()));
}
/**
* Test driver
*/
int main()
{
Matrix<3,2> B;
Matrix<3,3> D;
B(0,0) = -0.05; B(0,1) = 0;
B(1,0) = 0; B(1,1) = 0.05;
B(2,0) = 0.05; B(2,1) = -0.05;
D(0,0) = 2000; D(0,1) = 1000; D(0,2) = 0;
D(1,0) = 1000; D(1,1) = 2000; D(1,2) = 0;
D(2,0) = 0; D(2,1) = 0; D(2,2) = 500;
printf("B = ");
B.print();
printf("D = ");
D.print();
printf("\n***********************************************\n");
Matrix<2,2> K;
K = prod(prod(trans(B), D), B);
printf("Check: (equal prod(prod(trans(B), D), B)\n");
printf(" K = ");
K.print();
}