15 #include "../general/forall.hpp"
16 #include "../general/table.hpp"
17 #include "../general/sort_pairs.hpp"
26 #if defined(MFEM_USE_CUDA)
27 #define MFEM_cu_or_hip(stub) cu##stub
28 #define MFEM_Cu_or_Hip(stub) Cu##stub
29 #define MFEM_CU_or_HIP(stub) CU##stub
30 #define MFEM_CUDA_or_HIP(stub) CUDA##stub
32 #if CUSPARSE_VERSION >= 11400
33 #define MFEM_GPUSPARSE_ALG CUSPARSE_SPMV_CSR_ALG1
34 #else // CUSPARSE_VERSION >= 11400
35 #define MFEM_GPUSPARSE_ALG CUSPARSE_CSRMV_ALG1
36 #endif // CUSPARSE_VERSION >= 11400
38 #elif defined(MFEM_USE_HIP)
39 #define MFEM_cu_or_hip(stub) hip##stub
40 #define MFEM_Cu_or_Hip(stub) Hip##stub
41 #define MFEM_CU_or_HIP(stub) HIP##stub
42 #define MFEM_CUDA_or_HIP(stub) HIP##stub
45 #define MFEM_GPUSPARSE_ALG HIPSPARSE_CSRMV_ALG1
46 #endif // defined(MFEM_USE_CUDA)
53 #ifdef MFEM_USE_CUDA_OR_HIP
57 MFEM_cu_or_hip(sparseHandle_t) SparseMatrix::handle =
nullptr;
59 size_t SparseMatrix::bufferSize = 0;
60 void * SparseMatrix::dBuffer =
nullptr;
61 #endif // MFEM_USE_CUDA_OR_HIP
66 #ifdef MFEM_USE_CUDA_OR_HIP
69 if (!handle) { MFEM_cu_or_hip(sparseCreate)(&handle); }
77 #endif // MFEM_USE_CUDA_OR_HIP
82 #ifdef MFEM_USE_CUDA_OR_HIP
85 #if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
86 MFEM_cu_or_hip(sparseDestroySpMat)(matA_descr);
87 MFEM_cu_or_hip(sparseDestroyDnVec)(vecX_descr);
88 MFEM_cu_or_hip(sparseDestroyDnVec)(vecY_descr);
90 cusparseDestroyMatDescr(matA_descr);
91 #endif // CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
94 #endif // MFEM_USE_CUDA_OR_HIP
99 Rows(new RowNode *[nrows]),
111 for (
int i = 0; i < nrows; i++)
116 #ifdef MFEM_USE_MEMALLOC
133 A.
Wrap(data,
I[height],
true);
135 #ifdef MFEM_USE_MEMALLOC
143 bool ownij,
bool owna,
bool issorted)
154 #ifdef MFEM_USE_MEMALLOC
160 A.
Wrap(data,
I[height], owna);
166 for (
int ii=0; ii<nnz; ++ii)
183 #ifdef MFEM_USE_MEMALLOC
187 J.
New(nrows * rowsize);
188 A.
New(nrows * rowsize);
190 for (
int i = 0; i <= nrows; i++)
223 #ifdef MFEM_USE_MEMALLOC
229 #ifdef MFEM_USE_MEMALLOC
233 for (
int i = 0; i <
height; i++)
235 RowNode **node_pp = &
Rows[i];
236 for (RowNode *node_p = mat.
Rows[i]; node_p; node_p = node_p->Prev)
238 #ifdef MFEM_USE_MEMALLOC
241 RowNode *new_node_p =
new RowNode;
243 new_node_p->Value = node_p->Value;
244 new_node_p->Column = node_p->Column;
245 *node_pp = new_node_p;
246 node_pp = &new_node_p->Prev;
274 #ifdef MFEM_USE_MEMALLOC
281 for (
int i = 0; i <=
height; i++)
286 for (
int r=0; r<
height; r++)
307 MFEM_ASSERT(master.
Finalized(),
"'master' must be finalized");
328 #ifdef MFEM_USE_MEMALLOC
346 return I[gi+1]-
I[gi];
350 RowNode *row =
Rows[gi];
351 for ( ; row != NULL; row = row->Prev)
352 if (row->Value != 0.0)
365 for (
int i=0; i <
height; ++i)
367 rowSize =
I[i+1]-
I[i];
368 max_row_size = (max_row_size > rowSize) ? max_row_size : rowSize;
373 for (
int i=0; i <
height; ++i)
376 max_row_size = (max_row_size > rowSize) ? max_row_size : rowSize;
385 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
392 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
399 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
406 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
413 if (newWidth ==
width)
418 else if (newWidth == -1)
424 else if (newWidth >
width)
435 ColPtrJ =
static_cast<int *
>(NULL);
443 "The new width needs to be bigger or equal to the actual width");
451 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
463 for (
int j = 0, i = 0; i <
height; i++)
467 for (
int k = 0; k < row.
Size(); k++)
473 for (
int k = 0; k < row.
Size(); k++, j++)
484 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
486 for (
int row = 0, end = 0; row <
height; row++)
490 for (j = start;
true; j++)
492 MFEM_VERIFY(j < end,
"diagonal entry not found in row = " << row);
493 if (
J[j] == row) {
break; }
495 const double diag =
A[j];
496 for ( ; j > start; j--)
518 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
519 "Trying to access element outside of the matrix. "
520 <<
"height = " <<
height <<
", "
521 <<
"width = " <<
width <<
", "
522 <<
"i = " << i <<
", "
525 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
527 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
535 MFEM_ABORT(
"Did not find i = " << i <<
", j = " << j <<
" in matrix.");
541 static const double zero = 0.0;
543 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
544 "Trying to access element outside of the matrix. "
545 <<
"height = " <<
height <<
", "
546 <<
"width = " <<
width <<
", "
547 <<
"i = " << i <<
", "
552 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
562 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
564 if (node_p->Column == j)
566 return node_p->Value;
576 MFEM_VERIFY(
height ==
width,
"Matrix must be square, not height = "
578 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
582 const auto II = this->
ReadI();
583 const auto JJ = this->
ReadJ();
589 const int begin = II[i];
590 const int end = II[i+1];
592 for (j = begin; j < end; j++)
610 int num_rows = this->
Height();
611 int num_cols = this->
Width();
626 for (
int r=0; r<
height; r++)
631 for (
int cj=0; cj<this->
RowSize(r); cj++)
633 B(r, col[cj]) = val[cj];
647 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
648 <<
") must match matrix width (" <<
width <<
")");
649 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
650 <<
") must match matrix height (" <<
height <<
")");
658 for (
int i = 0; i <
height; i++)
660 RowNode *row =
Rows[i];
662 for ( ; row != NULL; row = row->Prev)
664 b += row->Value * xp[row->Column];
672 #ifndef MFEM_USE_LEGACY_OPENMP
675 auto d_I =
Read(
I, height+1);
676 auto d_J =
Read(
J, nnz);
677 auto d_A =
Read(
A, nnz);
682 if (nnz == 0) {
return;}
685 #ifdef MFEM_USE_CUDA_OR_HIP
687 const double beta = 1.0;
692 #if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
694 MFEM_cu_or_hip(sparseCreateCsr)(
698 const_cast<int *
>(d_I),
699 const_cast<int *>(d_J),
700 const_cast<double *
>(d_A),
701 MFEM_CU_or_HIP(SPARSE_INDEX_32I),
702 MFEM_CU_or_HIP(SPARSE_INDEX_32I),
703 MFEM_CU_or_HIP(SPARSE_INDEX_BASE_ZERO),
704 MFEM_CUDA_or_HIP(_R_64F));
707 MFEM_cu_or_hip(sparseCreateDnVec)(&
vecX_descr,
709 const_cast<double *
>(d_x),
710 MFEM_CUDA_or_HIP(_R_64F));
712 MFEM_CUDA_or_HIP(_R_64F));
715 cusparseSetMatIndexBase(
matA_descr, CUSPARSE_INDEX_BASE_ZERO);
716 cusparseSetMatType(
matA_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
717 #endif // CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
721 size_t newBufferSize = 0;
723 MFEM_cu_or_hip(sparseSpMV_bufferSize)(
725 MFEM_CU_or_HIP(SPARSE_OPERATION_NON_TRANSPOSE),
731 MFEM_CUDA_or_HIP(_R_64F),
736 if (newBufferSize > bufferSize)
738 bufferSize = newBufferSize;
743 #if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
745 MFEM_cu_or_hip(sparseDnVecSetValues)(
vecX_descr,
746 const_cast<double *
>(d_x));
747 MFEM_cu_or_hip(sparseDnVecSetValues)(
vecY_descr, d_y);
750 MFEM_cu_or_hip(sparseSpMV)(
752 MFEM_CU_or_HIP(SPARSE_OPERATION_NON_TRANSPOSE),
758 MFEM_CUDA_or_HIP(_R_64F),
763 CUSPARSE_OPERATION_NON_TRANSPOSE,
769 const_cast<double *
>(d_A),
770 const_cast<int *>(d_I),
771 const_cast<int *
>(d_J),
772 const_cast<double *>(d_x),
775 #endif // CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
776 #endif // MFEM_USE_CUDA_OR_HIP
781 MFEM_FORALL(i, height,
784 const int end = d_I[i+1];
785 for (
int j = d_I[i]; j < end; j++)
787 d += d_A[j] * d_x[d_J[j]];
794 #else // MFEM_USE_LEGACY_OPENMP
795 const double *Ap =
A, *xp = x.
GetData();
797 const int *Jp =
J, *Ip =
I;
799 #pragma omp parallel for
800 for (
int i = 0; i <
height; i++)
803 const int end = Ip[i+1];
804 for (
int j = Ip[i]; j < end; j++)
806 d += Ap[j] * xp[Jp[j]];
810 #endif // MFEM_USE_LEGACY_OPENMP
821 const double a)
const
824 <<
") must match matrix height (" <<
height <<
")");
825 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
826 <<
") must match matrix width (" <<
width <<
")");
833 for (
int i = 0; i <
height; i++)
835 RowNode *row =
Rows[i];
836 double b = a * xp[i];
837 for ( ; row != NULL; row = row->Prev)
839 yp[row->Column] += row->Value *
b;
852 "this backend is not enabled; see EnsureMultTranspose() for "
854 for (
int i = 0; i <
height; i++)
856 const double xi = a * x[i];
857 const int end =
I[i+1];
858 for (
int j =
I[i]; j < end; j++)
892 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
894 const int n = rows.
Size();
896 auto d_rows = rows.
Read();
898 auto d_J =
Read(
J, nnz);
899 auto d_A =
Read(
A, nnz);
901 auto d_y = y.
Write();
904 const int r = d_rows[i];
905 const int end = d_I[r + 1];
907 for (
int j = d_I[r]; j < end; j++)
909 a += d_A[j] * d_x[d_J[j]];
918 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
920 for (
int i = 0; i < rows.
Size(); i++)
925 for (
int j =
I[r]; j < end; j++)
927 val +=
A[j] * x(
J[j]);
935 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
936 MFEM_ASSERT(x.
Size() ==
Width(),
"Input vector size (" << x.
Size()
937 <<
") must match matrix width (" <<
Width() <<
")");
943 auto d_I =
Read(
I, height+1);
944 auto d_J =
Read(
J, nnz);
947 MFEM_FORALL(i, height,
950 const int end = d_I[i+1];
951 for (
int j = d_I[i]; j < end; j++)
966 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
967 MFEM_ASSERT(x.
Size() ==
Height(),
"Input vector size (" << x.
Size()
968 <<
") must match matrix height (" <<
Height() <<
")");
973 for (
int i = 0; i <
Height(); i++)
978 for (
int j =
I[i]; j < end; j++)
988 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
989 <<
") must match matrix width (" <<
width <<
")");
990 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
991 <<
") must match matrix height (" <<
height <<
")");
1002 for (
int i = 0; i <
height; i++)
1004 RowNode *row =
Rows[i];
1006 for ( ; row != NULL; row = row->Prev)
1008 b += std::abs(row->Value) * xp[row->Column];
1018 auto d_I =
Read(
I, height+1);
1019 auto d_J =
Read(
J, nnz);
1020 auto d_A =
Read(
A, nnz);
1021 auto d_x = x.
Read();
1023 MFEM_FORALL(i, height,
1026 const int end = d_I[i+1];
1027 for (
int j = d_I[i]; j < end; j++)
1029 d += std::abs(d_A[j]) * d_x[d_J[j]];
1037 MFEM_ASSERT(
height == x.
Size(),
"Input vector size (" << x.
Size()
1038 <<
") must match matrix height (" <<
height <<
")");
1039 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
1040 <<
") must match matrix width (" <<
width <<
")");
1048 for (
int i = 0; i <
height; i++)
1050 RowNode *row =
Rows[i];
1052 for ( ; row != NULL; row = row->Prev)
1054 yp[row->Column] += fabs(row->Value) *
b;
1067 "this backend is not enabled; see EnsureMultTranspose() for "
1069 for (
int i = 0; i <
height; i++)
1071 const double xi = x[i];
1072 const int end =
I[i+1];
1073 for (
int j =
I[i]; j < end; j++)
1075 const int Jj =
J[j];
1076 y[Jj] += std::abs(
A[j]) * xi;
1085 <<
" must be equal to Width() = " <<
Width());
1087 <<
" must be equal to Height() = " <<
Height());
1100 for (
int i = 0; i <
height; i++)
1105 for (
int j =
I[i], end =
I[i+1]; j < end; j++)
1107 a +=
A[j] * x(
J[j]);
1112 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
1114 a += np->Value * x(np->Column);
1125 for (
int i = 0; i <
height; i++)
1130 for (
int j =
I[i], end =
I[i+1]; j < end; j++)
1137 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
1148 MFEM_VERIFY(irow <
height,
1149 "row " << irow <<
" not in matrix with height " <<
height);
1154 for (
int j =
I[irow], end =
I[irow+1]; j < end; j++)
1161 for (RowNode *np =
Rows[irow]; np != NULL; np = np->Prev)
1163 a += fabs(np->Value);
1172 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
1174 atol = std::abs(tol);
1176 fix_empty_rows =
height ==
width ? fix_empty_rows :
false;
1184 for (i = 0, nz = 0; i <
height; i++)
1187 for (j =
I[i]; j <
I[i+1]; j++)
1188 if (std::abs(
A[j]) > atol)
1193 if (fix_empty_rows && !found) { nz++; }
1201 for (i = 0, nz = 0; i <
height; i++)
1205 for (j =
I[i]; j <
I[i+1]; j++)
1206 if (std::abs(
A[j]) > atol)
1211 if ( lastCol > newJ[nz] )
1218 if (fix_empty_rows && !found)
1226 I.
Wrap(newI, height+1,
true);
1227 J.
Wrap(newJ,
I[height],
true);
1228 A.
Wrap(newA,
I[height],
true);
1246 for (i = 1; i <=
height; i++)
1249 for (aux =
Rows[i-1]; aux != NULL; aux = aux->Prev)
1251 if (skip_zeros && aux->Value == 0.0)
1253 if (skip_zeros == 2) {
continue; }
1254 if ((i-1) != aux->Column) {
continue; }
1258 for (RowNode *other =
Rows[aux->Column]; other != NULL; other = other->Prev)
1260 if (other->Column == (i-1))
1263 found_val = other->Value;
1267 if (found && found_val == 0.0) {
continue; }
1272 if (fix_empty_rows && !nr) { nr = 1; }
1281 for (j = i = 0; i <
height; i++)
1285 for (aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1287 if (skip_zeros && aux->Value == 0.0)
1289 if (skip_zeros == 2) {
continue; }
1290 if (i != aux->Column) {
continue; }
1294 for (RowNode *other =
Rows[aux->Column]; other != NULL; other = other->Prev)
1296 if (other->Column == i)
1299 found_val = other->Value;
1303 if (found && found_val == 0.0) {
continue; }
1309 if ( lastCol >
J[j] )
1318 if (fix_empty_rows && !nr)
1326 #ifdef MFEM_USE_MEMALLOC
1330 for (i = 0; i <
height; i++)
1332 RowNode *node_p =
Rows[i];
1333 while (node_p != NULL)
1336 node_p = node_p->Prev;
1349 int nr = (
height + br - 1)/br, nc = (
width + bc - 1)/bc;
1351 for (
int j = 0; j < bc; j++)
1353 for (
int i = 0; i < br; i++)
1356 for (
int k = 0; k <= nr; k++)
1360 blocks(i,j) =
new SparseMatrix(bI, NULL, NULL, nr, nc);
1364 for (
int gr = 0; gr <
height; gr++)
1366 int bi = gr/nr, i = gr%nr + 1;
1369 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1373 blocks(bi,
J[j]/nc)->I[i]++;
1379 for (RowNode *n_p =
Rows[gr]; n_p != NULL; n_p = n_p->Prev)
1381 if (n_p->Value != 0.0)
1383 blocks(bi, n_p->Column/nc)->I[i]++;
1389 for (
int j = 0; j < bc; j++)
1391 for (
int i = 0; i < br; i++)
1395 for (
int k = 1; k <= nr; k++)
1397 rs = b.
I[k], b.
I[k] = nnz, nnz += rs;
1404 for (
int gr = 0; gr <
height; gr++)
1406 int bi = gr/nr, i = gr%nr + 1;
1409 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1414 b.
J[b.
I[i]] =
J[j] % nc;
1422 for (RowNode *n_p =
Rows[gr]; n_p != NULL; n_p = n_p->Prev)
1424 if (n_p->Value != 0.0)
1427 b.
J[b.
I[i]] = n_p->Column % nc;
1428 b.
A[b.
I[i]] = n_p->Value;
1450 for (
int i = 1; i <
height; i++)
1452 for (
int j =
I[i]; j <
I[i+1]; j++)
1456 symm = std::max(symm, std::abs(
A[j]-(*
this)(
J[j],i)));
1463 for (
int i = 0; i <
height; i++)
1465 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
1467 int col = node_p->Column;
1470 symm = std::max(symm, std::abs(node_p->Value-(*
this)(col,i)));
1480 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1483 for (i = 1; i <
height; i++)
1485 for (j =
I[i]; j <
I[i+1]; j++)
1489 A[j] += (*this)(
J[j],i);
1491 (*this)(J[j],i) = A[j];
1507 for (
int i = 0; i <
height; i++)
1509 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
1526 for (
int j = 0; j < nnz; j++)
1528 m = std::max(m, std::abs(
A[j]));
1533 for (
int i = 0; i <
height; i++)
1535 for (RowNode *n_p =
Rows[i]; n_p != NULL; n_p = n_p->Prev)
1537 m = std::max(m, std::abs(n_p->Value));
1551 const double *Ap =
A;
1553 for (
int i = 0; i < nz; i++)
1555 counter += (std::abs(Ap[i]) <= tol);
1560 for (
int i = 0; i <
height; i++)
1562 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1564 counter += (std::abs(aux->Value) <= tol);
1585 for (
int i = 0; i <
height; i++)
1587 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1605 MFEM_ASSERT(row < height && row >= 0,
1606 "Row " << row <<
" not in matrix of height " <<
height);
1608 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
1610 for (aux =
Rows[row]; aux != NULL; aux = aux->Prev)
1612 rhs(aux->Column) -= sol * aux->Value;
1621 MFEM_ASSERT(row < height && row >= 0,
1622 "Row " << row <<
" not in matrix of height " <<
height);
1623 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1625 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1630 for (
int i=
I[row]; i <
I[row+1]; ++i)
1637 for (aux =
Rows[row]; aux != NULL; aux = aux->Prev)
1651 MFEM_ASSERT(col < width && col >= 0,
1652 "Col " << col <<
" not in matrix of width " <<
width);
1653 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1655 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1661 for (
int jpos = 0; jpos != nnz; ++jpos)
1671 for (
int i = 0; i <
height; i++)
1673 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1675 if (aux->Column == col)
1694 for (
int i = 0; i <
height; i++)
1696 for (
int jpos =
I[i]; jpos !=
I[i+1]; ++jpos)
1702 (*b)(i) -=
A[jpos] * (*x)(
J[jpos] );
1711 for (
int i = 0; i <
height; i++)
1713 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1715 if (cols[aux -> Column])
1719 (*b)(i) -= aux -> Value * (*x)(aux -> Column);
1733 for (
int row = 0; row <
height; row++)
1735 for (nd =
Rows[row]; nd != NULL; nd = nd->Prev)
1737 if (col_marker[nd->Column])
1739 Ae.
Add(row, nd->Column, nd->Value);
1747 for (
int row = 0; row <
height; row++)
1749 for (
int j =
I[row]; j <
I[row+1]; j++)
1751 if (col_marker[
J[j]])
1753 Ae.
Add(row,
J[j],
A[j]);
1765 MFEM_ASSERT(rc < height && rc >= 0,
1766 "Row " << rc <<
" not in matrix of height " <<
height);
1770 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1772 const int col =
J[j];
1778 rhs(rc) =
A[j] * sol;
1789 mfem_error(
"SparseMatrix::EliminateRowCol () #2");
1796 for (
int k = I[col]; 1; k++)
1800 mfem_error(
"SparseMatrix::EliminateRowCol () #3");
1802 else if (
J[k] == rc)
1804 rhs(col) -= sol *
A[k];
1814 for (RowNode *aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
1816 const int col = aux->Column;
1822 rhs(rc) = aux->Value * sol;
1833 mfem_error(
"SparseMatrix::EliminateRowCol () #4");
1840 for (RowNode *node =
Rows[col]; 1; node = node->Prev)
1844 mfem_error(
"SparseMatrix::EliminateRowCol () #5");
1846 else if (node->Column == rc)
1848 rhs(col) -= sol * node->Value;
1862 MFEM_ASSERT(rc < height && rc >= 0,
1863 "Row " << rc <<
" not in matrix of height " <<
height);
1864 MFEM_ASSERT(sol.
Size() == rhs.
Width(),
"solution size (" << sol.
Size()
1865 <<
") must match rhs width (" << rhs.
Width() <<
")");
1867 const int num_rhs = rhs.
Width();
1870 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1872 const int col =
J[j];
1878 for (
int r = 0; r < num_rhs; r++)
1880 rhs(rc,r) =
A[j] * sol(r);
1885 for (
int r = 0; r < num_rhs; r++)
1892 for (
int r = 0; r < num_rhs; r++)
1898 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #3");
1905 for (
int k = I[col]; 1; k++)
1909 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #4");
1911 else if (
J[k] == rc)
1913 for (
int r = 0; r < num_rhs; r++)
1915 rhs(col,r) -= sol(r) *
A[k];
1926 for (RowNode *aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
1928 const int col = aux->Column;
1934 for (
int r = 0; r < num_rhs; r++)
1936 rhs(rc,r) = aux->Value * sol(r);
1941 for (
int r = 0; r < num_rhs; r++)
1948 for (
int r = 0; r < num_rhs; r++)
1954 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #5");
1961 for (RowNode *node =
Rows[col]; 1; node = node->Prev)
1965 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #6");
1967 else if (node->Column == rc)
1969 for (
int r = 0; r < num_rhs; r++)
1971 rhs(col,r) -= sol(r) * node->Value;
1984 MFEM_ASSERT(rc < height && rc >= 0,
1985 "Row " << rc <<
" not in matrix of height " <<
height);
1989 const auto &II = this->
I;
1990 const auto &JJ = this->
J;
1991 for (
int j = II[rc]; j < II[rc+1]; j++)
1993 const int col = JJ[j];
2008 for (
int k = II[col]; 1; k++)
2012 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
2014 else if (JJ[k] == rc)
2025 RowNode *aux, *node;
2027 for (aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
2029 const int col = aux->Column;
2044 for (node =
Rows[col]; 1; node = node->Prev)
2048 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
2050 else if (node->Column == rc)
2065 MFEM_ASSERT(rc < height && rc >= 0,
2066 "Row " << rc <<
" not in matrix of height " <<
height);
2070 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2072 const int col =
J[j];
2080 for (
int k = I[col]; 1; k++)
2084 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
2086 else if (
J[k] == rc)
2097 RowNode *aux, *node;
2099 for (aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
2101 const int col = aux->Column;
2109 for (node =
Rows[col]; 1; node = node->Prev)
2113 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
2115 else if (node->Column == rc)
2132 for (nd =
Rows[rc]; nd != NULL; nd = nd->Prev)
2134 const int col = nd->Column;
2140 Ae.
Add(rc, rc, nd->Value - 1.0);
2144 Ae.
Add(rc, rc, nd->Value);
2150 mfem_error(
"SparseMatrix::EliminateRowCol #1");
2156 Ae.
Add(rc, col, nd->Value);
2158 for (nd2 =
Rows[col]; 1; nd2 = nd2->Prev)
2162 mfem_error(
"SparseMatrix::EliminateRowCol #2");
2164 else if (nd2->Column == rc)
2166 Ae.
Add(col, rc, nd2->Value);
2176 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2178 const int col =
J[j];
2184 Ae.
Add(rc, rc,
A[j] - 1.0);
2188 Ae.
Add(rc, rc,
A[j]);
2194 mfem_error(
"SparseMatrix::EliminateRowCol #3");
2200 Ae.
Add(rc, col,
A[j]);
2202 for (
int k = I[col];
true; k++)
2206 mfem_error(
"SparseMatrix::EliminateRowCol #4");
2208 else if (
J[k] == rc)
2210 Ae.
Add(col, rc,
A[k]);
2222 for (
int i = 0; i <
height; i++)
2224 if (
I[i+1] ==
I[i]+1 && fabs(
A[
I[i]]) < 1e-16)
2233 for (
int i = 0; i <
height; i++)
2236 for (
int j =
I[i]; j <
I[i+1]; j++)
2240 if (zero <= threshold)
2242 for (
int j = I[i]; j < I[i+1]; j++)
2244 A[j] = (
J[j] == i) ? 1.0 : 0.0;
2255 const double *xp = x.
GetData();
2256 RowNode *diag_p, *n_p, **R =
Rows;
2259 for (
int i = 0; i <
s; i++)
2263 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
2265 const int c = n_p->Column;
2272 sum += n_p->Value * yp[c];
2276 if (diag_p != NULL && diag_p->Value != 0.0)
2278 yp[i] = (xp[i] - sum) / diag_p->Value;
2280 else if (xp[i] == sum)
2286 mfem_error(
"SparseMatrix::Gauss_Seidel_forw()");
2300 for (
int i = 0, j = Ip[0]; i <
s; i++)
2302 const int end = Ip[i+1];
2305 for ( ; j < end; j++)
2307 const int c = Jp[j];
2314 sum += Ap[j] * yp[c];
2318 if (d >= 0 && Ap[d] != 0.0)
2320 yp[i] = (xp[i] - sum) / Ap[d];
2322 else if (xp[i] == sum)
2328 mfem_error(
"SparseMatrix::Gauss_Seidel_forw(...) #2");
2339 const double *xp = x.
GetData();
2340 RowNode *diag_p, *n_p, **R =
Rows;
2342 for (
int i =
height-1; i >= 0; i--)
2346 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
2348 const int c = n_p->Column;
2355 sum += n_p->Value * yp[c];
2359 if (diag_p != NULL && diag_p->Value != 0.0)
2361 yp[i] = (xp[i] - sum) / diag_p->Value;
2363 else if (xp[i] == sum)
2369 mfem_error(
"SparseMatrix::Gauss_Seidel_back()");
2383 for (
int i = s-1, j = Ip[s]-1; i >= 0; i--)
2385 const int beg = Ip[i];
2388 for ( ; j >= beg; j--)
2390 const int c = Jp[j];
2397 sum += Ap[j] * yp[c];
2401 if (d >= 0 && Ap[d] != 0.0)
2403 yp[i] = (xp[i] - sum) / Ap[d];
2405 else if (xp[i] == sum)
2411 mfem_error(
"SparseMatrix::Gauss_Seidel_back(...) #2");
2419 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2422 for (
int i = 0; i <
height; i++)
2426 for (
int j =
I[i]; j <
I[i+1]; j++)
2434 if (d >= 0 &&
A[d] != 0.0)
2436 double a = 1.8 * fabs(
A[d]) / norm;
2444 mfem_error(
"SparseMatrix::GetJacobiScaling() #2");
2451 double sc,
bool use_abs_diag)
const
2453 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2455 for (
int i = 0; i <
height; i++)
2459 for (
int j =
I[i]; j <
I[i+1]; j++)
2467 sum -=
A[j] * x0(
J[j]);
2470 if (d >= 0 &&
A[d] != 0.0)
2472 const double diag = (use_abs_diag) ? fabs(
A[d]) :
A[d];
2473 x1(i) = sc * (sum / diag) + (1.0 - sc) * x0(i);
2483 double sc,
bool use_abs_diag)
const
2485 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2491 const auto Ap =
Read(
A, nnz, use_dev);
2493 const auto Jp =
Read(
J, nnz, use_dev);
2495 const auto bp = b.
Read(use_dev);
2496 auto xp = x.
Write(use_dev);
2498 MFEM_FORALL_SWITCH(use_dev, i, H,
2500 const int end = Ip[i+1];
2501 for (
int j = Ip[i];
true; j++)
2505 MFEM_ABORT_KERNEL(
"Diagonal not found in SparseMatrix::DiagScale");
2509 const double diag = (use_abs_diag) ? fabs(Ap[j]) : Ap[j];
2512 MFEM_ABORT_KERNEL(
"Zero diagonal in SparseMatrix::DiagScale");
2514 xp[i] = sc * bp[i] / diag;
2521 template <
bool useFabs>
2529 const auto bp = b.
Read(useDevice);
2530 const auto x0p = x0.
Read(useDevice);
2531 auto x1p = x1.
Write(useDevice);
2533 const auto Ip =
Read(I, height+1, useDevice);
2537 MFEM_FORALL_SWITCH(useDevice, i, height,
2539 double resi = bp[i], norm = 0.0;
2540 for (
int j = Ip[i]; j < Ip[i+1]; j++)
2542 resi -= Ap[j] * x0p[Jp[j]];
2545 norm += fabs(Ap[j]);
2554 x1p[i] = x0p[i] + sc * resi / norm;
2560 MFEM_ABORT_KERNEL(
"L1 norm of row is zero.");
2564 MFEM_ABORT_KERNEL(
"sum of row is zero.");
2573 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2574 JacobiDispatch<true>(
b,x0,x1,
I,
J,
A,
height,sc);
2580 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2581 JacobiDispatch<false>(
b,x0,x1,
I,
J,
A,
height,sc);
2587 int i, j, gi, gj,
s,
t;
2597 for (i = 0; i < rows.
Size(); i++)
2599 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2601 MFEM_ASSERT(gi < height,
2602 "Trying to insert a row " << gi <<
" outside the matrix height "
2605 for (j = 0; j < cols.
Size(); j++)
2607 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2609 MFEM_ASSERT(gj <
width,
2610 "Trying to insert a column " << gj <<
" outside the matrix width "
2613 if (skip_zeros && a == 0.0)
2618 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2623 if (t < 0) { a = -
a; }
2635 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2637 MFEM_ASSERT(gi < height,
2638 "Trying to set a row " << gi <<
" outside the matrix height "
2640 if ((gj=j) < 0) { gj = -1-gj, t = -
s; }
2642 MFEM_ASSERT(gj <
width,
2643 "Trying to set a column " << gj <<
" outside the matrix width "
2645 if (t < 0) { a = -
a; }
2654 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2656 MFEM_ASSERT(gi < height,
2657 "Trying to insert a row " << gi <<
" outside the matrix height "
2659 if ((gj=j) < 0) { gj = -1-gj, t = -
s; }
2661 MFEM_ASSERT(gj <
width,
2662 "Trying to insert a column " << gj <<
" outside the matrix width "
2664 if (t < 0) { a = -
a; }
2671 int i, j, gi, gj,
s,
t;
2674 for (i = 0; i < rows.
Size(); i++)
2676 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2678 MFEM_ASSERT(gi < height,
2679 "Trying to set a row " << gi <<
" outside the matrix height "
2682 for (j = 0; j < cols.
Size(); j++)
2685 if (skip_zeros && a == 0.0)
2690 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2695 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2697 MFEM_ASSERT(gj <
width,
2698 "Trying to set a column " << gj <<
" outside the matrix width "
2700 if (t < 0) { a = -
a; }
2712 int i, j, gi, gj,
s,
t;
2715 for (i = 0; i < rows.
Size(); i++)
2717 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2719 MFEM_ASSERT(gi < height,
2720 "Trying to set a row " << gi <<
" outside the matrix height "
2723 for (j = 0; j < cols.
Size(); j++)
2726 if (skip_zeros && a == 0.0)
2731 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2736 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2738 MFEM_ASSERT(gj <
width,
2739 "Trying to set a column " << gj <<
" outside the matrix width "
2741 if (t < 0) { a = -
a; }
2751 int i, j, gi, gj,
s,
t;
2754 for (i = 0; i < rows.
Size(); i++)
2756 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2758 MFEM_ASSERT(gi < height,
2759 "Trying to read a row " << gi <<
" outside the matrix height "
2762 for (j = 0; j < cols.
Size(); j++)
2764 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2766 MFEM_ASSERT(gj <
width,
2767 "Trying to read a column " << gj <<
" outside the matrix width "
2770 subm(i, j) = (t < 0) ? (-a) : (
a);
2784 MFEM_ASSERT(gi < height,
2785 "Trying to query a row " << gi <<
" outside the matrix height "
2789 return (
Rows[gi] == NULL);
2793 return (I[gi] == I[gi+1]);
2802 if ((gi=row) < 0) { gi = -1-gi; }
2803 MFEM_ASSERT(gi < height,
2804 "Trying to read a row " << gi <<
" outside the matrix height "
2808 for (n =
Rows[gi], j = 0; n; n = n->Prev)
2814 for (n =
Rows[gi], j = 0; n; n = n->Prev, j++)
2816 cols[j] = n->Column;
2829 cols.
MakeRef(const_cast<int*>((
const int*)J) + j, I[gi+1]-j);
2831 const_cast<double*>((
const double*)A) + j, cols.
Size());
2832 MFEM_ASSERT(row >= 0,
"Row not valid: " << row <<
", height: " << height);
2843 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2845 MFEM_ASSERT(gi < height,
2846 "Trying to set a row " << gi <<
" outside the matrix height "
2852 for (
int j = 0; j < cols.
Size(); j++)
2854 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2856 MFEM_ASSERT(gj <
width,
2857 "Trying to set a column " << gj <<
" outside the matrix"
2858 " width " <<
width);
2860 if (t < 0) { a = -
a; }
2868 MFEM_ASSERT(cols.
Size() == srow.
Size(),
"");
2870 for (
int i = I[gi], j = 0; j < cols.
Size(); j++, i++)
2872 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2874 MFEM_ASSERT(gj <
width,
2875 "Trying to set a column " << gj <<
" outside the matrix"
2876 " width " <<
width);
2887 int j, gi, gj,
s,
t;
2890 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
2892 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2894 MFEM_ASSERT(gi < height,
2895 "Trying to insert a row " << gi <<
" outside the matrix height "
2898 for (j = 0; j < cols.
Size(); j++)
2900 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2902 MFEM_ASSERT(gj <
width,
2903 "Trying to insert a column " << gj <<
" outside the matrix width "
2910 if (t < 0) { a = -
a; }
2928 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2930 aux -> Value *= scale;
2935 int j, end = I[i+1];
2937 for (j = I[i]; j < end; j++)
2950 for (
int i=0; i <
height; ++i)
2953 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2955 aux -> Value *= scale;
2963 for (
int i=0; i <
height; ++i)
2967 for (j = I[i]; j < end; j++)
2980 for (
int i=0; i <
height; ++i)
2982 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2984 aux -> Value *= sr(aux->Column);
2992 for (
int i=0; i <
height; ++i)
2995 for (j = I[i]; j < end; j++)
3006 "Mismatch of this matrix size and rhs. This height = "
3007 << height <<
", width = " <<
width <<
", B.height = "
3010 for (
int i = 0; i <
height; i++)
3015 for (RowNode *aux = B.
Rows[i]; aux != NULL; aux = aux->Prev)
3017 _Add_(aux->Column, aux->Value);
3022 for (
int j = B.
I[i]; j < B.
I[i+1]; j++)
3035 for (
int i = 0; i <
height; i++)
3040 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
3042 np->Value += a * B.
_Get_(np->Column);
3047 for (
int j = I[i]; j < I[i+1]; j++)
3049 A[j] += a * B.
_Get_(J[j]);
3062 for (
int i = 0; i < nnz; i++)
3069 for (
int i = 0; i <
height; i++)
3071 for (RowNode *node_p =
Rows[i]; node_p != NULL;
3072 node_p = node_p -> Prev)
3074 node_p -> Value =
a;
3086 for (
int i = 0, nnz = I[height]; i < nnz; i++)
3093 for (
int i = 0; i <
height; i++)
3095 for (RowNode *node_p =
Rows[i]; node_p != NULL;
3096 node_p = node_p -> Prev)
3098 node_p -> Value *=
a;
3113 for (i = 0; i <
height; i++)
3115 os <<
"[row " << i <<
"]\n";
3116 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->Prev, j++)
3118 os <<
" (" << nd->Column <<
"," << nd->Value <<
")";
3119 if ( !((j+1) % width_) )
3136 for (i = 0; i <
height; i++)
3138 os <<
"[row " << i <<
"]\n";
3139 for (j = I[i]; j < I[i+1]; j++)
3141 os <<
" (" << J[j] <<
"," << A[j] <<
")";
3142 if ( !((j+1-I[i]) % width_) )
3147 if ((j-I[i]) % width_)
3156 os <<
"% size " << height <<
" " <<
width <<
"\n";
3159 ios::fmtflags old_fmt = os.flags();
3160 os.setf(ios::scientific);
3161 std::streamsize old_prec = os.precision(14);
3163 for (i = 0; i <
height; i++)
3165 for (j = I[i]; j < I[i+1]; j++)
3167 os << i+1 <<
" " << J[j]+1 <<
" " << A[j] <<
'\n';
3171 os << height <<
" " << width <<
" 0.0\n";
3172 os.precision(old_prec);
3179 ios::fmtflags old_fmt = os.flags();
3180 os.setf(ios::scientific);
3181 std::streamsize old_prec = os.precision(14);
3183 os <<
"%%MatrixMarket matrix coordinate real general" <<
'\n'
3184 <<
"% Generated by MFEM" <<
'\n';
3187 for (i = 0; i <
height; i++)
3189 for (j = I[i]; j < I[i+1]; j++)
3191 os << i+1 <<
" " << J[j]+1 <<
" " << A[j] <<
'\n';
3194 os.precision(old_prec);
3200 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3204 os << height <<
'\n';
3206 for (i = 0; i <=
height; i++)
3208 os << I[i]+1 <<
'\n';
3211 for (i = 0; i < I[
height]; i++)
3213 os << J[i]+1 <<
'\n';
3216 for (i = 0; i < I[
height]; i++)
3224 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3228 os << height <<
'\n';
3229 os <<
width <<
'\n';
3231 for (i = 0; i <=
height; i++)
3236 for (i = 0; i < I[
height]; i++)
3241 for (i = 0; i < I[
height]; i++)
3249 const double MiB = 1024.*1024;
3251 double pz = 100./nnz;
3261 "SparseMatrix statistics:\n"
3264 " Dimensions : " << height <<
" x " <<
width <<
"\n"
3265 " Number of entries (total) : " << nnz <<
"\n"
3266 " Number of entries (per row) : " << 1.*nnz/
Height() <<
"\n"
3267 " Number of stored zeros : " << nz*pz <<
"% (" << nz <<
")\n"
3268 " Number of Inf/Nan entries : " << nnf*pz <<
"% ("<< nnf <<
")\n"
3269 " Norm, max |a_ij| : " << max_norm <<
"\n"
3270 " Symmetry, max |a_ij-a_ji| : " << symm <<
"\n"
3271 " Number of small entries:\n"
3272 " |a_ij| <= 1e-12*Norm : " << ns12*pz <<
"% (" << ns12 <<
")\n"
3273 " |a_ij| <= 1e-15*Norm : " << ns15*pz <<
"% (" << ns15 <<
")\n"
3274 " |a_ij| <= 1e-18*Norm : " << ns18*pz <<
"% (" << ns18 <<
")\n";
3277 os <<
" Memory used by CSR : " <<
3278 (
sizeof(int)*(height+1+nnz)+
sizeof(double)*nnz)/MiB <<
" MiB\n";
3282 size_t used_mem =
sizeof(RowNode*)*height;
3283 #ifdef MFEM_USE_MEMALLOC
3286 for (
int i = 0; i <
height; i++)
3288 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
3290 used_mem +=
sizeof(RowNode);
3294 os <<
" Memory used by LIL : " << used_mem/MiB <<
" MiB\n";
3306 #if !defined(MFEM_USE_MEMALLOC)
3307 for (
int i = 0; i <
height; i++)
3309 RowNode *aux, *node_p =
Rows[i];
3310 while (node_p != NULL)
3313 node_p = node_p->Prev;
3323 #ifdef MFEM_USE_MEMALLOC
3336 const int *start_j =
J;
3337 const int *end_j = J + I[
height];
3338 for (
const int *jptr = start_j; jptr != end_j; ++jptr)
3340 awidth = std::max(awidth, *jptr + 1);
3346 for (
int i = 0; i <
height; i++)
3348 for (aux =
Rows[i]; aux != NULL; aux = aux->Prev)
3350 awidth = std::max(awidth, aux->Column + 1);
3362 for (
int i = 0; i < n; i++)
3372 "Finalize must be called before Transpose. Use TransposeRowMatrix instead");
3375 const int *A_i, *A_j;
3376 int m, n, nnz, *At_i, *At_j;
3377 const double *A_data;
3391 for (i = 0; i <= n; i++)
3395 for (i = 0; i < nnz; i++)
3399 for (i = 1; i < n; i++)
3401 At_i[i+1] += At_i[i];
3404 for (i = j = 0; i < m; i++)
3407 for ( ; j < end; j++)
3409 At_j[At_i[A_j[j]]] = i;
3410 At_data[At_i[A_j[j]]] = A_data[j];
3415 for (i = n; i > 0; i--)
3417 At_i[i] = At_i[i-1];
3428 int m, n, nnz, *At_i, *At_j;
3438 for (i = 0; i < m; i++)
3440 A.
GetRow(i, Acols, Avals);
3462 for (i = 0; i <= n; i++)
3467 for (i = 0; i < m; i++)
3469 A.
GetRow(i, Acols, Avals);
3470 for (j = 0; j<Acols.
Size(); ++j)
3475 for (i = 1; i < n; i++)
3477 At_i[i+1] += At_i[i];
3480 for (i = 0; i < m; i++)
3482 A.
GetRow(i, Acols, Avals);
3483 for (j = 0; j<Acols.
Size(); ++j)
3485 At_j[At_i[Acols[j]]] = i;
3486 At_data[At_i[Acols[j]]] = Avals[j];
3491 for (i = n; i > 0; i--)
3493 At_i[i] = At_i[i-1];
3504 int nrowsA, ncolsA, nrowsB, ncolsB;
3505 const int *A_i, *A_j, *B_i, *B_j;
3506 int *C_i, *C_j, *B_marker;
3507 const double *A_data, *B_data;
3509 int ia, ib, ic, ja, jb, num_nonzeros;
3510 int row_start, counter;
3511 double a_entry, b_entry;
3519 MFEM_VERIFY(ncolsA == nrowsB,
3520 "number of columns of A (" << ncolsA
3521 <<
") must equal number of rows of B (" << nrowsB <<
")");
3530 B_marker =
new int[ncolsB];
3532 for (ib = 0; ib < ncolsB; ib++)
3541 C_i[0] = num_nonzeros = 0;
3542 for (ic = 0; ic < nrowsA; ic++)
3544 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3547 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3550 if (B_marker[jb] != ic)
3557 C_i[ic+1] = num_nonzeros;
3563 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3565 for (ib = 0; ib < ncolsB; ib++)
3574 MFEM_VERIFY(nrowsA == C->
Height() && ncolsB == C->
Width(),
3575 "Input matrix sizes do not match output sizes"
3576 <<
" nrowsA = " << nrowsA
3577 <<
", C->Height() = " << C->
Height()
3578 <<
" ncolsB = " << ncolsB
3579 <<
", C->Width() = " << C->
Width());
3587 for (ic = 0; ic < nrowsA; ic++)
3590 row_start = counter;
3591 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3594 a_entry = A_data[ia];
3595 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3598 b_entry = B_data[ib];
3599 if (B_marker[jb] < row_start)
3601 B_marker[jb] = counter;
3606 C_data[counter] = a_entry*b_entry;
3611 C_data[B_marker[jb]] += a_entry*b_entry;
3619 "With pre-allocated output matrix, number of non-zeros ("
3621 <<
") did not match number of entries changed from matrix-matrix multiply, "
3640 int nrowsA, ncolsA, nrowsB, ncolsB;
3641 int *C_i, *C_j, *B_marker;
3643 int ia, ib, ic, ja, jb, num_nonzeros;
3644 int row_start, counter;
3645 double a_entry, b_entry;
3653 MFEM_VERIFY(ncolsA == nrowsB,
3654 "number of columns of A (" << ncolsA
3655 <<
") must equal number of rows of B (" << nrowsB <<
")");
3657 B_marker =
new int[ncolsB];
3659 for (ib = 0; ib < ncolsB; ib++)
3666 C_i[0] = num_nonzeros = 0;
3670 for (ic = 0; ic < nrowsA; ic++)
3672 A.
GetRow(ic, colsA, dataA);
3673 for (ia = 0; ia < colsA.
Size(); ia++)
3676 B.
GetRow(ja, colsB, dataB);
3677 for (ib = 0; ib < colsB.
Size(); ib++)
3680 if (B_marker[jb] != ic)
3687 C_i[ic+1] = num_nonzeros;
3693 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3695 for (ib = 0; ib < ncolsB; ib++)
3701 for (ic = 0; ic < nrowsA; ic++)
3703 row_start = counter;
3704 A.
GetRow(ic, colsA, dataA);
3705 for (ia = 0; ia < colsA.
Size(); ia++)
3708 a_entry = dataA[ia];
3709 B.
GetRow(ja, colsB, dataB);
3710 for (ib = 0; ib < colsB.
Size(); ib++)
3713 b_entry = dataB[ib];
3714 if (B_marker[jb] < row_start)
3716 B_marker[jb] = counter;
3718 C_data[counter] = a_entry*b_entry;
3723 C_data[B_marker[jb]] += a_entry*b_entry;
3738 for (
int j = 0; j < B.
Width(); ++j)
3742 A.
Mult(columnB, columnC);
3752 Mult (R, *AP, *RAP_);
3795 int i, At_nnz, *At_j;
3799 At_nnz = At -> NumNonZeroElems();
3800 At_j = At -> GetJ();
3801 At_data = At -> GetData();
3802 for (i = 0; i < At_nnz; i++)
3804 At_data[i] *= D(At_j[i]);
3815 int ncols = A.
Width();
3821 const int *A_i = A.
GetI();
3822 const int *A_j = A.
GetJ();
3823 const double *A_data = A.
GetData();
3825 const int *B_i = B.
GetI();
3826 const int *B_j = B.
GetJ();
3827 const double *B_data = B.
GetData();
3829 int * marker =
new int[ncols];
3830 std::fill(marker, marker+ncols, -1);
3832 int num_nonzeros = 0, jcol;
3834 for (
int ic = 0; ic < nrows; ic++)
3836 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3842 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
3845 if (marker[jcol] != ic)
3851 C_i[ic+1] = num_nonzeros;
3857 for (
int ia = 0; ia < ncols; ia++)
3863 for (
int ic = 0; ic < nrows; ic++)
3865 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3869 C_data[pos] = a*A_data[ia];
3873 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
3876 if (marker[jcol] < C_i[ic])
3879 C_data[pos] = b*B_data[ib];
3885 C_data[marker[jcol]] += b*B_data[ib];
3891 return new SparseMatrix(C_i, C_j, C_data, nrows, ncols);
3896 return Add(1.,A,1.,B);
3901 MFEM_ASSERT(Ai.
Size() > 0,
"invalid size Ai.Size() = " << Ai.
Size());
3906 for (
int i=1; i < Ai.
Size(); ++i)
3908 result =
Add(*accumulate, *Ai[i]);
3914 accumulate = result;
3924 for (
int r = 0; r < B.
Height(); r++)
3928 for (
int i=0; i<A.
RowSize(r); i++)
3930 B(r, colA[i]) += alpha * valA[i];
3943 for (
int i=0; i<mA; i++)
3945 for (
int j=0; j<nA; j++)
3947 C->
AddMatrix(A(i,j), B, i * mB, j * nB);
3961 for (
int i=0; i<mA; i++)
3963 for (
int j=0; j<nA; j++)
3965 for (
int r=0; r<mB; r++)
3970 for (
int cj=0; cj<B.
RowSize(r); cj++)
3972 C->
Set(i * mB + r, j * nB + colB[cj], A(i,j) * valB[cj]);
3990 for (
int r=0; r<mA; r++)
3995 for (
int aj=0; aj<A.
RowSize(r); aj++)
3997 for (
int i=0; i<mB; i++)
3999 for (
int j=0; j<nB; j++)
4001 C->
Set(r * mB + i, colA[aj] * nB + j, valA[aj] * B(i, j));
4019 for (
int ar=0; ar<mA; ar++)
4024 for (
int aj=0; aj<A.
RowSize(ar); aj++)
4026 for (
int br=0; br<mB; br++)
4031 for (
int bj=0; bj<B.
RowSize(br); bj++)
4033 C->
Set(ar * mB + br, colA[aj] * nB + colB[bj],
4034 valA[aj] * valB[bj]);
4057 #ifdef MFEM_USE_MEMALLOC
4067 #ifdef MFEM_USE_CUDA_OR_HIP
4074 MFEM_cu_or_hip(sparseDestroy)(
handle);
4079 MFEM_Cu_or_Hip(MemFree)(
dBuffer);
4086 #endif // MFEM_USE_CUDA_OR_HIP
Memory< int > I
Array with size (height+1) containing the row offsets.
double GetJacobiScaling() const
Determine appropriate scaling for Jacobi iteration.
int CheckFinite() const
Count the number of entries that are NOT finite, i.e. Inf or Nan.
int Size() const
Return the logical size of the array.
void DiagScale(const Vector &b, Vector &x, double sc=1.0, bool use_abs_diag=false) const
x = sc b / A_ii. When use_abs_diag = true, |A_ii| is used.
SparseMatrix * TransposeAbstractSparseMatrix(const AbstractSparseMatrix &A, int useActualWidth)
Transpose of a sparse matrix. A does not need to be a CSR matrix.
int RowSize(const int i) const
Returns the number of elements in row i.
int CheckFinite(const double *v, const int n)
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
void _Add_(const int col, const double a)
Add a value to an entry in the "current row". See SetColPtr().
void BuildTranspose() const
Build and store internally the transpose of this matrix which will be used in the methods AddMultTran...
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
void Clear()
Clear the contents of the SparseMatrix.
void EliminateCol(int col, DiagonalPolicy dpolicy=DIAG_ZERO)
Eliminates the column col from the matrix.
Memory< T > & GetMemory()
Return a reference to the Memory object used by the Array.
SparseMatrix * At
Transpose of A. Owned. Used to perform MultTranspose() on devices.
HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
Returns the matrix P^t * A * P.
size_t MemoryUsage() const
virtual void Finalize(int skip_zeros=1)
Finalize the matrix initialization, switching the storage format from LIL to CSR. ...
void MakeRef(const SparseMatrix &master)
Clear the contents of the SparseMatrix and make it a reference to master.
void SetSize(int s)
Resize the vector to size s.
double & SearchRow(const int col)
Perform a fast search for an entry in the "current row". See SetColPtr().
void Delete()
Delete the owned pointers and reset the Memory object.
DenseMatrix * ToDenseMatrix() const
Produces a DenseMatrix from a SparseMatrix.
bool Empty() const
Check if the SparseMatrix is empty.
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
const double * ReadData(bool on_dev=true) const
int * GetJ()
Return the array J.
Biwise-OR of all HIP backends.
Abstract data type for sparse matrices.
SparseMatrix & operator+=(const SparseMatrix &B)
Add the sparse matrix 'B' to '*this'. This operation will cause an error if '*this' is finalized and ...
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true...
Data type dense matrix using column-major storage.
void AddMult(const Vector &x, Vector &y, const double a=1.0) const
y += A * x (default) or y += a * A * x
int Size() const
Returns the size of the vector.
int * GetI()
Return the array I.
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const
y += At * x (default) or y += a * At * x
Abstract data type for matrix inverse.
void EliminateRowColMultipleRHS(int rc, const Vector &sol, DenseMatrix &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Similar to EliminateRowCol(int, const double, Vector &, DiagonalPolicy), but multiple values for elim...
virtual int NumNonZeroElems() const =0
Returns the number of non-zeros in a matrix.
void ClearGPUSparse()
Clear the cuSPARSE/hipSPARSE descriptors. This must be called after releasing the device memory of A...
void PrintInfo(std::ostream &out) const
Print various sparse matrix statistics.
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
virtual double & Elem(int i, int j)
Returns reference to a_{ij}.
void Jacobi(const Vector &b, const Vector &x0, Vector &x1, double sc, bool use_abs_diag=false) const
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
double * GetRowEntries(const int row)
Return a pointer to the entries in a row.
double * GetData() const
Return a pointer to the beginning of the Vector data.
void SortColumnIndices()
Sort the column indices corresponding to each row.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void PrintMM(std::ostream &out=mfem::out) const
Prints matrix in Matrix Market sparse format.
int Capacity() const
Return the size of the allocated memory.
cusparseDnVecDescr_t vecY_descr
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm) const
double * HostReadWriteData()
void _Set_(const int col, const double a)
Set an entry in the "current row". See SetColPtr().
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
SparseMatrix * Mult_AtDA(const SparseMatrix &A, const Vector &D, SparseMatrix *OAtDA)
Matrix multiplication A^t D A. All matrices must be finalized.
void PartAddMult(const Array< int > &rows, const Vector &x, Vector &y, const double a=1.0) const
bool RowIsEmpty(const int row) const
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
unsigned flags
Bit flags defined from the FlagMask enum.
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
const int * ReadJ(bool on_dev=true) const
void ScaleRow(const int row, const double scale)
double * GetData()
Return the element data, i.e. the array A.
void Symmetrize()
(*this) = 1/2 ((*this) + (*this)^t)
bool IsFinite(const double &val)
void MoveDiagonalFirst()
Move the diagonal entry to the first position in each row, preserving the order of the rest of the co...
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
void Set(const int i, const int j, const double val)
void Wrap(T *ptr, int size, bool own)
Wrap an externally allocated host pointer, ptr with the current host memory type returned by MemoryMa...
void ClearColPtr() const
Reset the "current row" set by calling SetColPtr(). This method must be called between any two calls ...
void ScaleColumns(const Vector &sr)
this = this * diag(sr);
virtual ~SparseMatrix()
Destroys sparse matrix.
void PrintCSR2(std::ostream &out) const
Prints a sparse matrix to stream out in CSR format.
double f(const Vector &xvec)
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
Extract all column indices and values from a given row.
bool isSorted
Are the columns sorted already.
Memory< double > A
Array with size I[height], containing the actual entries of the sparse matrix, as indexed by the I ar...
SparseMatrix()
Create an empty SparseMatrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
void EnsureMultTranspose() const
Ensures that the matrix is capable of performing MultTranspose(), AddMultTranspose(), and AbsMultTranspose().
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
void SetWidth(int width_=-1)
Change the width of a SparseMatrix.
const double * HostReadData() const
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
double IsSymmetric() const
Returns max_{i,j} |(i,j)-(j,i)| for a finalized matrix.
const int * HostReadJ() const
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
static int SparseMatrixCount
void SetDiagIdentity()
If a row contains only one diag entry of zero, set it to 1.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
void ScaleRows(const Vector &sl)
this = diag(sl) * this;
static cusparseHandle_t handle
DenseMatrix * OuterProduct(const DenseMatrix &A, const DenseMatrix &B)
Produces a block matrix with blocks A_{ij}*B.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const =0
Gets the columns indexes and values for row row.
Set the diagonal value to one.
virtual void PrintMatlab(std::ostream &out=mfem::out) const
Prints matrix in matlab format.
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true...
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Biwise-OR of all CUDA backends.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void Add(const int i, const int j, const double val)
Dynamic 2D array using row-major layout.
void SetSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
bool Finalized() const
Returns whether or not CSR format has been finalized.
Biwise-OR of all CPU backends.
T * HostWrite(Memory< T > &mem, int size)
Shortcut to Write(const Memory<T> &mem, int size, false)
void SparseMatrixFunction(SparseMatrix &S, double(*f)(double))
Applies f() to each element of the matrix (after it is finalized).
virtual MatrixInverse * Inverse() const
This virtual method is not supported: it always returns NULL.
void Swap(Array< T > &, Array< T > &)
void ClearOwnerFlags() const
Clear the ownership flags for the host and device pointers, as well as any internal data allocated by...
void EliminateRowColDiag(int rc, double value)
Perform elimination and set the diagonal entry to the given value.
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
void SetColPtr(const int row) const
Initialize the SparseMatrix for fast access to the entries of the given row which becomes the "curren...
MemoryType
Memory types supported by MFEM.
void SetSubMatrixTranspose(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void SetHostPtrOwner(bool own) const
Set/clear the ownership flag for the host pointer. Ownership indicates whether the pointer will be de...
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
void EliminateRowCol(int rc, const double sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate row rc and column rc and modify the rhs using sol.
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
void GetColumnReference(int c, Vector &col)
void Threshold(double tol, bool fix_empty_rows=false)
Remove entries smaller in absolute value than a given tolerance tol. If fix_empty_rows is true...
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0<=i<A.Height, 0<=j<A.Width.
void Gauss_Seidel_back(const Vector &x, Vector &y) const
const int * ReadI(bool on_dev=true) const
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
void Gauss_Seidel_forw(const Vector &x, Vector &y) const
Gauss-Seidel forward and backward iterations over a vector x.
RowNode ** Rows
Array of linked lists, one for every row. This array represents the linked list (LIL) storage format...
int height
Dimension of the output / number of rows in the matrix.
void EliminateRow(int row, const double sol, Vector &rhs)
Eliminates a column from the transpose matrix.
const T * HostRead(const Memory< T > &mem, int size)
Shortcut to Read(const Memory<T> &mem, int size, false)
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
int ActualWidth() const
Returns the actual Width of the matrix.
void GetDiag(Vector &d) const
Returns the Diagonal of A.
MemAlloc< RowNode, 1024 > RowNodeAlloc
double GetRowNorml1(int irow) const
For i = irow compute .
void ResetTranspose() const
SparseMatrix * TransposeMult(const SparseMatrix &A, const SparseMatrix &B)
C = A^T B.
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
virtual void EliminateZeroRows(const double threshold=1e-12)
If a row contains only zeros, set its diagonal to 1.
void AbsMultTranspose(const Vector &x, Vector &y) const
y = |At| * x, using entry-wise absolute values of the transpose of matrix A
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
double & operator()(int i, int j)
Returns reference to A[i][j].
void MultTranspose(const Vector &x, Vector &y) const
Multiply a vector with the transposed matrix. y = At * x.
void EliminateCols(const Array< int > &cols, const Vector *x=NULL, Vector *b=NULL)
Eliminate all columns i for which cols[i] != 0.
SparseMatrix & operator=(const SparseMatrix &rhs)
Assignment operator: deep copy.
double infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
SparseMatrix & operator*=(double a)
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
cusparseSpMatDescr_t matA_descr
void MakeRef(T *, int)
Make this Array a reference to a pointer.
void Print(std::ostream &out=mfem::out, int width_=4) const
Prints matrix to stream out.
const int * HostReadI() const
void Jacobi2(const Vector &b, const Vector &x0, Vector &x1, double sc=1.0) const
cusparseDnVecDescr_t vecX_descr
int MaxRowSize() const
Returns the maximum number of elements among all rows.
void Jacobi3(const Vector &b, const Vector &x0, Vector &x1, double sc=1.0) const
SparseMatrix * MultAbstractSparseMatrix(const AbstractSparseMatrix &A, const AbstractSparseMatrix &B)
Matrix product of sparse matrices. A and B do not need to be CSR matrices.
void AbsMult(const Vector &x, Vector &y) const
y = |A| * x, using entry-wise absolute values of matrix A
double _Get_(const int col) const
Read the value of an entry in the "current row". See SetColPtr().
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Memory< int > J
Array with size I[height], containing the column indices for all matrix entries, as indexed by the I ...
void Swap(SparseMatrix &other)
void PrintCSR(std::ostream &out) const
Prints matrix to stream out in hypre_CSRMatrix format.
double InnerProduct(const Vector &x, const Vector &y) const
Compute y^t A x.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Set the diagonal value to zero.
int width
Dimension of the input / number of columns in the matrix.
int CountSmallElems(double tol) const
Count the number of entries with |a_ij| <= tol.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
void GetRowSums(Vector &x) const
For all i compute .
void Neg()
(*this) = -(*this)