netgen/libsrc/linalg/densemat.cpp
2024-11-25 17:25:40 +01:00

1387 lines
30 KiB
C++

#include <mystdlib.h>
#include <linalg.hpp>
namespace netgen
{
DenseMatrix :: DenseMatrix ()
{
data = NULL;
height = 0;
width = 0;
}
DenseMatrix :: DenseMatrix (int h, int w)
{
if (!w) w = h;
width = w;
height = h;
int hw = h*w;
if (hw)
data = new double[hw];
else
data = 0;
for (int i = 0 ; i < (hw); i++)
data[i] = 0;
}
/*
DenseMatrix :: DenseMatrix (int h, int w, const double * d)
: BaseMatrix (h, w)
{
int size = h * w;
int i;
if (size)
{
data = new double[size];
for (i = 0; i < size; i++)
data[i] = d[i];
}
else
data = NULL;
}
*/
DenseMatrix :: DenseMatrix (const DenseMatrix & m2)
{
data = NULL; height = width = 0;
SetSize (m2.Height(), m2.Width());
if (Height()*Width())
memcpy (data, m2.data, sizeof(double) * (Height() * Width()));
}
DenseMatrix :: ~DenseMatrix ()
{
delete [] data;
}
void DenseMatrix :: SetSize (int h, int w)
{
if (!w) w = h;
if (height == h && width == w)
return;
height = h;
width = w;
delete[] data;
if (h*w)
data = new double[h*w];
else
data = NULL;
}
/*
DenseMatrix & DenseMatrix :: operator= (const BaseMatrix & m2)
{
int i, j;
SetSize (m2.Height(), m2.Width());
if (data)
for (i = 1; i <= Height(); i++)
for (j = 1; j <= Width(); j++)
Set (i, j, m2(i, j));
else
(*myerr) << "DenseMatrix::Operator=: Matrix not allocated" << endl;
return *this;
}
*/
DenseMatrix & DenseMatrix :: operator= (const DenseMatrix & m2)
{
SetSize (m2.Height(), m2.Width());
if (data) memcpy (data, m2.data, sizeof(double) * m2.Height() * m2.Width());
return *this;
}
DenseMatrix & DenseMatrix :: operator+= (const DenseMatrix & m2)
{
int i;
double * p, * q;
if (Height() != m2.Height() || Width() != m2.Width())
{
(*myerr) << "DenseMatrix::Operator+=: Sizes don't fit" << endl;
return *this;
}
if (data)
{
p = data;
q = m2.data;
for (i = Width() * Height(); i > 0; i--)
{
*p += *q;
p++;
q++;
}
}
else
(*myerr) << "DenseMatrix::Operator+=: Matrix not allocated" << endl;
return *this;
}
DenseMatrix & DenseMatrix :: operator-= (const DenseMatrix & m2)
{
int i;
double * p, * q;
if (Height() != m2.Height() || Width() != m2.Width())
{
(*myerr) << "DenseMatrix::Operator-=: Sizes don't fit" << endl;
return *this;
}
if (data)
{
p = data;
q = m2.data;
for (i = Width() * Height(); i > 0; i--)
{
*p -= *q;
p++;
q++;
}
}
else
(*myerr) << "DenseMatrix::Operator-=: Matrix not allocated" << endl;
return *this;
}
DenseMatrix & DenseMatrix :: operator= (double v)
{
double * p = data;
if (data)
for (int i = width*height; i > 0; i--, p++)
*p = v;
return *this;
}
DenseMatrix & DenseMatrix :: operator*= (double v)
{
double * p = data;
if (data)
for (int i = width*height; i > 0; i--, p++)
*p *= v;
return *this;
}
double DenseMatrix :: Det () const
{
if (width != height)
{
(*myerr) << "DenseMatrix :: Det: width != height" << endl;
return 0;
}
switch (width)
{
case 1: return data[0];
case 2: return data[0] * data[3] - data[1] * data[2];
case 3: return data[0] * data[4] * data[8]
+ data[1] * data[5] * data[6]
+ data[2] * data[3] * data[7]
- data[0] * data[5] * data[7]
- data[1] * data[3] * data[8]
- data[2] * data[4] * data[6];
default:
{
(*myerr) << "Matrix :: Det: general size not implemented (size=" << width << ")" << endl;
return 0;
}
}
}
void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2)
{
double det;
if (m1.Width() != m1.Height())
{
(*myerr) << "CalcInverse: matrix not symmetric" << endl;
return;
}
if (m1.Width() != m2.Width() || m1.Height() != m2.Height())
{
(*myerr) << "CalcInverse: dim(m2) != dim(m1)" << endl;
return;
}
if (m1.Width() <= 3)
{
det = m1.Det();
if (det == 0)
{
(*myerr) << "CalcInverse: Matrix singular" << endl;
(*testout) << "CalcInverse: Matrix singular" << endl;
return;
}
det = 1.0 / det;
switch (m1.Width())
{
case 1:
{
m2(0,0) = det;
return;
}
case 2:
{
m2(0,0) = det * m1(3);
m2(1,1) = det * m1(0);
m2(0,1) = -det * m1(1);
m2(1,0) = - det * m1(2);
return;
}
case 3:
{
m2(0, 0) = det * (m1(4) * m1(8) - m1(5) * m1(7));
m2(1, 0) = -det * (m1(3) * m1(8) - m1(5) * m1(6));
m2(2, 0) = det * (m1(3) * m1(7) - m1(4) * m1(6));
m2(0, 1) = -det * (m1(1) * m1(8) - m1(2) * m1(7));
m2(1, 1) = det * (m1(0) * m1(8) - m1(2) * m1(6));
m2(2, 1) = -det * (m1(0) * m1(7) - m1(1) * m1(6));
m2(0, 2) = det * (m1(1) * m1(5) - m1(2) * m1(4));
m2(1, 2) = -det * (m1(0) * m1(5) - m1(2) * m1(3));
m2(2, 2) = det * (m1(0) * m1(4) - m1(1) * m1(3));
return;
}
}
}
else
{
int i, j, k, n;
n = m1.Height();
#ifdef CHOL
int dots = (n > 200);
// Cholesky
double x;
Vector p(n);
m2 = m1;
/*
m2.SetSymmetric();
if (!m2.Symmetric())
cerr << "m should be symmetric for Cholesky" << endl;
*/
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
m2.Elem(j, i) = m2.Get(i, j);
for (i = 1; i <= n; i++)
{
if (dots && i % 10 == 0)
(*mycout) << "." << flush;
for (j = i; j <= n; j++)
{
x = m2.Get(i, j);
const double * pik = &m2.Get(i, 1);
const double * pjk = &m2.Get(j, 1);
for (k = i-2; k >= 0; --k, ++pik, ++pjk)
x -= (*pik) * (*pjk);
// for (k = i-1; k >= 1; --k)
// x -= m2.Get(j, k) * m2.Get(i, k);
if (i == j)
{
if (x <= 0)
{
cerr << "Matrix indefinite 1" << endl;
return;
}
p.Elem(i) = 1 / sqrt(x);
}
else
{
m2.Elem(j, i) = x * p.Get(i);
}
}
}
for (i = 1; i <= n; i++)
m2.Elem(i, i) = 1 / p.Get(i);
// check: A = L L^t
// for (i = 1; i <= n; i++)
// for (j = 1; j <= n; j++)
// {
// x = 0;
// for (k = 1; k <= i && k <= j; k++)
// x += m2.Get(i, k) * m2.Get(j, k);
// (*testout) << "err " << i << "," << j << " = " << (m1.Get(i, j) - x) << endl;
// }
// calc L^{-1}, store upper triangle
// DenseMatrix hm(n);
// hm = m2;
for (i = 1; i <= n; i++)
{
if (dots && i % 10 == 0)
(*mycout) << "+" << flush;
for (j = i; j <= n; j++)
{
x = 0;
if (j == i) x = 1;
const double * pjk = &m2.Get(j, i);
const double * pik = &m2.Get(i, i);
for (k = i; k < j; k++, ++pjk, ++pik)
x -= *pik * *pjk;
// for (k = i; k < j; k++)
// x -= m2.Get(j, k) * m2.Get(i, k);
m2.Elem(i, j) = x / m2.Get(j, j);
}
}
// (*testout) << "check L^-1" << endl;
// for (i = 1; i <= n; i++)
// for (j = 1; j <= n; j++)
// {
// x = 0;
// for (k = j; k <= i; k++)
// x += hm.Get(i, k) * m2.Get(j, k);
// (*testout) << "i, j = " << i << "," << j << " x = " << x << endl;
// }
// calc A^-1 = L^-T * L^-1
for (i = 1; i <= n; i++)
{
if (dots && i % 10 == 0)
(*mycout) << "-" << flush;
for (j = 1; j <= i; j++)
{
x = 0;
k = i;
if (j > i) k = j;
const double * pik = &m2.Get(i, k);
const double * pjk = &m2.Get(j, k);
for ( ; k <= n; ++k, ++pik, ++pjk)
x += *pik * *pjk;
// for ( ; k <= n; k++)
// x += m2.Get(i, k) * m2.Get(j, k);
m2.Elem(i, j) = x;
}
}
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
m2.Elem(j, i) = m2.Get(i, j);
if (dots) (*mycout) << endl;
#endif
// Gauss - Jordan - algorithm
int r, hi;
double max, hr;
NgArray<int> p(n); // pivot-permutation
Vector hv(n);
m2 = m1;
/*
if (m2.Symmetric())
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
m2.Elem(j, i) = m2.Get(i, j);
*/
// Algorithm of Stoer, Einf. i. d. Num. Math, S 145
for (j = 1; j <= n; j++)
p.Set(j, j);
for (j = 1; j <= n; j++)
{
// pivot search
max = fabs(m2.Get(j, j));
r = j;
for (i = j+1; i <= n ;i++)
if (fabs (m2.Get(i, j)) > max)
{
r = i;
max = fabs (m2.Get(i, j));
}
if (max < 1e-20)
{
cerr << "Inverse matrix: matrix singular" << endl;
*testout << "Inverse matrix: matrix singular" << endl;
return;
}
r = j;
// exchange rows
if (r > j)
{
for (k = 1; k <= n; k++)
{
hr = m2.Get(j, k);
m2.Elem(j, k) = m2.Get(r, k);
m2.Elem(r, k) = hr;
}
hi = p.Get(j);
p.Elem(j) = p.Get(r);
p.Elem(r) = hi;
}
// transformation
hr = 1 / m2.Get(j, j);
for (i = 1; i <= n; i++)
m2.Elem(i, j) *= hr;
m2.Elem(j, j) = hr;
for (k = 1; k <= n; k++)
if (k != j)
{
for (i = 1; i <= n; i++)
if (i != j)
m2.Elem(i, k) -= m2.Elem(i, j) * m2.Elem(j, k);
m2.Elem(j, k) *= -hr;
}
}
// col exchange
for (i = 1; i <= n; i++)
{
for (k = 1; k <= n; k++)
hv(p.Get(k)-1) = m2.Get(i, k);
for (k = 1; k <= n; k++)
m2.Elem(i, k) = hv(k-1);
}
/*
if (m1.Symmetric())
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
m1.Elem(j, i) = m1.Get(i, j);
m2 = 0;
for (i = 1; i <= n; i++)
m2.Elem(i, i) = 1;
for (i = 1; i <= n; i++)
{
// (*mycout) << '.' << flush;
q = m1.Get(i, i);
for (k = 1; k <= n; k++)
{
m1.Elem(i, k) /= q;
m2.Elem(i, k) /= q;
}
for (j = i+1; j <= n; j++)
{
q = m1.Elem(j, i);
double * m1pi = &m1.Elem(i, i);
double * m1pj = &m1.Elem(j, i);
for (k = n; k >= i; --k, ++m1pi, ++m1pj)
*m1pj -= q * (*m1pi);
double * m2pi = &m2.Elem(i, 1);
double * m2pj = &m2.Elem(j, 1);
for (k = i; k > 0; --k, ++m2pi, ++m2pj)
*m2pj -= q * (*m2pi);
// for (k = 1; k <= n; k++)
// {
// m1.Elem(j, k) -= q * m1.Elem(i, k);
// m2.Elem(j, k) -= q * m2.Elem(i, k);
// }
}
}
for (i = n; i >= 1; i--)
{
// (*mycout) << "+" << flush;
for (j = 1; j < i; j++)
{
q = m1.Elem(j, i);
double * m2pi = &m2.Elem(i, 1);
double * m2pj = &m2.Elem(j, 1);
for (k = n; k > 0; --k, ++m2pi, ++m2pj)
*m2pj -= q * (*m2pi);
// for (k = 1; k <= n; k++)
// {
// m1.Elem(j, k) -= q * m1.Elem(i, k);
// m2.Elem(j, k) -= q * m2.Elem(i, k);
// }
}
}
if (m2.Symmetric())
{
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
m2.Elem(i, j) = m2.Elem(j, i);
}
*/
}
}
void CalcAAt (const DenseMatrix & a, DenseMatrix & m2)
{
int n1 = a.Height();
int n2 = a.Width();
int i, j, k;
double sum;
const double *p, *q, *p0;
if (m2.Height() != n1 || m2.Width() != n1)
{
(*myerr) << "CalcAAt: sizes don't fit" << endl;
return;
}
for (i = 1; i <= n1; i++)
{
sum = 0;
p = &a.ConstElem(i, 1);
for (k = 1; k <= n2; k++)
{
sum += *p * *p;
p++;
}
m2.Set(i, i, sum);
p0 = &a.ConstElem(i, 1);
q = a.data;
for (j = 1; j < i; j++)
{
sum = 0;
p = p0;
for (k = 1; k <= n2; k++)
{
sum += *p * *q;
p++;
q++;
}
m2.Set(i, j, sum);
m2.Set(j, i, sum);
}
}
}
void CalcAtA (const DenseMatrix & a, DenseMatrix & m2)
{
int n1 = a.Height();
int n2 = a.Width();
int i, j, k;
double sum;
if (m2.Height() != n2 || m2.Width() != n2)
{
(*myerr) << "CalcAtA: sizes don't fit" << endl;
return;
}
for (i = 1; i <= n2; i++)
for (j = 1; j <= n2; j++)
{
sum = 0;
for (k = 1; k <= n1; k++)
sum += a.Get(k, i) * a.Get(k, j);
m2.Elem(i, j) = sum;
}
}
void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
{
int n1 = a.Height();
int n2 = a.Width();
int n3 = b.Height();
int i, j, k;
double sum;
if (m2.Height() != n1 || m2.Width() != n3 || b.Width() != n2)
{
(*myerr) << "CalcABt: sizes don't fit" << endl;
return;
}
double * pm2 = &m2.Elem(1, 1);
const double * pa1 = &a.Get(1, 1);
for (i = 1; i <= n1; i++)
{
const double * pb = &b.Get(1, 1);
for (j = 1; j <= n3; j++)
{
sum = 0;
const double * pa = pa1;
for (k = 1; k <= n2; k++)
{
sum += *pa * *pb;
pa++; pb++;
}
*pm2 = sum;
pm2++;
}
pa1 += n2;
}
}
void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
{
int n1 = a.Height();
int n2 = a.Width();
int n3 = b.Width();
int i, j, k;
if (m2.Height() != n2 || m2.Width() != n3 || b.Height() != n1)
{
(*myerr) << "CalcAtB: sizes don't fit" << endl;
return;
}
for (i = 1; i <= n2 * n3; i++)
m2.data[i-1] = 0;
for (i = 1; i <= n1; i++)
for (j = 1; j <= n2; j++)
{
const double va = a.Get(i, j);
double * pm2 = &m2.Elem(j, 1);
const double * pb = &b.Get(i, 1);
for (k = 1; k <= n3; ++k, ++pm2, ++pb)
*pm2 += va * *pb;
// for (k = 1; k <= n3; k++)
// m2.Elem(j, k) += va * b.Get(i, k);
}
/*
for (i = 1; i <= n2; i++)
for (j = 1; j <= n3; j++)
{
sum = 0;
for (k = 1; k <= n1; k++)
sum += a.Get(k, i) * b.Get(k, j);
m2.Elem(i, j) = sum;
}
*/
}
DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2)
{
DenseMatrix temp (m1.Height(), m2.Width());
if (m1.Width() != m2.Height())
{
(*myerr) << "DenseMatrix :: operator*: Matrix Size does not fit" << endl;
}
else if (temp.Height() != m1.Height())
{
(*myerr) << "DenseMatrix :: operator*: temp not allocated" << endl;
}
else
{
Mult (m1, m2, temp);
}
return temp;
}
void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3)
{
double sum;
double *p1, *p1s, *p1sn, *p1snn, *p2, *p2s, *p2sn, *p3;
if (m1.Width() != m2.Height() || m1.Height() != m3.Height() ||
m2.Width() != m3.Width() )
{
(*myerr) << "DenseMatrix :: Mult: Matrix Size does not fit" << endl;
(*myerr) << "m1: " << m1.Height() << " x " << m1.Width() << endl;
(*myerr) << "m2: " << m2.Height() << " x " << m2.Width() << endl;
(*myerr) << "m3: " << m3.Height() << " x " << m3.Width() << endl;
return;
}
/*
else if (m1.Symmetric() || m2.Symmetric() || m3.Symmetric())
{
(*myerr) << "DenseMatrix :: Mult: not implemented for symmetric matrices" << endl;
return;
}
*/
else
{
// int i, j, k;
int n1 = m1.Height();
int n2 = m2.Width();
int n3 = m1.Width();
/*
for (i = n1 * n2-1; i >= 0; --i)
m3.data[i] = 0;
const double * pm1 = &m1.Get(1, 1);
for (i = 1; i <= n1; i++)
{
const double * pm2 = &m2.Get(1, 1);
double * pm3i = &m3.Elem(i, 1);
for (j = 1; j <= n3; j++)
{
const double vm1 = *pm1;
++pm1;
// const double vm1 = m1.Get(i, j);
double * pm3 = pm3i;
// const double * pm2 = &m2.Get(j, 1);
for (k = 0; k < n2; k++)
{
*pm3 += vm1 * *pm2;
++pm2;
++pm3;
}
// for (k = 1; k <= n2; k++)
// m3.Elem(i, k) += m1.Get(i, j) * m2.Get(j, k);
}
}
*/
/*
for (i = 1; i <= n1; i++)
for (j = 1; j <= n2; j++)
{
sum = 0;
for (k = 1; k <= n3; k++)
sum += m1.Get(i, k) * m2.Get(k, j);
m3.Set(i, j, sum);
}
*/
/*
for (i = 1; i <= n1; i++)
{
const double pm1i = &m1.Get(i, 1);
const double pm2j = &m2.Get(1, 1);
for (j = 1; j <= n2; j++)
{
double sum = 0;
const double * pm1 = pm1i;
const double * pm2 = pm2j;
pm2j++;
for (k = 1; k <= n3; k++)
{
sum += *pm1 * *pm2;
++pm1;
pm2 += n2;
}
m3.Set (i, j, sum);
}
}
*/
p3 = m3.data;
p1s = m1.data;
p2sn = m2.data + n2;
p1snn = p1s + n1 * n3;
while (p1s != p1snn)
{
p1sn = p1s + n3;
p2s = m2.data;
while (p2s != p2sn)
{
sum = 0;
p1 = p1s;
p2 = p2s;
p2s++;
while (p1 != p1sn)
{
sum += *p1 * *p2;
p1++;
p2 += n2;
}
*p3++ = sum;
}
p1s = p1sn;
}
}
}
DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2)
{
DenseMatrix temp (m1.Height(), m1.Width());
int i, j;
if (m1.Width() != m2.Width() || m1.Height() != m2.Height())
{
(*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl;
}
else if (temp.Height() != m1.Height())
{
(*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl;
}
else
{
for (i = 1; i <= m1.Height(); i++)
for (j = 1; j <= m1.Width(); j++)
{
temp.Set(i, j, m1.Get(i, j) + m2.Get(i, j));
}
}
return temp;
}
void Transpose (const DenseMatrix & m1, DenseMatrix & m2)
{
int w = m1.Width();
int h = m1.Height();
int i, j;
m2.SetSize (w, h);
double * pm2 = &m2.Elem(1, 1);
for (j = 1; j <= w; j++)
{
const double * pm1 = &m1.Get(1, j);
for (i = 1; i <= h; i++)
{
*pm2 = *pm1;
pm2 ++;
pm1 += w;
}
}
}
/*
void DenseMatrix :: Mult (const Vector & v, Vector & prod) const
{
double sum, val;
const double * mp, * sp;
double * dp;
// const Vector & v = bv.CastToVector();
// Vector & prod = bprod.CastToVector();
int n = Height();
int m = Width();
if (prod.Size() != n)
prod.SetSize (n);
#ifdef DEVELOP
if (!n)
{
cout << "DenseMatrix::Mult mheight = 0" << endl;
}
if (!m)
{
cout << "DenseMatrix::Mult mwidth = 0" << endl;
}
if (m != v.Size())
{
(*myerr) << "\nMatrix and Vector don't fit" << endl;
}
else if (Height() != prod.Size())
{
(*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
}
else
#endif
{
if (Symmetric())
{
int i, j;
for (i = 1; i <= n; i++)
{
sp = &v.Get(1);
dp = &prod.Elem(1);
mp = &Get(i, 1);
val = v.Get(i);
sum = Get(i, i) * val;
for (j = 1; j < i; ++j, ++mp, ++sp, ++dp)
{
sum += *mp * *sp;
*dp += val * *mp;
}
prod.Elem(i) = sum;
}
}
else
{
mp = data;
dp = &prod.Elem(1);
for (int i = 1; i <= n; i++)
{
sum = 0;
sp = &v.Get(1);
for (int j = 1; j <= m; j++)
{
// sum += Get(i,j) * v.Get(j);
sum += *mp * *sp;
mp++;
sp++;
}
// prod.Set (i, sum);
*dp = sum;
dp++;
}
}
}
}
*/
void DenseMatrix :: MultTrans (const Vector & v, Vector & prod) const
{
// const Vector & v = (const Vector&)bv; // .CastToVector();
// Vector & prod = (Vector & )bprod; // .CastToVector();
/*
if (Height() != v.Size())
{
(*myerr) << "\nMatrix and Vector don't fit" << endl;
}
else if (Width() != prod.Size())
{
(*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
}
else
*/
{
int i, j;
int w = Width(), h = Height();
if (prod.Size() != w)
prod.SetSize (w);
const double * pmat = &Get(1, 1);
const double * pv = &v(0);
prod = 0;
for (i = 1; i <= h; i++)
{
double val = *pv;
++pv;
double * pprod = &prod(0);
for (j = w-1; j >= 0; --j, ++pmat, ++pprod)
{
*pprod += val * *pmat;
}
}
/*
double sum;
for (i = 1; i <= Width(); i++)
{
sum = 0;
for (int j = 1; j <= Height(); j++)
sum += Get(j, i) * v.Get(j);
prod.Set (i, sum);
}
*/
}
}
void DenseMatrix :: Residuum (const Vector & x, const Vector & b,
Vector & res) const
{
double sum;
// const Vector & x = bx.CastToVector();
// const Vector & b = bb.CastToVector();
// Vector & res = bres.CastToVector();
res.SetSize (Height());
if (Width() != x.Size() || Height() != b.Size())
{
(*myerr) << "\nMatrix and Vector don't fit" << endl;
}
else if (Height() != res.Size())
{
(*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
}
else
{
int h = Height();
int w = Width();
const double * mp = &Get(1, 1);
for (int i = 1; i <= h; i++)
{
sum = b(i-1);
const double * xp = &x(0);
for (int j = 1; j <= w; ++j, ++mp, ++xp)
sum -= *mp * *xp;
res(i-1) = sum;
}
}
}
#ifdef ABC
double DenseMatrix :: EvaluateBilinearform (const Vector & hx) const
{
double sum = 0, hsum;
// const Vector & hx = x.CastToVector();
int i, j;
if (Width() != hx.Size() || Height() != hx.Size())
{
(*myerr) << "Matrix::EvaluateBilinearForm: sizes don't fit" << endl;
}
else
{
for (i = 1; i <= Height(); i++)
{
hsum = 0;
for (j = 1; j <= Height(); j++)
{
hsum += Get(i, j) * hx.Get(j);
}
sum += hsum * hx.Get(i);
}
}
// testout << "sum = " << sum << endl;
return sum;
}
void DenseMatrix :: MultElementMatrix (const NgArray<int> & pnum,
const Vector & hx, Vector & hy)
{
int i, j;
// const Vector & hx = x.CastToVector();
// Vector & hy = y.CastToVector();
if (Symmetric())
{
for (i = 1; i <= Height(); i++)
{
for (j = 1; j < i; j++)
{
hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
hy.Elem(pnum.Get(j)) += Get(i, j) * hx.Get(pnum.Get(i));
}
hy.Elem(pnum.Get(j)) += Get(i, i) * hx.Get(pnum.Get(i));
}
}
else
for (i = 1; i <= Height(); i++)
for (j = 1; j <= Width(); j++)
hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
}
void DenseMatrix :: MultTransElementMatrix (const NgArray<int> & pnum,
const Vector & hx, Vector & hy)
{
int i, j;
// const Vector & hx = x.CastToVector();
// Vector & hy = y.CastToVector();
if (Symmetric())
MultElementMatrix (pnum, hx, hy);
else
for (i = 1; i <= Height(); i++)
for (j = 1; j <= Width(); j++)
hy.Elem(pnum.Get(i)) += Get(j, i) * hx.Get(pnum.Get(j));
}
#endif
void DenseMatrix :: Solve (const Vector & v, Vector & sol) const
{
DenseMatrix temp (*this);
temp.SolveDestroy (v, sol);
}
void DenseMatrix :: SolveDestroy (const Vector & v, Vector & sol)
{
double q;
if (Width() != Height())
{
(*myerr) << "SolveDestroy: Matrix not square";
return;
}
if (Width() != v.Size())
{
(*myerr) << "SolveDestroy: Matrix and Vector don't fit";
return;
}
sol = v;
if (Height() != sol.Size())
{
(*myerr) << "SolveDestroy: Solution Vector not ok";
return;
}
if (0 /* Symmetric() */)
{
// Cholesky factorization
int i, j, k, n;
n = Height();
// Cholesky
double x;
Vector p(n);
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
Elem(j, i) = Get(i, j);
for (i = 1; i <= n; i++)
{
// (*mycout) << "." << flush;
for (j = i; j <= n; j++)
{
x = Get(i, j);
const double * pik = &Get(i, 1);
const double * pjk = &Get(j, 1);
for (k = i-2; k >= 0; --k, ++pik, ++pjk)
x -= (*pik) * (*pjk);
// for (k = i-1; k >= 1; --k)
// x -= Get(j, k) * Get(i, k);
if (i == j)
{
if (x <= 0)
{
cerr << "Matrix indefinite" << endl;
return;
}
p(i-1) = 1 / sqrt(x);
}
else
{
Elem(j, i) = x * p(i-1);
}
}
}
for (int i = 1; i <= n; i++)
Elem(i, i) = 1 / p(i-1);
// A = L L^t
// L stored in left-lower triangle
sol = v;
// Solve L sol = sol
for (int i = 1; i <= n; i++)
{
double val = sol(i-1);
const double * pij = &Get(i, 1);
const double * solj = &sol(0);
for (int j = 1; j < i; j++, ++pij, ++solj)
val -= *pij * *solj;
// for (j = 1; j < i; j++)
// val -= Get(i, j) * sol.Get(j);
sol(i-1) = val / Get(i, i);
}
// Solve L^t sol = sol
for (int i = n; i >= 1; i--)
{
double val = sol(i-1) / Get(i, i);
sol(i-1) = val;
double * solj = &sol(0);
const double * pij = &Get(i, 1);
for (j = 1; j < i; ++j, ++pij, ++solj)
*solj -= val * *pij;
// for (j = 1; j < i; j++)
// sol.Elem(j) -= Get(i, j) * val;
}
}
else
{
// (*mycout) << "gauss" << endl;
int n = Height();
for (int i = 1; i <= n; i++)
{
for (int j = i+1; j <= n; j++)
{
q = Get(j,i) / Get(i,i);
if (q)
{
const double * pik = &Get(i, i+1);
double * pjk = &Elem(j, i+1);
for (int k = i+1; k <= n; ++k, ++pik, ++pjk)
*pjk -= q * *pik;
// for (k = i+1; k <= Height(); k++)
// Elem(j, k) -= q * Get(i,k);
sol(j-1) -= q * sol(i-1);
}
}
}
for (int i = n; i >= 1; i--)
{
q = sol(i-1);
for (int j = i+1; j <= n; j++)
q -= Get(i,j) * sol(j-1);
sol(i-1) = q / Get(i,i);
}
}
}
/*
BaseMatrix * DenseMatrix :: Copy () const
{
return new DenseMatrix (*this);
}
*/
ostream & operator<< (ostream & ost, const DenseMatrix & m)
{
for (int i = 0; i < m.Height(); i++)
{
for (int j = 0; j < m.Width(); j++)
ost << m.Get(i+1,j+1) << " ";
ost << endl;
}
return ost;
}
}