// Copyright (C) 2001-2009 Vivien Mallet
// Copyright (C) 2003-2009 Marc Duruflé
//
// This file is part of the linear-algebra library Seldon,
// http://seldon.sourceforge.net/.
//
// Seldon 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 2.1 of the License, or (at your option)
// any later version.
//
// Seldon 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 for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Seldon. If not, see http://www.gnu.org/licenses/.
#ifndef SELDON_FILE_FUNCTIONS_MATRIX_CXX
/*
Function defined in this file:
alpha.A -> A
Mlt(alpha, A)
A*B -> C
Mlt(A, B, C)
alpha.A*B -> C
Mlt(alpha, A, B, C)
alpha.A*B + beta.C -> C
MltAdd(alpha, A, B, beta, C)
alpha*A + B -> B
Add(alpha, A, B)
LU factorization of matrix A without pivoting.
GetLU(A)
Highest absolute value of A.
MaxAbs(A)
1-norm of matrix A.
Norm1(A)
infinity norm of matrix A.
NormInf(A)
Transpose(A)
*/
namespace Seldon
{
/////////
// MLT //
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1>
void Mlt(const T0 alpha,
Matrix<T1, Prop1, Storage1, Allocator1>& A) throw()
{
T1 alpha_ = alpha;
typename Matrix<T1, Prop1, Storage1, Allocator1>::pointer
data = A.GetData();
for (int i = 0; i < A.GetDataSize(); i++)
data[i] = alpha_ * data[i];
}
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2,
class T3, class Prop3, class Storage3, class Allocator3>
void Mlt(const T0 alpha,
const Matrix<T1, Prop1, Storage1, Allocator1>& A,
const Matrix<T2, Prop2, Storage2, Allocator2>& B,
Matrix<T3, Prop3, Storage3, Allocator3>& C)
{
C.Fill(T3(0));
MltAdd(alpha, A, B, T3(0), C);
}
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2>
void Mlt(const Matrix<T0, Prop0, Storage0, Allocator0>& A,
const Matrix<T1, Prop1, Storage1, Allocator1>& B,
Matrix<T2, Prop2, Storage2, Allocator2>& C)
{
C.Fill(T2(0));
MltAdd(T0(1), A, B, T2(0), C);
}
// MLT //
/////////
////////////
// MLTADD //
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2,
class T3,
class T4, class Prop4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, Storage1, Allocator1>& A,
const Matrix<T2, Prop2, Storage2, Allocator2>& B,
const T3 beta,
Matrix<T4, Prop4, Storage4, Allocator4>& C)
{
int na = A.GetN();
int mc = C.GetM();
int nc = C.GetN();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(A, B, C, "MltAdd(alpha, A, B, beta, C)");
#endif
T4 temp;
T4 alpha_(alpha);
T4 beta_(beta);
if (beta_ != T4(0))
for (int i = 0; i < Storage4::GetFirst(mc, nc); i++)
for (int j = 0; j < Storage4::GetSecond(mc, nc); j++)
C(Storage4::GetFirst(i, j), Storage4::GetSecond(i, j))
*= beta_;
else
for (int i = 0; i < Storage4::GetFirst(mc, nc); i++)
for (int j = 0; j < Storage4::GetSecond(mc, nc); j++)
C(Storage4::GetFirst(i, j), Storage4::GetSecond(i, j)) = T4(0);
for (int i = 0; i < Storage4::GetFirst(mc, nc); i++)
for (int j = 0; j < Storage4::GetSecond(mc, nc); j++)
{
temp = T4(0);
for (int k = 0; k < na; k++)
temp += A(Storage4::GetFirst(i, j), k)
* B(k, Storage4::GetSecond(i, j));
C(Storage4::GetFirst(i, j), Storage4::GetSecond(i, j))
+= alpha_ * temp;
}
}
// MLTADD //
////////////
/////////
// ADD //
template<class T0, class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void Add(const T0& alpha,
const Matrix<T1, General, Storage1, Allocator1>& A,
Matrix<T2, General, Storage2, Allocator2>& B)
{
int i, j;
for (i = 0; i < A.GetM(); i++)
for (j = 0; j < A.GetN(); j++)
B(i, j) += alpha * A(i, j);
}
template<class T0, class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void Add(const T0& alpha,
const Matrix<T1, Symmetric, Storage1, Allocator1>& A,
Matrix<T2, Symmetric, Storage2, Allocator2>& B)
{
int i, j;
for (i = 0; i < A.GetM(); i++)
for (j = i; j < A.GetN(); j++)
B(i, j) += alpha * A(i, j);
}
// ADD //
/////////
///////////
// GETLU //
// Returns the LU decomposition of A = LU (in A)
// where L diagonal elements are set to unit value.
template <class T0, class Prop0, class Storage0, class Allocator0>
void GetLU(Matrix<T0, Prop0, Storage0, Allocator0>& A)
{
int i, p, q, k;
T0 temp;
int ma = A.GetM();
#ifdef SELDON_CHECK_BOUNDS
int na = A.GetN();
if (na != ma)
throw WrongDim("GetLU(A)", "The matrix must be squared.");
#endif
for (i = 0; i < ma; i++)
{
for (p = i; p < ma; p++)
{
temp = 0;
for (k = 0; k < i; k++)
temp += A(p, k) * A(k, i);
A(p, i) -= temp;
}
for (q = i+1; q < ma; q++)
{
temp = 0;
for (k = 0; k < i; k++)
temp += A(i, k) * A(k, q);
A(i, q) = (A(i,q ) - temp) / A(i, i);
}
}
}
// GETLU //
///////////
//////////////
// CHECKDIM //
//! Checks the compatibility of the dimensions.
/*! Checks that A.B + C -> C is possible according to the dimensions of
the matrices A, B and C. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param A matrix.
\param B matrix.
\param C matrix.
\param function (optional) function in which the compatibility is checked.
Default: "".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2>
void CheckDim(const Matrix<T0, Prop0, Storage0, Allocator0>& A,
const Matrix<T1, Prop1, Storage1, Allocator1>& B,
const Matrix<T2, Prop2, Storage2, Allocator2>& C,
string function = "")
{
if (B.GetM() != A.GetN() || C.GetM() != A.GetM() || B.GetN() != C.GetN())
throw WrongDim(function, string("Operation A.B + C -> C not permitted:")
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix;\n C (")
+ to_str(&C) + string(") is a ") + to_str(C.GetM())
+ string(" x ") + to_str(C.GetN()) + string(" matrix."));
}
#ifdef SELDON_WITH_CBLAS
//! Checks the compatibility of the dimensions.
/*! Checks that A.B + C -> C or B.A + C -> C is possible according to the
dimensions of the matrices A, B and C. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param side side by which A is multiplied by B.
\param A matrix.
\param B matrix.
\param C matrix.
\function (optional) function in which the compatibility is checked.
Default: "".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2>
void CheckDim(const enum CBLAS_SIDE side,
const Matrix<T0, Prop0, Storage0, Allocator0>& A,
const Matrix<T1, Prop1, Storage1, Allocator1>& B,
const Matrix<T2, Prop2, Storage2, Allocator2>& C,
string function = "")
{
if ( SeldonSide(side).Left() &&
(B.GetM() != A.GetN() || C.GetM() != A.GetM()
|| B.GetN() != C.GetN()) )
throw WrongDim(function, string("Operation A.B + C -> C not permitted:")
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix;\n C (")
+ to_str(&C) + string(") is a ") + to_str(C.GetM())
+ string(" x ") + to_str(C.GetN()) + string(" matrix."));
else if ( SeldonSide(side).Right() &&
(B.GetN() != A.GetM() || C.GetM() != B.GetM()
|| A.GetN() != C.GetN()) )
throw WrongDim(function, string("Operation B.A + C -> C not permitted:")
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix;\n C (")
+ to_str(&C) + string(") is a ") + to_str(C.GetM())
+ string(" x ") + to_str(C.GetN()) + string(" matrix."));
}
#endif
#ifdef SELDON_WITH_CBLAS
//! Checks the compatibility of the dimensions.
/*! Checks that A.B + C -> C is possible according to the dimensions of
the matrices A, B and C. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param TransA status of A, e.g. transposed.
\param A matrix.
\param TransB status of B, e.g. transposed.
\param B matrix.
\param C matrix.
\function (optional) function in which the compatibility is checked.
Default: "".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Prop2, class Storage2, class Allocator2>
void CheckDim(const enum CBLAS_TRANSPOSE TransA,
const Matrix<T0, Prop0, Storage0, Allocator0>& A,
const enum CBLAS_TRANSPOSE TransB,
const Matrix<T1, Prop1, Storage1, Allocator1>& B,
const Matrix<T2, Prop2, Storage2, Allocator2>& C,
string function = "")
{
SeldonTranspose status_A(TransA);
SeldonTranspose status_B(TransB);
string op;
if (status_A.Trans())
op = string("A'");
else if (status_A.ConjTrans())
op = string("A*");
else
op = string("A");
if (status_B.Trans())
op += string(".B' + C");
else if (status_B.ConjTrans())
op += string(".B* + C");
else
op += string(".B + C");
op = string("Operation ") + op + string(" not permitted:");
if (B.GetM(status_B) != A.GetN(status_A) || C.GetM() != A.GetM(status_A)
|| B.GetN(status_B) != C.GetN())
throw WrongDim(function, op
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix;\n C (")
+ to_str(&C) + string(") is a ") + to_str(C.GetM())
+ string(" x ") + to_str(C.GetN()) + string(" matrix."));
}
#endif
#ifdef SELDON_WITH_CBLAS
//! Checks the compatibility of the dimensions.
/*! Checks that A.B or B.A is possible according to the dimensions of
the matrices A and B. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param side side by which A is multiplied by B.
\param A matrix.
\param B matrix.
\function (optional) function in which the compatibility is checked.
Default: "".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Prop1, class Storage1, class Allocator1>
void CheckDim(const enum CBLAS_SIDE side,
const Matrix<T0, Prop0, Storage0, Allocator0>& A,
const Matrix<T1, Prop1, Storage1, Allocator1>& B,
string function = "")
{
if (SeldonSide(side).Left() && B.GetM() != A.GetN())
throw WrongDim(function, string("Operation A.B not permitted:")
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix."));
else if (SeldonSide(side).Right() && B.GetN() != A.GetM())
throw WrongDim(function, string("Operation B.A not permitted:")
+ string("\n A (") + to_str(&A) + string(") is a ")
+ to_str(A.GetM()) + string(" x ") + to_str(A.GetN())
+ string(" matrix;\n B (") + to_str(&B)
+ string(") is a ") + to_str(B.GetM()) + string(" x ")
+ to_str(B.GetN()) + string(" matrix."));
}
#endif
// CHECKDIM //
//////////////
///////////
// NORMS //
//! Returns the maximum (in absolute value) of a matrix.
/*!
\param A matrix.
\return The maximum (in absolute value) of matrix A.
*/
template <class T, class Prop, class Storage, class Allocator>
T MaxAbs(const Matrix<T, Prop, Storage, Allocator>& A)
{
T res(0);
for (int i = 0; i < A.GetM(); i++)
for (int j = 0; j < A.GetN(); j++)
res = max(res, abs(A(i, j)) );
return res;
}
//! Returns the 1-norm of a matrix.
/*!
\param A matrix.
\return \f$ max_j \sum_i |A_{ij}| \f$
*/
template <class T, class Prop, class Storage, class Allocator>
T Norm1(const Matrix<T, Prop, Storage, Allocator>& A)
{
T res(0), sum;
for (int j = 0; j < A.GetN(); j++)
{
sum = T(0);
for (int i = 0; i < A.GetM(); i++)
sum += abs( A(i, j) );
res = max(res, sum);
}
return res;
}
//! Returns the infinity-norm of a matrix.
/*!
\param A matrix.
\return \f$ max_i \sum_j |A_{ij}| \f$
*/
template <class T, class Prop, class Storage, class Allocator>
T NormInf(const Matrix<T, Prop, Storage, Allocator>& A)
{
T res(0), sum;
for (int i = 0; i < A.GetM(); i++)
{
sum = T(0);
for (int j = 0; j < A.GetN(); j++)
sum += abs( A(i, j) );
res = max(res, sum);
}
return res;
}
//! Returns the maximum (in modulus) of a matrix.
/*!
\param A matrix.
\return The maximum (in modulus) of matrix A.
*/
template <class T, class Prop, class Storage, class Allocator>
T MaxAbs(const Matrix<complex<T>, Prop, Storage, Allocator>& A)
{
T res(0);
for (int i = 0; i < A.GetM(); i++)
for (int j = 0; j < A.GetN(); j++)
{
res = max(res, abs(A(i, j)) );
}
return res;
}
//! Returns the 1-norm of a matrix.
/*!
\param A matrix.
\return \f$ max_j \sum_i |A_{ij}| \f$
*/
template <class T, class Prop, class Storage, class Allocator>
T Norm1(const Matrix<complex<T>, Prop, Storage, Allocator>& A)
{
T res(0), sum;
for (int j = 0; j < A.GetN(); j++)
{
sum = T(0);
for (int i = 0; i < A.GetM(); i++)
sum += abs( A(i, j) );
res = max(res, sum);
}
return res;
}
//! Returns the infinity-norm of a matrix.
/*!
\param A matrix.
\return \f$ max_i \sum_j |A_{ij}| \f$
*/
template <class T, class Prop, class Storage, class Allocator>
T NormInf(const Matrix<complex<T>, Prop, Storage, Allocator>& A)
{
T res(0), sum;
for (int i = 0; i < A.GetM(); i++)
{
sum = T(0);
for (int j = 0; j < A.GetN(); j++)
sum += abs( A(i, j) );
res = max(res, sum);
}
return res;
}
// NORMS //
///////////
///////////////
// TRANSPOSE //
//! Matrix transposition.
template<class T, class Prop, class Storage, class Allocator>
void Transpose(Matrix<T, Prop, Storage, Allocator>& A)
{
int m = A.GetM();
int n = A.GetN();
if (m == n)
{
T tmp;
for (int i = 0; i < m; i++)
for (int j = 0; j < i; j++)
{
tmp = A(i,j);
A(i,j) = A(j,i);
A(j,i) = tmp;
}
}
else
{
Matrix<T, Prop, Storage, Allocator> B;
B = A;
A.Reallocate(n,m);
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
A(j,i) = B(i,j);
}
}
//! Matrix transposition and conjugation.
template<class T, class Prop, class Storage, class Allocator>
void TransposeConj(Matrix<T, Prop, Storage, Allocator>& A)
{
int i, j;
int m = A.GetM();
int n = A.GetN();
if (m == n)
{
T tmp;
for (i = 0; i < m; i++)
for (j = 0; j < i; j++)
{
tmp = A(i, j);
A(i, j) = conj(A(j, i));
A(j, i) = conj(tmp);
}
}
else
{
Matrix<T, Prop, Storage, Allocator> B;
B = A;
A.Reallocate(n, m);
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
A(j, i) = conj(B(i, j));
}
}
// TRANSPOSE //
///////////////
///////////////////////
// ISSYMMETRICMATRIX //
//! returns true if the matrix is symmetric
template<class T, class Prop, class Storage, class Allocator>
bool IsSymmetricMatrix(const Matrix<T, Prop, Storage, Allocator>& A)
{
return false;
}
//! returns true if the matrix is symmetric
template<class T, class Storage, class Allocator>
bool IsSymmetricMatrix(const Matrix<T, Symmetric, Storage, Allocator>& A)
{
return true;
}
// ISSYMMETRICMATRIX //
///////////////////////
} // namespace Seldon.
#define SELDON_FILE_FUNCTIONS_MATRIX_CXX
#endif