// Copyright (C) 2001-2009 Vivien Mallet
//
// 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_MATVECT_CXX
/*
Functions defined in this file:
M*X -> Y
Mlt(M, X, Y)
alpha.M*X -> Y
Mlt(alpha, M, X, Y)
alpha.M*X + beta.Y -> Y
MltAdd(alpha, M, X, beta, Y)
*/
namespace Seldon
{
/////////
// MLT //
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void Mlt(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
Vector<T2, Storage2, Allocator2>& Y)
{
Y.Fill(T2(0));
MltAdd(T2(1), M, X, T2(0), Y);
}
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3, class Storage3, class Allocator3>
void Mlt(const T0 alpha,
const Matrix<T1, Prop1, Storage1, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
Vector<T3, Storage3, Allocator3>& Y)
{
Y.Fill(T2(0));
MltAdd(alpha, M, X, T3(0), Y);
}
// MLT //
/////////
////////////
// MltAdd //
/*** Sparse matrices ***/
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, RowSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(M, X, Y, "MltAdd(alpha, M, X, beta, Y)");
#endif
Mlt(beta, Y);
T4 zero(0);
T4 temp;
int* ptr = M.GetPtr();
int* ind = M.GetInd();
typename Matrix<T1, Prop1, RowSparse, Allocator1>::pointer
data = M.GetData();
for (int i = 0; i < ma; i++)
{
temp = zero;
for (int j = ptr[i]; j < ptr[i+1]; j++)
temp += data[j] * X(ind[j]);
Y(i) += alpha * temp;
}
}
/*** Complex sparse matrices ***/
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, RowComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int i, j;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(M, X, Y, "MltAdd(alpha, M, X, beta, Y)");
#endif
Mlt(beta, Y);
complex<T1> zero(0);
complex<T1> temp;
int* real_ptr = M.GetRealPtr();
int* imag_ptr = M.GetImagPtr();
int* real_ind = M.GetRealInd();
int* imag_ind = M.GetImagInd();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
real_data = M.GetRealData();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
imag_data = M.GetImagData();
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
temp += real_data[j] * X(real_ind[j]);
Y(i) += alpha * temp;
}
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
temp += complex<T1>(T1(0), imag_data[j]) * X(imag_ind[j]);
Y(i) += alpha * temp;
}
}
/*** Symmetric sparse matrices ***/
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, RowSymSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(M, X, Y, "MltAdd(alpha, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int i, j;
T4 zero(0);
T4 temp;
int* ptr = M.GetPtr();
int* ind = M.GetInd();
typename Matrix<T1, Prop1, RowSymSparse, Allocator1>::pointer
data = M.GetData();
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = ptr[i]; j < ptr[i + 1]; j++)
temp += data[j] * X(ind[j]);
Y(i) += alpha * temp;
}
for (i = 0; i < ma-1; i++)
for (j = ptr[i]; j < ptr[i + 1]; j++)
if (ind[j] != i)
Y(ind[j]) += alpha * data[j] * X(i);
}
/*** Symmetric complex sparse matrices ***/
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(M, X, Y, "MltAdd(alpha, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int i, j;
complex<T1> zero(0);
complex<T1> temp;
int* real_ptr = M.GetRealPtr();
int* imag_ptr = M.GetImagPtr();
int* real_ind = M.GetRealInd();
int* imag_ind = M.GetImagInd();
typename Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>::pointer
real_data = M.GetRealData();
typename Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>::pointer
imag_data = M.GetImagData();
for (i = 0; i<ma; i++)
{
temp = zero;
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
temp += real_data[j] * X(real_ind[j]);
Y(i) += alpha * temp;
}
for (i = 0; i<ma-1; i++)
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
if (real_ind[j] != i)
Y(real_ind[j]) += alpha * real_data[j] * X(i);
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
temp += complex<T1>(T1(0), imag_data[j]) * X(imag_ind[j]);
Y(i) += alpha * temp;
}
for (i = 0; i<ma-1; i++)
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
if (imag_ind[j] != i)
Y(imag_ind[j]) += alpha * complex<T1>(T1(0), imag_data[j]) * X(i);
}
/*** Sparse matrices, *Trans ***/
// NoTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonNoTrans& Trans,
const Matrix<T1, Prop1, RowSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// Trans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonTrans& Trans,
const Matrix<T1, Prop1, RowSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int i, j;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int* ptr = M.GetPtr();
int* ind = M.GetInd();
typename Matrix<T1, Prop1, RowSparse, Allocator1>::pointer
data = M.GetData();
for (i = 0; i < ma; i++)
for (j = ptr[i]; j < ptr[i + 1]; j++)
Y(ind[j]) += alpha * data[j] * X(i);
}
// ConjTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonConjTrans& Trans,
const Matrix<complex<T1>, Prop1, RowSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int i, j;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonConjTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int* ptr = M.GetPtr();
int* ind = M.GetInd();
typename Matrix<complex<T1>, Prop1, RowSparse, Allocator1>::pointer
data = M.GetData();
for (i = 0; i < ma; i++)
for (j = ptr[i]; j < ptr[i + 1]; j++)
Y(ind[j]) += alpha * conj(data[j]) * X(i);
}
/*** Complex sparse matrices, *Trans ***/
// NoTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonNoTrans& Trans,
const Matrix<T1, Prop1, RowComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// Trans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonTrans& Trans,
const Matrix<T1, Prop1, RowComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int i, j;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int* real_ptr = M.GetRealPtr();
int* imag_ptr = M.GetImagPtr();
int* real_ind = M.GetRealInd();
int* imag_ind = M.GetImagInd();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
real_data = M.GetRealData();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
imag_data = M.GetImagData();
for (i = 0; i < ma; i++)
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
Y(real_ind[j]) += alpha * real_data[j] * X(i);
for (i = 0; i < ma; i++)
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
Y(imag_ind[j]) += alpha * complex<T1>(T1(0), imag_data[j]) * X(i);
}
// ConjTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonConjTrans& Trans,
const Matrix<T1, Prop1, RowComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int i, j;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonConjTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int* real_ptr = M.GetRealPtr();
int* imag_ptr = M.GetImagPtr();
int* real_ind = M.GetRealInd();
int* imag_ind = M.GetImagInd();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
real_data = M.GetRealData();
typename Matrix<T1, Prop1, RowComplexSparse, Allocator1>::pointer
imag_data = M.GetImagData();
for (i = 0; i < ma; i++)
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
Y(real_ind[j]) += alpha * real_data[j] * X(i);
for (i = 0; i < ma; i++)
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
Y(imag_ind[j]) += alpha * complex<T1>(T1(0), - imag_data[j]) * X(i);
}
/*** Symmetric sparse matrices, *Trans ***/
// NoTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonNoTrans& Trans,
const Matrix<T1, Prop1, RowSymSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// Trans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonTrans& Trans,
const Matrix<T1, Prop1, RowSymSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// ConjTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonConjTrans& Trans,
const Matrix<complex<T1>, Prop1, RowSymSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonConjTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int i, j;
complex<T1> zero(0);
complex<T1> temp;
int* ptr = M.GetPtr();
int* ind = M.GetInd();
typename Matrix<complex<T1>, Prop1, RowSymSparse, Allocator1>::pointer
data = M.GetData();
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = ptr[i]; j < ptr[i + 1]; j++)
temp += conj(data[j]) * X(ind[j]);
Y(i) += temp;
}
for (i = 0; i < ma - 1; i++)
for (j = ptr[i]; j < ptr[i + 1]; j++)
if (ind[j] != i)
Y(ind[j]) += conj(data[j]) * X(i);
}
/*** Symmetric complex sparse matrices, *Trans ***/
// NoTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonNoTrans& Trans,
const Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// Trans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonTrans& Trans,
const Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
MltAdd(alpha, M, X, beta, Y);
}
// ConjTrans.
template <class T0,
class T1, class Prop1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const class_SeldonConjTrans& Trans,
const Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta, Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, SeldonConjTrans, M, X, beta, Y)");
#endif
Mlt(beta, Y);
int i, j;
complex<T1> zero(0);
complex<T1> temp;
int* real_ptr = M.GetRealPtr();
int* imag_ptr = M.GetImagPtr();
int* real_ind = M.GetRealInd();
int* imag_ind = M.GetImagInd();
typename Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>::pointer
real_data = M.GetRealData();
typename Matrix<T1, Prop1, RowSymComplexSparse, Allocator1>::pointer
imag_data = M.GetImagData();
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
temp += real_data[j] * X(real_ind[j]);
Y(i) += temp;
}
for (i = 0; i < ma - 1; i++)
for (j = real_ptr[i]; j < real_ptr[i + 1]; j++)
if (real_ind[j] != i)
Y(real_ind[j]) += real_data[j] * X(i);
for (i = 0; i < ma; i++)
{
temp = zero;
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
temp += complex<T1>(T1(0), - imag_data[j]) * X(imag_ind[j]);
Y(i) += temp;
}
for (i = 0; i < ma - 1; i++)
for (j = imag_ptr[i]; j < imag_ptr[i + 1]; j++)
if (imag_ind[j] != i)
Y(imag_ind[j]) += complex<T1>(T1(0), - imag_data[j]) * X(i);
}
// MltAdd //
////////////
////////////
// MltAdd //
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const Matrix<T1, Prop1, Storage1, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta,
Vector<T4, Storage4, Allocator4>& Y)
{
int ma = M.GetM();
int na = M.GetN();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(M, X, Y, "MltAdd(alpha, M, X, beta, Y)");
#endif
Mlt(beta, Y);
T4 zero(0);
T4 temp;
T4 alpha_(alpha);
for (int i = 0; i < ma; i++)
{
temp = zero;
for (int j = 0; j < na; j++)
temp += M(i, j) * X(j);
Y(i) += alpha_ * temp;
}
}
template <class T0,
class T1, class Prop1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3,
class T4, class Storage4, class Allocator4>
void MltAdd(const T0 alpha,
const SeldonTranspose& Trans,
const Matrix<T1, Prop1, Storage1, Allocator1>& M,
const Vector<T2, Storage2, Allocator2>& X,
const T3 beta,
Vector<T4, Storage4, Allocator4>& Y)
{
if (Trans.NoTrans())
{
MltAdd(alpha, M, X, beta, Y);
return;
}
else if (Trans.ConjTrans())
throw WrongArgument("MltAdd(alpha, trans, M, X, beta, Y)",
"Complex conjugation not supported.");
int ma = M.GetM();
int na = M.GetN();
#ifdef SELDON_CHECK_BOUNDS
CheckDim(Trans, M, X, Y, "MltAdd(alpha, trans, M, X, beta, Y)");
#endif
if (beta == T3(0))
Y.Fill(T4(0));
else
Mlt(beta, Y);
T4 zero(0);
T4 temp;
T4 alpha_(alpha);
for (int i = 0; i < na; i++)
{
temp = zero;
for (int j = 0; j < ma; j++)
temp += M(j, i) * X(j);
Y(i) += alpha_ * temp;
}
}
// MltAdd //
////////////
///////////
// Gauss //
// Solve X = M*Y with Gauss method.
// Warning: M is modified. The results are stored in X.
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1>
inline void Gauss(Matrix<T0, Prop0, Storage0, Allocator0>& M,
Vector<T1, Storage1, Allocator1>& X)
{
int i, j, k;
T1 r, S;
int ma = M.GetM();
int na = M.GetN();
#ifdef SELDON_CHECK_BOUNDS
if (na != ma)
throw WrongDim("Gauss(M, X)",
"The matrix must be squared.");
CheckDim(M, X, "Gauss(M, X)");
#endif
for (k = 0; k < ma - 1; k++)
for (i = k + 1; i < ma; i++)
{
r = M(i, k) / M(k, k);
for (j = k + 1; j < ma; j++)
M(i, j) -= r * M(k, j);
X(i) -= r *= X(k);
}
X(ma - 1) = X(ma - 1) / M(ma - 1, ma - 1);
for (k = ma - 2; k > -1; k--)
{
S = X(k);
for (j = k + 1; j < ma; j++)
S -= M(k, j) * X(j);
X(k) = S / M(k, k);
}
}
// Gauss //
///////////
////////////////////
// Gauss - Seidel //
// Solve X = M*Y with Gauss-Seidel method.
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
inline void GaussSeidel(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
Vector<T2, Storage2, Allocator2>& Y,
int iter)
{
int i, j, k;
T1 temp;
int ma = M.GetM();
int na = M.GetN();
#ifdef SELDON_CHECK_BOUNDS
if (na != ma)
throw WrongDim("GaussSeidel(M, X, Y, iter)",
"The matrix must be squared.");
CheckDim(M, X, Y, "GaussSeidel(M, X, Y, iter)");
#endif
for (i = 0; i < iter; i++)
for (j = 0; j < na; j++)
{
temp = 0;
for (k = 0; k < j; k++)
temp -= M(j, k) * Y(k);
for (k = j + 1; k < na; k++)
temp -= M(j, k) * Y(k);
Y(j) = (X(j) + temp) / M(j, j);
}
}
// Gauss-Seidel //
//////////////////
///////////////////
// S.O.R. method //
// Solve X = M*Y with S.O.R. method.
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2,
class T3>
inline void SOR(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
Vector<T2, Storage2, Allocator2>& Y,
T3 omega,
int iter)
{
int i, j, k;
T1 temp;
int ma = M.GetM();
int na = M.GetN();
#ifdef SELDON_CHECK_BOUNDS
if (na != ma)
throw WrongDim("SOR(M, X, Y, omega, iter)",
"The matrix must be squared.");
CheckDim(M, X, Y, "SOR(M, X, Y, omega, iter)");
#endif
for (i = 0; i < iter; i++)
for (j = 0; j < na; j++)
{
temp = 0;
for (k = 0; k < j; k++)
temp -= M(j, k) * Y(k);
for (k = j + 1; k < na; k++)
temp -= M(j, k) * Y(k);
Y(j) = (T3(1) - omega) * Y(j) + omega * (X(j) + temp) / M(j, j);
}
}
// Gauss-Seidel //
//////////////////
/////////////
// SolveLU //
// Solves M.X = Y where A has been decomposed in a LU form.
// Y is overwritten (Y <- X).
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1>
void SolveLU(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
Vector<T1, Storage1, Allocator1>& Y)
{
int i, k;
T1 temp;
int ma = M.GetM();
#ifdef SELDON_CHECK_BOUNDS
int na = M.GetN();
if (na != ma)
throw WrongDim("SolveLU(M, Y)",
"The matrix must be squared.");
CheckDim(M, Y, "SolveLU(M, Y)");
#endif
// Forward substitution.
for (i = 0; i < ma; i++)
{
temp = 0;
for (k = 0; k < i; k++)
temp += M(i, k) * Y(k);
Y(i) = (Y(i) - temp) / M(i, i);
}
// Back substitution.
for (i = ma - 2; i > -1; i--)
{
temp = 0;
for (k = i + 1; k < ma; k++)
temp += M(i, k) * Y(k);
Y(i) -= temp;
}
}
// SolveLU //
/////////////
//////////////
// CHECKDIM //
//! Checks the compatibility of the dimensions.
/*! Checks that M.X + Y -> Y is possible according to the dimensions of
the matrix M and the vectors X and Y. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param M matrix.
\param X vector.
\param Y vector.
\param function (optional) function in which the compatibility is checked.
Default: "".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void CheckDim(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
const Vector<T2, Storage2, Allocator2>& Y,
string function = "")
{
if (X.GetLength() != M.GetN() || Y.GetLength() != M.GetM())
throw WrongDim(function, string("Operation M.X + Y -> Y not permitted:")
+ string("\n M (") + to_str(&M) + string(") is a ")
+ to_str(M.GetM()) + string(" x ") + to_str(M.GetN())
+ string(" matrix;\n X (") + to_str(&X)
+ string(") is vector of length ")
+ to_str(X.GetLength()) + string(";\n Y (")
+ to_str(&Y) + string(") is vector of length ")
+ to_str(Y.GetLength()) + string("."));
}
//! Checks the compatibility of the dimensions.
/*! Checks that M.X + Y -> Y is possible according to the dimensions of
the matrix M and the vectors X and Y. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param status status of the matrix M, e.g. transposed.
\param M matrix.
\param X vector.
\param Y vector.
\param function (optional) function in which the compatibility is checked.
Default: "".
\param op (optional) operation to be performed on the vectors.
Default: "M.X + Y -> Y".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void CheckDim(const SeldonTranspose& status,
const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
const Vector<T2, Storage2, Allocator2>& Y,
string function = "", string op = "M.X + Y -> Y")
{
if (op == "M.X + Y -> Y")
if (status.Trans())
op = string("Operation M'.X + Y -> Y not permitted:");
else if (status.ConjTrans())
op = string("Operation M*.X + Y -> Y not permitted:");
else
op = string("Operation M.X + Y -> Y not permitted:");
else
op = string("Operation ") + op + string(" not permitted:");
if (X.GetLength() != M.GetN(status) || Y.GetLength() != M.GetM(status))
throw WrongDim(function, op + string("\n M (") + to_str(&M)
+ string(") is a ") + to_str(M.GetM()) + string(" x ")
+ to_str(M.GetN()) + string(" matrix;\n X (")
+ to_str(&X) + string(") is vector of length ")
+ to_str(X.GetLength()) + string(";\n Y (")
+ to_str(&Y) + string(") is vector of length ")
+ to_str(Y.GetLength()) + string("."));
}
#ifdef SELDON_WITH_CBLAS
//! Checks the compatibility of the dimensions.
/*! Checks that M.X + Y -> Y is possible according to the dimensions of
the matrix M and the vectors X and Y. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param trans status of the matrix M, e.g. transposed.
\param M matrix.
\param X vector.
\param Y vector.
\param function (optional) function in which the compatibility is checked.
Default: "".
\param op (optional) operation to be performed on the vectors.
Default: "M.X + Y -> Y".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1,
class T2, class Storage2, class Allocator2>
void CheckDim(const enum CBLAS_TRANSPOSE trans,
const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
const Vector<T2, Storage2, Allocator2>& Y,
string function = "", string op = "M.X + Y -> Y")
{
SeldonTranspose status(trans);
if (op == "M.X + Y -> Y")
if (status.Trans())
op = string("Operation M'.X + Y -> Y not permitted:");
else if (status.ConjTrans())
op = string("Operation M*.X + Y -> Y not permitted:");
else
op = string("Operation M.X + Y -> Y not permitted:");
else
op = string("Operation ") + op + string(" not permitted:");
if (X.GetLength() != M.GetN(status) || Y.GetLength() != M.GetM(status))
throw WrongDim(function, op + string("\n M (") + to_str(&M)
+ string(") is a ") + to_str(M.GetM()) + string(" x ")
+ to_str(M.GetN()) + string(" matrix;\n X (")
+ to_str(&X) + string(") is vector of length ")
+ to_str(X.GetLength()) + string(";\n Y (")
+ to_str(&Y) + string(") is vector of length ")
+ to_str(Y.GetLength()) + string("."));
}
#endif
//! Checks the compatibility of the dimensions.
/*! Checks that M.X is possible according to the dimensions of
the matrix M and the vector X. If the dimensions are incompatible,
an exception is raised (a WrongDim object is thrown).
\param M matrix.
\param X vector.
\param function (optional) function in which the compatibility is checked.
Default: "".
\param op (optional) operation to be performed. Default: "M.X".
*/
template <class T0, class Prop0, class Storage0, class Allocator0,
class T1, class Storage1, class Allocator1>
void CheckDim(const Matrix<T0, Prop0, Storage0, Allocator0>& M,
const Vector<T1, Storage1, Allocator1>& X,
string function = "", string op = "M.X")
{
if (X.GetLength() != M.GetN())
throw WrongDim(function, string("Operation ") + op + " not permitted:"
+ string("\n M (") + to_str(&M) + string(") is a ")
+ to_str(M.GetM()) + string(" x ") + to_str(M.GetN())
+ string(" matrix;\n X (") + to_str(&X)
+ string(") is vector of length ")
+ to_str(X.GetLength()) + string("."));
}
// CHECKDIM //
//////////////
} // namespace Seldon.
#define SELDON_FUNCTIONS_MATVECT_CXX
#endif