1312 lines
29 KiB
C++
1312 lines
29 KiB
C++
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
|
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
|
// reserved. See file COPYRIGHT for details.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability see http://mfem.googlecode.com.
|
|
//
|
|
// MFEM 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) version 2.1 dated February 1999.
|
|
|
|
// Implementation of sparse matrix
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <math.h>
|
|
|
|
#include "linalg.hpp"
|
|
#include "../general/table.hpp"
|
|
|
|
SparseMatrix::SparseMatrix (int nrows, int ncols)
|
|
: Matrix (nrows)
|
|
{
|
|
I = NULL;
|
|
J = NULL;
|
|
A = NULL;
|
|
|
|
Rows = new RowNode *[nrows];
|
|
width = (ncols) ? (ncols) : (nrows);
|
|
for (int i = 0; i < nrows; i++)
|
|
Rows[i] = NULL;
|
|
}
|
|
|
|
int SparseMatrix::RowSize (int i)
|
|
{
|
|
if (I)
|
|
return I[i+1]-I[i];
|
|
|
|
int s = 0;
|
|
RowNode *row = Rows[i];
|
|
for ( ; row != NULL; row = row->Prev)
|
|
if (row -> Value != 0.0)
|
|
s++;
|
|
return s;
|
|
}
|
|
|
|
double& SparseMatrix::Elem (int i, int j)
|
|
{
|
|
return operator()(i,j);
|
|
}
|
|
|
|
const double& SparseMatrix::Elem (int i, int j) const
|
|
{
|
|
return operator()(i,j);
|
|
}
|
|
|
|
double& SparseMatrix::operator() (int i, int j)
|
|
{
|
|
int k, end;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( i>=size || i<0 || j>=width || j<0 )
|
|
mfem_error ("SparseMatrix::operator() #1");
|
|
#endif
|
|
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::operator() #2");
|
|
|
|
end = I[i+1];
|
|
for (k = I[i]; k < end; k++)
|
|
if (J[k] == j)
|
|
return A[k];
|
|
|
|
mfem_error ("SparseMatrix::operator() #3");
|
|
return A[0];
|
|
}
|
|
|
|
const double& SparseMatrix::operator() (int i, int j) const
|
|
{
|
|
int k, end;
|
|
static const double zero = 0.0;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( i>=size || i<0 || j>=width || j<0 )
|
|
mfem_error ("SparseMatrix::operator() const #1");
|
|
#endif
|
|
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::operator() const #2");
|
|
end = I[i+1];
|
|
for (k = I[i]; k < end; k++)
|
|
if (J[k] == j)
|
|
return A[k];
|
|
|
|
return zero;
|
|
}
|
|
|
|
void SparseMatrix::Mult (const Vector & x, Vector & y) const
|
|
{
|
|
y = 0.0;
|
|
AddMult (x, y);
|
|
}
|
|
|
|
void SparseMatrix::AddMult (const Vector & x, Vector & y, const double a) const
|
|
{
|
|
#ifdef MFEM_DEBUG
|
|
if (( width != x.Size() ) || ( size != y.Size() ))
|
|
mfem_error ("SparseMatrix::AddMult() #1");
|
|
#endif
|
|
|
|
int i, j, end;
|
|
double *Ap = A, *yp = y.GetData();
|
|
const double *xp = x.GetData();
|
|
|
|
if (Ap == NULL)
|
|
{
|
|
// The matrix is not finalized, but multiplication is still possible
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
RowNode *row = Rows[i];
|
|
double b = 0.0;
|
|
for ( ; row != NULL; row = row->Prev)
|
|
b += row->Value * xp[row->Column];
|
|
*yp += a * b;
|
|
yp++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int *Jp = J, *Ip = I;
|
|
|
|
j = *Ip;
|
|
if (a == 1.0)
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
double d;
|
|
d = 0.0;
|
|
Ip++;
|
|
end = (*Ip);
|
|
for( ; j < end; j++)
|
|
{
|
|
d += (*Ap) * xp[*Jp];
|
|
Ap++;
|
|
Jp++;
|
|
}
|
|
*yp += d;
|
|
yp++;
|
|
}
|
|
else
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
double d;
|
|
d = 0.0;
|
|
Ip++;
|
|
end = (*Ip);
|
|
for( ; j < end; j++)
|
|
{
|
|
d += (*Ap) * xp[*Jp];
|
|
Ap++;
|
|
Jp++;
|
|
}
|
|
*yp += a * d;
|
|
yp++;
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::MultTranspose (const Vector & x, Vector & y) const
|
|
{
|
|
y = 0.0;
|
|
AddMultTranspose (x, y);
|
|
}
|
|
|
|
void SparseMatrix::AddMultTranspose (const Vector & x, Vector & y,
|
|
const double a) const
|
|
{
|
|
#ifdef MFEM_DEBUG
|
|
if (( size != x.Size() ) || ( width != y.Size() ))
|
|
mfem_error ("SparseMatrix::AddMultTranspose() #1");
|
|
#endif
|
|
|
|
int i, j, end;
|
|
double *yp = y.GetData();
|
|
|
|
if (A == NULL)
|
|
{
|
|
// The matrix is not finalized, but multiplication is still possible
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
RowNode *row = Rows[i];
|
|
double b = a * x(i);
|
|
for ( ; row != NULL; row = row->Prev)
|
|
yp[row->Column] += row->Value * b;
|
|
}
|
|
return;
|
|
}
|
|
|
|
for(i=0; i<size; i++)
|
|
{
|
|
double xi = a * x(i);
|
|
end = I[i+1];
|
|
for(j=I[i]; j<end; j++)
|
|
{
|
|
yp[J[j]] += A[j]*xi;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::PartMult(
|
|
const Array<int> &rows, const Vector &x, Vector &y)
|
|
{
|
|
if (A)
|
|
{
|
|
for (int i = 0; i < rows.Size(); i++)
|
|
{
|
|
int r = rows[i];
|
|
int end = I[r+1];
|
|
double a = 0.0;
|
|
for (int j = I[r]; j < end; j++)
|
|
a += A[j] * x(J[j]);
|
|
y(r) = a;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mfem_error("SparseMatrix::PartMult");
|
|
}
|
|
}
|
|
|
|
double SparseMatrix::InnerProduct (const Vector &x, const Vector &y) const
|
|
{
|
|
double prod = 0.0;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
double a = 0.0;
|
|
if (A)
|
|
for (int j = I[i], end = I[i+1]; j < end; j++)
|
|
a += A[j] * x(J[j]);
|
|
else
|
|
for (RowNode *node_p = Rows[i]; node_p != NULL;
|
|
node_p = node_p -> Prev)
|
|
a += node_p -> Value * x(node_p -> Column);
|
|
prod += a * y(i);
|
|
}
|
|
|
|
return prod;
|
|
}
|
|
|
|
void SparseMatrix::Finalize (int skip_zeros)
|
|
{
|
|
int i, j, nr, nz;
|
|
RowNode *aux;
|
|
|
|
I = new int[size+1];
|
|
I[0] = 0;
|
|
for (i = 1; i <= size; i++)
|
|
{
|
|
nr = 0;
|
|
for (aux = Rows[i-1]; aux != NULL; aux = aux->Prev)
|
|
if (!skip_zeros || aux->Value != 0.0)
|
|
nr++;
|
|
I[i] = I[i-1] + nr;
|
|
}
|
|
nz = I[size];
|
|
J = new int[nz];
|
|
A = new double[nz];
|
|
for (j = i = 0; i < size; i++)
|
|
for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
|
|
if (!skip_zeros || aux->Value != 0.0)
|
|
{
|
|
J[j] = aux->Column;
|
|
A[j] = aux->Value;
|
|
j++;
|
|
}
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
NodesMem.Clear();
|
|
#else
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
RowNode *node_p = Rows[i];
|
|
while (node_p != NULL)
|
|
{
|
|
aux = node_p;
|
|
node_p = node_p->Prev;
|
|
delete aux;
|
|
}
|
|
}
|
|
#endif
|
|
delete [] Rows;
|
|
Rows = NULL;
|
|
}
|
|
|
|
double SparseMatrix::IsSymmetric() const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::IsSymmetric()");
|
|
|
|
int i, j;
|
|
double a, max;
|
|
|
|
max = 0.0;
|
|
for (i = 1; i < size; i++)
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
if (J[j] < i)
|
|
{
|
|
a = fabs ( A[j] - (*this)(J[j],i) );
|
|
if (max < a)
|
|
max = a;
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
void SparseMatrix::Symmetrize()
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Symmetrize()");
|
|
|
|
int i, j;
|
|
for (i = 1; i < size; i++)
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
if (J[j] < i)
|
|
{
|
|
A[j] += (*this)(J[j],i);
|
|
A[j] *= 0.5;
|
|
(*this)(J[j],i) = A[j];
|
|
}
|
|
}
|
|
|
|
int SparseMatrix::NumNonZeroElems() const
|
|
{
|
|
if (A != NULL) // matrix is finalized
|
|
return I[size];
|
|
mfem_error ("SparseMatrix::NumNonZeroElems");
|
|
return -1;
|
|
}
|
|
|
|
int SparseMatrix::CountSmallElems (double tol)
|
|
{
|
|
int i, counter = 0;
|
|
|
|
if (A)
|
|
{
|
|
int nz = I[size];
|
|
double *Ap = A;
|
|
|
|
for (i = 0; i < nz; i++)
|
|
if (fabs(Ap[i]) < tol)
|
|
counter++;
|
|
}
|
|
else
|
|
{
|
|
RowNode *aux;
|
|
|
|
for (i = 0; i < size; i++)
|
|
for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
|
|
if (fabs(aux -> Value) < tol)
|
|
counter++;
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
|
|
MatrixInverse * SparseMatrix::Inverse() const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void SparseMatrix::EliminateRow (int row, const double sol, Vector &rhs)
|
|
{
|
|
RowNode *aux;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( row >= size || row < 0 )
|
|
mfem_error ("SparseMatrix::EliminateRow () #1");
|
|
#endif
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::EliminateRow () #2");
|
|
|
|
for (aux = Rows[row]; aux != NULL; aux = aux->Prev)
|
|
{
|
|
rhs(aux->Column) -= sol * aux->Value;
|
|
aux->Value = 0.0;
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::EliminateRow (int row)
|
|
{
|
|
RowNode *aux;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( row >= size || row < 0 )
|
|
mfem_error ("SparseMatrix::EliminateRow () #1");
|
|
#endif
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::EliminateRow () #2");
|
|
|
|
for (aux = Rows[row]; aux != NULL; aux = aux->Prev)
|
|
aux->Value = 0.0;
|
|
}
|
|
|
|
void SparseMatrix::EliminateCol (int col)
|
|
{
|
|
RowNode *aux;
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::EliminateCol () #1");
|
|
|
|
for (int i = 0; i < size; i++)
|
|
for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
|
|
if (aux -> Column == col)
|
|
aux->Value = 0.0;
|
|
}
|
|
|
|
void SparseMatrix::EliminateCols (Array<int> &cols, Vector *x, Vector *b)
|
|
{
|
|
RowNode *aux;
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::EliminateCols () #1");
|
|
|
|
for (int i = 0; i < size; i++)
|
|
for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
|
|
if (cols[aux -> Column])
|
|
{
|
|
if (x && b)
|
|
(*b)(i) -= aux -> Value * (*x)(aux -> Column);
|
|
aux->Value = 0.0;
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::EliminateRowCol (int rc, const double sol, Vector &rhs,
|
|
int d)
|
|
{
|
|
int col;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( rc >= size || rc < 0 )
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #1");
|
|
#endif
|
|
|
|
if (Rows == NULL)
|
|
for (int j = I[rc]; j < I[rc+1]; j++)
|
|
if ((col = J[j]) == rc)
|
|
if (d)
|
|
{
|
|
rhs(rc) = A[j] * sol;
|
|
}
|
|
else
|
|
{
|
|
A[j] = 1.0;
|
|
rhs(rc) = sol;
|
|
}
|
|
else
|
|
{
|
|
A[j] = 0.0;
|
|
for (int k = I[col]; 1; k++)
|
|
if (k == I[col+1])
|
|
{
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #2");
|
|
}
|
|
else if (J[k] == rc)
|
|
{
|
|
rhs(col) -= sol * A[k];
|
|
A[k] = 0.0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
for (RowNode *aux = Rows[rc]; aux != NULL; aux = aux->Prev)
|
|
if ((col = aux->Column) == rc)
|
|
if (d)
|
|
{
|
|
rhs(rc) = aux->Value * sol;
|
|
}
|
|
else
|
|
{
|
|
aux->Value = 1.0;
|
|
rhs(rc) = sol;
|
|
}
|
|
else
|
|
{
|
|
aux->Value = 0.0;
|
|
for (RowNode *node = Rows[col]; 1; node = node->Prev)
|
|
if (node == NULL)
|
|
{
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #3");
|
|
}
|
|
else if (node->Column == rc)
|
|
{
|
|
rhs(col) -= sol * node->Value;
|
|
node->Value = 0.0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::EliminateRowCol (int rc, int d)
|
|
{
|
|
int col;
|
|
RowNode *aux, *node;
|
|
|
|
#ifdef MFEM_DEBUG
|
|
if ( rc >= size || rc < 0 )
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #1");
|
|
#endif
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #2");
|
|
|
|
for (aux = Rows[rc]; aux != NULL; aux = aux->Prev)
|
|
{
|
|
if ((col = aux->Column) == rc)
|
|
{
|
|
if (d == 0)
|
|
aux->Value = 1.0;
|
|
}
|
|
else
|
|
{
|
|
aux->Value = 0.0;
|
|
for (node = Rows[col]; 1; node = node->Prev)
|
|
if (node == NULL)
|
|
{
|
|
mfem_error ("SparseMatrix::EliminateRowCol () #3");
|
|
}
|
|
else if (node->Column == rc)
|
|
{
|
|
node->Value = 0.0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::EliminateRowCol (int rc, SparseMatrix &Ae, int d)
|
|
{
|
|
int col;
|
|
|
|
if (Rows)
|
|
{
|
|
RowNode *nd, *nd2;
|
|
for (nd = Rows[rc]; nd != NULL; nd = nd->Prev)
|
|
{
|
|
if ((col = nd->Column) == rc)
|
|
{
|
|
if (d == 0)
|
|
{
|
|
Ae.Add(rc, rc, nd->Value - 1.0);
|
|
nd->Value = 1.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Ae.Add(rc, col, nd->Value);
|
|
nd->Value = 0.0;
|
|
for (nd2 = Rows[col]; 1; nd2 = nd2->Prev)
|
|
{
|
|
if (nd2 == NULL)
|
|
{
|
|
mfem_error("SparseMatrix::EliminateRowCol");
|
|
}
|
|
else if (nd2->Column == rc)
|
|
{
|
|
Ae.Add(col, rc, nd2->Value);
|
|
nd2->Value = 0.0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mfem_error("SparseMatrix::EliminateRowCol");
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::SetDiagIdentity()
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
if (I[i+1] == I[i]+1 && fabs(A[I[i]]) < 1e-16)
|
|
A[I[i]] = 1.0;
|
|
}
|
|
|
|
void SparseMatrix::EliminateZeroRows()
|
|
{
|
|
int i, j;
|
|
double zero;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
zero = 0.0;
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
zero += fabs(A[j]);
|
|
if (zero < 1e-12) {
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
if (J[j] == i)
|
|
A[j] = 1.0;
|
|
else
|
|
A[j] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::Gauss_Seidel_forw(const Vector &x, Vector &y) const
|
|
{
|
|
int c, i, j, end, d, s = size, *Ip = I, *Jp = J;
|
|
double sum, *Ap = A, *yp = y.GetData();
|
|
const double *xp = x.GetData();
|
|
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Gauss_Seidel_forw ()");
|
|
|
|
j = Ip[0];
|
|
for(i=0; i<s; i++){
|
|
end = Ip[i+1];
|
|
sum = 0.0;
|
|
d = -1;
|
|
for( ; j<end ; j++)
|
|
if ((c = Jp[j]) == i)
|
|
d = j;
|
|
else
|
|
sum += Ap[j] * yp[c];
|
|
|
|
if (d >= 0 && Ap[d] != 0.0)
|
|
yp[i] = (xp[i] - sum) / Ap[d];
|
|
else
|
|
if (xp[i] == sum)
|
|
yp[i] = sum;
|
|
else
|
|
mfem_error ("SparseMatrix::Gauss_Seidel_forw (...) #2");
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::Gauss_Seidel_back(const Vector &x, Vector &y) const
|
|
{
|
|
int i, j, beg, c, d;
|
|
double sum, *Ap = A, *yp = y.GetData();
|
|
double *xp = x.GetData();
|
|
int *Ip = I, *Jp = J;
|
|
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Gauss_Seidel_back ()");
|
|
|
|
j=Ip[size]-1;
|
|
for(i=size-1; i >= 0; i--){
|
|
beg = Ip[i];
|
|
sum = 0.;
|
|
d = -1;
|
|
for( ; j>=beg; j--)
|
|
if ((c = Jp[j]) == i)
|
|
d = j;
|
|
else
|
|
sum += Ap[j] * yp[c];
|
|
|
|
if (d >= 0 && Ap[d] != 0.0)
|
|
yp[i] = (xp[i] - sum) / Ap[d];
|
|
else
|
|
if (xp[i] == sum)
|
|
yp[i] = sum;
|
|
else
|
|
mfem_error ("SparseMatrix::Gauss_Seidel_back (...) #2");
|
|
}
|
|
}
|
|
|
|
double SparseMatrix::GetJacobiScaling() const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::GetJacobiScaling()");
|
|
|
|
double sc = 1.0;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
int d = -1;
|
|
double norm = 0.0;
|
|
for (int j = I[i]; j < I[i+1]; j++)
|
|
{
|
|
if (J[j] == i)
|
|
d = j;
|
|
norm += fabs(A[j]);
|
|
}
|
|
if (d >= 0 && A[d] != 0.0)
|
|
{
|
|
double a = 1.8 * fabs(A[d]) / norm;
|
|
if (a < sc)
|
|
sc = a;
|
|
}
|
|
else
|
|
mfem_error("SparseMatrix::GetJacobiScaling() #2");
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
void SparseMatrix::Jacobi(const Vector &b, const Vector &x0, Vector &x1,
|
|
double sc) const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Jacobi(...)");
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
int d = -1;
|
|
double sum = b(i);
|
|
for (int j = I[i]; j < I[i+1]; j++)
|
|
{
|
|
if (J[j] == i)
|
|
d = j;
|
|
else
|
|
sum -= A[j] * x0(J[j]);
|
|
}
|
|
if (d >= 0 && A[d] != 0.0)
|
|
x1(i) = sc * (sum / A[d]) + (1.0 - sc) * x0(i);
|
|
else
|
|
mfem_error("SparseMatrix::Jacobi(...) #2");
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::Jacobi2(const Vector &b, const Vector &x0, Vector &x1,
|
|
double sc) const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Jacobi2(...)");
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
double resi = b(i), norm = 0.0;
|
|
for (int j = I[i]; j < I[i+1]; j++)
|
|
{
|
|
resi -= A[j] * x0(J[j]);
|
|
norm += fabs(A[j]);
|
|
}
|
|
if (norm > 0.0)
|
|
x1(i) = x0(i) + sc * resi / norm;
|
|
else
|
|
mfem_error("SparseMatrix::Jacobi2(...) #2");
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::AddSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
|
const DenseMatrix &subm, int skip_zeros)
|
|
{
|
|
int i, j, gi, gj, s, t;
|
|
double a;
|
|
|
|
for (i = 0; i < rows.Size(); i++)
|
|
{
|
|
if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::AddSubMatrix(...) #1");
|
|
#endif
|
|
for (j = 0; j < cols.Size(); j++)
|
|
{
|
|
if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::AddSubMatrix(...) #2");
|
|
#endif
|
|
a = subm(i, j);
|
|
if (skip_zeros && a == 0.0)
|
|
{
|
|
// if the element is zero do not assemble it unless this breaks
|
|
// the symmetric structure
|
|
if (&rows != &cols || subm(j, i) == 0.0)
|
|
continue;
|
|
}
|
|
if (t < 0) a = -a;
|
|
_Add_ (gi, gj, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::Set (const int i, const int j, const double A)
|
|
{
|
|
double a = A;
|
|
int gi, gj, s, t;
|
|
|
|
if ((gi=i) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::Set (...) #1");
|
|
#endif
|
|
if ((gj=j) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::Set (...) #2");
|
|
#endif
|
|
if (t < 0) a = -a;
|
|
_Set_ (gi, gj, a);
|
|
}
|
|
|
|
void SparseMatrix::Add (const int i, const int j, const double A)
|
|
{
|
|
int gi, gj, s, t;
|
|
double a = A;
|
|
|
|
if ((gi=i) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::Add (...) #1");
|
|
#endif
|
|
if ((gj=j) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::Add (...) #2");
|
|
#endif
|
|
if (t < 0) a = -a;
|
|
_Add_ (gi, gj, a);
|
|
}
|
|
|
|
void SparseMatrix::SetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
|
const DenseMatrix &subm, int skip_zeros)
|
|
{
|
|
int i, j, gi, gj, s, t;
|
|
double a;
|
|
|
|
for (i = 0; i < rows.Size(); i++)
|
|
{
|
|
if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::SetSubMatrix(...) #1");
|
|
#endif
|
|
for (j = 0; j < cols.Size(); j++)
|
|
{
|
|
a = subm(i, j);
|
|
if (skip_zeros && a == 0.0)
|
|
continue;
|
|
if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::SetSubMatrix(...) #2");
|
|
#endif
|
|
if (t < 0) a = -a;
|
|
_Set_ (gi, gj, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::SetSubMatrixTranspose(const Array<int> &rows,
|
|
const Array<int> &cols,
|
|
const DenseMatrix &subm,
|
|
int skip_zeros)
|
|
{
|
|
int i, j, gi, gj, s, t;
|
|
double a;
|
|
|
|
for (i = 0; i < rows.Size(); i++)
|
|
{
|
|
if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::SetSubMatrixTranspose (...) #1");
|
|
#endif
|
|
for (j = 0; j < cols.Size(); j++)
|
|
{
|
|
a = subm(j, i);
|
|
if (skip_zeros && a == 0.0)
|
|
continue;
|
|
if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::SetSubMatrixTranspose (...) #2");
|
|
#endif
|
|
if (t < 0) a = -a;
|
|
_Set_ (gi, gj, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::GetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
|
DenseMatrix &subm)
|
|
{
|
|
int i, j, gi, gj, s, t;
|
|
RowNode *aux;
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::GetSubMatrix(...) #0");
|
|
|
|
for (i = 0; i < rows.Size(); i++)
|
|
{
|
|
if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::GetSubMatrix(...) #1");
|
|
#endif
|
|
for (j = 0; j < cols.Size(); j++)
|
|
{
|
|
if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::GetSubMatrix(...) #2");
|
|
#endif
|
|
for (aux = Rows[gi]; 1; aux = aux->Prev)
|
|
if (aux == NULL)
|
|
{
|
|
subm(i, j) = 0.0;
|
|
break;
|
|
}
|
|
else if (aux->Column == gj)
|
|
{
|
|
subm(i, j) = (t < 0) ? (-aux->Value) : (aux->Value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::AddRow (const int row, const Array<int> &cols,
|
|
const Vector &srow)
|
|
{
|
|
int j, gi, gj, s, t;
|
|
double a;
|
|
|
|
if (Rows == NULL)
|
|
mfem_error ("SparseMatrix::AddRow(...) #0");
|
|
|
|
if ((gi=row) < 0) gi = -1-gi, s = -1; else s = 1;
|
|
#ifdef MFEM_DEBUG
|
|
if (gi >= size)
|
|
mfem_error ("SparseMatrix::AddRow(...) #1");
|
|
#endif
|
|
for (j = 0; j < cols.Size(); j++)
|
|
{
|
|
if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s;
|
|
#ifdef MFEM_DEBUG
|
|
if (gj >= width)
|
|
mfem_error ("SparseMatrix::AddRow(...) #2");
|
|
#endif
|
|
a = srow(j);
|
|
if (a == 0.0)
|
|
continue;
|
|
if (t < 0) a = -a;
|
|
_Add_ (gi, gj, a);
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::ScaleRow (const int row, const double scale)
|
|
{
|
|
int i;
|
|
|
|
if ((i=row) < 0)
|
|
i = -1-i;
|
|
if (Rows != NULL)
|
|
{
|
|
RowNode *aux;
|
|
|
|
for (aux = Rows[i]; aux != NULL; aux = aux -> Prev)
|
|
aux -> Value *= scale;
|
|
}
|
|
else
|
|
{
|
|
int j, end = I[i+1];
|
|
|
|
for (j = I[i]; j < end; j++)
|
|
A[j] *= scale;
|
|
}
|
|
}
|
|
|
|
SparseMatrix & SparseMatrix::operator+= (SparseMatrix &B)
|
|
{
|
|
int i;
|
|
RowNode *aux;
|
|
|
|
if (Rows == NULL || B.Rows == NULL)
|
|
mfem_error ("SparseMatrix::operator+=(...) #0");
|
|
#ifdef MFEM_DEBUG
|
|
if (size != B.size || width != B.width)
|
|
mfem_error ("SparseMatrix::operator+=(...) #1");
|
|
#endif
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
for (aux = B.Rows[i]; aux != NULL; aux = aux->Prev)
|
|
{
|
|
_Add_ (i, aux->Column, aux->Value);
|
|
}
|
|
}
|
|
|
|
return (*this);
|
|
}
|
|
|
|
SparseMatrix & SparseMatrix::operator= (double a)
|
|
{
|
|
if (Rows == NULL)
|
|
for (int i = 0, nnz = I[size]; i < nnz; i++)
|
|
A[i] = a;
|
|
else
|
|
for (int i = 0; i < size; i++)
|
|
for (RowNode *node_p = Rows[i]; node_p != NULL;
|
|
node_p = node_p -> Prev)
|
|
node_p -> Value = a;
|
|
|
|
return (*this);
|
|
}
|
|
|
|
void SparseMatrix::Print(ostream & out, int _width) const
|
|
{
|
|
int i, j;
|
|
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::Print()");
|
|
|
|
out << setiosflags(ios::scientific | ios::showpos);
|
|
for(i = 0; i < size; i++) {
|
|
out << "[row " << i << "]\n";
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
{
|
|
out << "(" << setw(3) << J[j] << ","<< A[j] << ") ";
|
|
if ( !((j+1-I[i]) % _width) )
|
|
out << endl;
|
|
}
|
|
out << endl;
|
|
}
|
|
out << endl;
|
|
}
|
|
|
|
void SparseMatrix::PrintMatlab(ostream & out) const
|
|
{
|
|
int i, j;
|
|
ios::fmtflags old_fmt = out.setf(ios::scientific);
|
|
int old_prec = out.precision(14);
|
|
|
|
for(i = 0; i < size; i++)
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
out << i+1 << " " << J[j]+1 << " " << A[j] << endl;
|
|
out.precision(old_prec);
|
|
out.setf(old_fmt);
|
|
}
|
|
|
|
void SparseMatrix::PrintMM(ostream & out) const
|
|
{
|
|
int i, j;
|
|
ios::fmtflags old_fmt = out.setf(ios::scientific);
|
|
int old_prec = out.precision(14);
|
|
|
|
out << "%%MatrixMarket matrix coordinate real general" << endl
|
|
<< "% Generated by AggieFEM" << endl;
|
|
|
|
out << size << " " << width << " " << NumNonZeroElems() << endl;
|
|
for(i = 0; i < size; i++)
|
|
for (j = I[i]; j < I[i+1]; j++)
|
|
out << i+1 << " " << J[j]+1 << " " << A[j] << endl;
|
|
out.precision(old_prec);
|
|
out.setf(old_fmt);
|
|
}
|
|
|
|
void SparseMatrix::PrintCSR(ostream & out) const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::PrintCSR()");
|
|
|
|
int i;
|
|
ios::fmtflags old_fmt = out.setf(ios::scientific);
|
|
int old_prec = out.precision(14);
|
|
|
|
out << size << '\n'; // number of rows
|
|
|
|
for (i = 0; i <= size; i++)
|
|
out << I[i]+1 << '\n';
|
|
|
|
for (i = 0; i < I[size]; i++)
|
|
out << J[i]+1 << '\n';
|
|
|
|
for (i = 0; i < I[size]; i++)
|
|
out << A[i] << '\n';
|
|
|
|
out.precision(old_prec);
|
|
out.setf(old_fmt);
|
|
}
|
|
|
|
void SparseMatrix::PrintCSR2(ostream & out) const
|
|
{
|
|
if (A == NULL)
|
|
mfem_error ("SparseMatrix::PrintCSR2()");
|
|
|
|
int i;
|
|
ios::fmtflags old_fmt = out.setf(ios::scientific);
|
|
int old_prec = out.precision(14);
|
|
|
|
out << size << '\n'; // number of rows
|
|
out << width << '\n'; // number of columns
|
|
|
|
for (i = 0; i <= size; i++)
|
|
out << I[i] << '\n';
|
|
|
|
for (i = 0; i < I[size]; i++)
|
|
out << J[i] << '\n';
|
|
|
|
for (i = 0; i < I[size]; i++)
|
|
out << A[i] << '\n';
|
|
|
|
out.precision(old_prec);
|
|
out.setf(old_fmt);
|
|
}
|
|
|
|
SparseMatrix::~SparseMatrix ()
|
|
{
|
|
if (Rows != NULL)
|
|
{
|
|
#ifdef MFEM_USE_MEMALLOC
|
|
// NodesMem.Clear(); // this is done implicitly
|
|
#else
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
RowNode *aux, *node_p = Rows[i];
|
|
while (node_p != NULL)
|
|
{
|
|
aux = node_p;
|
|
node_p = node_p->Prev;
|
|
delete aux;
|
|
}
|
|
}
|
|
#endif
|
|
delete [] Rows;
|
|
}
|
|
if (A != NULL)
|
|
{
|
|
delete [] I;
|
|
delete [] J;
|
|
delete [] A;
|
|
}
|
|
}
|
|
|
|
void SparseMatrixFunction (SparseMatrix & S, double (*f)(double))
|
|
{
|
|
int n = S.NumNonZeroElems();
|
|
double * s = S.GetData();
|
|
|
|
for (int i = 0; i < n; i++)
|
|
s[i] = f(s[i]);
|
|
}
|
|
|
|
SparseMatrix *Transpose (SparseMatrix &A)
|
|
{
|
|
int i, j, end;
|
|
int m, n, nnz, *A_i, *A_j, *At_i, *At_j;
|
|
double *A_data, *At_data;
|
|
|
|
m = A.Size(); // number of rows of A
|
|
n = A.Width(); // number of columns of A
|
|
nnz = A.NumNonZeroElems();
|
|
A_i = A.GetI();
|
|
A_j = A.GetJ();
|
|
A_data = A.GetData();
|
|
|
|
At_i = new int[n+1];
|
|
At_j = new int[nnz];
|
|
At_data = new double[nnz];
|
|
|
|
for (i = 0; i <= n; i++)
|
|
At_i[i] = 0;
|
|
for (i = 0; i < nnz; i++)
|
|
At_i[A_j[i]+1]++;
|
|
for (i = 1; i < n; i++)
|
|
At_i[i+1] += At_i[i];
|
|
|
|
for (i = j = 0; i < m; i++)
|
|
{
|
|
end = A_i[i+1];
|
|
for ( ; j < end; j++)
|
|
{
|
|
At_j[At_i[A_j[j]]] = i;
|
|
At_data[At_i[A_j[j]]] = A_data[j];
|
|
At_i[A_j[j]]++;
|
|
}
|
|
}
|
|
|
|
for (i = n; i > 0; i--)
|
|
At_i[i] = At_i[i-1];
|
|
At_i[0] = 0;
|
|
|
|
return new SparseMatrix (At_i, At_j, At_data, n, m);
|
|
}
|
|
|
|
SparseMatrix *Mult (SparseMatrix &A, SparseMatrix &B,
|
|
SparseMatrix *OAB)
|
|
{
|
|
int nrowsA, ncolsA, nrowsB, ncolsB;
|
|
int *A_i, *A_j, *B_i, *B_j, *C_i, *C_j, *B_marker;
|
|
double *A_data, *B_data, *C_data;
|
|
int ia, ib, ic, ja, jb, num_nonzeros;
|
|
int row_start, counter;
|
|
double a_entry, b_entry;
|
|
SparseMatrix *C;
|
|
|
|
nrowsA = A.Size();
|
|
ncolsA = A.Width();
|
|
nrowsB = B.Size();
|
|
ncolsB = B.Width();
|
|
|
|
if (ncolsA != nrowsB)
|
|
mfem_error ("Sparse matrix multiplication, Mult (...) #1");
|
|
|
|
A_i = A.GetI();
|
|
A_j = A.GetJ();
|
|
A_data = A.GetData();
|
|
B_i = B.GetI();
|
|
B_j = B.GetJ();
|
|
B_data = B.GetData();
|
|
|
|
B_marker = new int[ncolsB];
|
|
|
|
for (ib = 0; ib < ncolsB; ib++)
|
|
B_marker[ib] = -1;
|
|
|
|
if (OAB == NULL)
|
|
{
|
|
C_i = new int[nrowsA+1];
|
|
|
|
C_i[0] = num_nonzeros = 0;
|
|
for (ic = 0; ic < nrowsA; ic++)
|
|
{
|
|
for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
|
|
{
|
|
ja = A_j[ia];
|
|
for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
|
|
{
|
|
jb = B_j[ib];
|
|
if (B_marker[jb] != ic)
|
|
{
|
|
B_marker[jb] = ic;
|
|
num_nonzeros++;
|
|
}
|
|
}
|
|
}
|
|
C_i[ic+1] = num_nonzeros;
|
|
}
|
|
|
|
C_j = new int[num_nonzeros];
|
|
C_data = new double[num_nonzeros];
|
|
|
|
C = new SparseMatrix (C_i, C_j, C_data, nrowsA, ncolsB);
|
|
|
|
for (ib = 0; ib < ncolsB; ib++)
|
|
B_marker[ib] = -1;
|
|
}
|
|
else
|
|
{
|
|
C = OAB;
|
|
|
|
if (nrowsA != C -> Size() || ncolsB != C -> Width())
|
|
mfem_error ("Sparse matrix multiplication, Mult (...) #2");
|
|
|
|
C_i = C -> GetI();
|
|
C_j = C -> GetJ();
|
|
C_data = C -> GetData();
|
|
}
|
|
|
|
counter = 0;
|
|
for (ic = 0; ic < nrowsA; ic++)
|
|
{
|
|
// row_start = C_i[ic];
|
|
row_start = counter;
|
|
for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
|
|
{
|
|
ja = A_j[ia];
|
|
a_entry = A_data[ia];
|
|
for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
|
|
{
|
|
jb = B_j[ib];
|
|
b_entry = B_data[ib];
|
|
if (B_marker[jb] < row_start)
|
|
{
|
|
B_marker[jb] = counter;
|
|
if (OAB == NULL)
|
|
C_j[counter] = jb;
|
|
C_data[counter] = a_entry*b_entry;
|
|
counter++;
|
|
}
|
|
else
|
|
C_data[B_marker[jb]] += a_entry*b_entry;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OAB != NULL && counter != OAB -> NumNonZeroElems())
|
|
mfem_error ("Sparse matrix multiplication, Mult (...) #3");
|
|
|
|
delete [] B_marker;
|
|
|
|
return C;
|
|
}
|
|
|
|
SparseMatrix *RAP (SparseMatrix &A, SparseMatrix &R,
|
|
SparseMatrix *ORAP)
|
|
{
|
|
SparseMatrix *P = Transpose (R);
|
|
SparseMatrix *AP = Mult (A, *P);
|
|
delete P;
|
|
SparseMatrix *_RAP = Mult (R, *AP, ORAP);
|
|
delete AP;
|
|
return _RAP;
|
|
}
|
|
|
|
SparseMatrix *Mult_AtDA (SparseMatrix &A, Vector &D,
|
|
SparseMatrix *OAtDA)
|
|
{
|
|
int i, At_nnz, *At_j;
|
|
double *At_data;
|
|
|
|
SparseMatrix *At = Transpose (A);
|
|
At_nnz = At -> NumNonZeroElems();
|
|
At_j = At -> GetJ();
|
|
At_data = At -> GetData();
|
|
for (i = 0; i < At_nnz; i++)
|
|
At_data[i] *= D(At_j[i]);
|
|
SparseMatrix *AtDA = Mult (*At, A, OAtDA);
|
|
delete At;
|
|
return AtDA;
|
|
}
|