27#if defined(MFEM_USE_CUDA)
28#define MFEM_cu_or_hip(stub) cu##stub
29#define MFEM_Cu_or_Hip(stub) Cu##stub
30#define MFEM_CU_or_HIP(stub) CU##stub
31#define MFEM_CUDA_or_HIP(stub) CUDA##stub
33#if CUSPARSE_VERSION >= 11400
34#define MFEM_GPUSPARSE_ALG CUSPARSE_SPMV_CSR_ALG1
36#define MFEM_GPUSPARSE_ALG CUSPARSE_CSRMV_ALG1
39#elif defined(MFEM_USE_HIP)
40#define MFEM_cu_or_hip(stub) hip##stub
41#define MFEM_Cu_or_Hip(stub) Hip##stub
42#define MFEM_CU_or_HIP(stub) HIP##stub
43#define MFEM_CUDA_or_HIP(stub) HIP##stub
46#define MFEM_GPUSPARSE_ALG HIPSPARSE_CSRMV_ALG1
49#ifdef MFEM_USE_CUDA_OR_HIP
50#define MFEM_CHECK_SPARSE(call) \
52 auto sparse_status = (call); \
53 if (sparse_status != MFEM_CU_or_HIP(SPARSE_STATUS_SUCCESS)) \
55 MFEM_VERIFY(sparse_status == MFEM_CU_or_HIP(SPARSE_STATUS_SUCCESS),\
56 MFEM_cu_or_hip(sparseGetErrorString)(sparse_status)); \
62#if defined(MFEM_USE_SINGLE)
63#define MFEM_CUDA_or_HIP_REAL_T MFEM_CUDA_or_HIP(_R_32F)
64#elif defined(MFEM_USE_DOUBLE)
65#define MFEM_CUDA_or_HIP_REAL_T MFEM_CUDA_or_HIP(_R_64F)
73#ifdef MFEM_USE_CUDA_OR_HIP
79#ifndef MFEM_CUDA_1897_WORKAROUND
90#ifdef MFEM_USE_CUDA_OR_HIP
94 if (!
handle) { MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreate)(&
handle)); }
107#ifdef MFEM_USE_CUDA_OR_HIP
110#if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
111 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroySpMat)(
matA_descr));
112 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroyDnVec)(
vecX_descr));
113 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroyDnVec)(
vecY_descr));
136 for (
int i = 0; i < nrows; i++)
141#ifdef MFEM_USE_MEMALLOC
160#ifdef MFEM_USE_MEMALLOC
168 bool ownij,
bool owna,
bool issorted)
179#ifdef MFEM_USE_MEMALLOC
191 for (
int ii=0; ii<nnz; ++ii)
208#ifdef MFEM_USE_MEMALLOC
212 J.
New(nrows * rowsize);
213 A.
New(nrows * rowsize);
215 for (
int i = 0; i <= nrows; i++)
249#ifdef MFEM_USE_MEMALLOC
255#ifdef MFEM_USE_MEMALLOC
259 for (
int i = 0; i <
height; i++)
262 for (
RowNode *node_p = mat.
Rows[i]; node_p; node_p = node_p->Prev)
264#ifdef MFEM_USE_MEMALLOC
269 new_node_p->
Value = node_p->Value;
270 new_node_p->
Column = node_p->Column;
271 *node_pp = new_node_p;
272 node_pp = &new_node_p->
Prev;
300#ifdef MFEM_USE_MEMALLOC
307 for (
int i = 0; i <=
height; i++)
312 for (
int r=0; r<
height; r++)
339 MFEM_ASSERT(master.
Finalized(),
"'master' must be finalized");
360#ifdef MFEM_USE_MEMALLOC
378 return I[gi+1]-
I[gi];
383 for ( ; row != NULL; row = row->
Prev)
384 if (row->
Value != 0.0)
397 for (
int i=0; i <
height; ++i)
399 rowSize =
I[i+1]-
I[i];
400 max_row_size = (max_row_size > rowSize) ? max_row_size : rowSize;
405 for (
int i=0; i <
height; ++i)
408 max_row_size = (max_row_size > rowSize) ? max_row_size : rowSize;
417 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
424 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
431 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
438 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
445 if (newWidth ==
width)
450 else if (newWidth == -1)
456 else if (newWidth >
width)
467 ColPtrJ =
static_cast<int *
>(NULL);
475 "The new width needs to be bigger or equal to the actual width");
483 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
490#ifdef MFEM_USE_CUDA_OR_HIP
495 const int n =
Width();
497 const int *d_ia =
ReadI();
502 size_t pBufferSizeInBytes;
503 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseXcsrsort_bufferSizeExt)(
handle, m, n,
505 d_ja, &pBufferSizeInBytes));
506 void *pBuffer = MFEM_Cu_or_Hip(
MemAlloc)(&pBuffer, pBufferSizeInBytes);
510 MFEM_cu_or_hip(sparseMatDescr_t) sort_descr;
511 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateMatDescr)(&sort_descr));
515 int *d_P = P.
Write();
516 mfem::forall(nnzA, [=] MFEM_HOST_DEVICE (
int i) { d_P[i] = i; });
520 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseXcsrsort)(
handle, m, n, nnzA, sort_descr,
526 void *d_a_unsorted = MFEM_Cu_or_Hip(
MemAlloc)(&d_a_unsorted,
528 MFEM_Cu_or_Hip(MemcpyDtoD)(d_a_unsorted, d_a, nnzA *
sizeof(
real_t));
531 MFEM_cu_or_hip(sparseDnVecDescr_t) d_a_dense;
532 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateDnVec)(&d_a_dense, nnzA,
534 MFEM_CUDA_or_HIP_REAL_T));
537 MFEM_cu_or_hip(sparseSpVecDescr_t) d_a_sparse;
538 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateSpVec)(&d_a_sparse, nnzA, nnzA,
540 MFEM_CU_or_HIP(SPARSE_INDEX_32I),
541 MFEM_CU_or_HIP(SPARSE_INDEX_BASE_ZERO),
542 MFEM_CUDA_or_HIP_REAL_T));
545 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseGather)(
handle, d_a_dense, d_a_sparse));
551 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroyDnVec)(d_a_dense));
552 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroySpVec)(d_a_sparse));
553 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroyMatDescr)(sort_descr));
555 MFEM_Cu_or_Hip(MemFree)(d_a_unsorted);
556 MFEM_Cu_or_Hip(MemFree)(pBuffer);
566 for (
int j = 0, i = 0; i <
height; i++)
570 for (
int k = 0; k < row.
Size(); k++)
576 for (
int k = 0; k < row.
Size(); k++, j++)
588 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
590 for (
int row = 0, end = 0; row <
height; row++)
594 for (j = start;
true; j++)
596 MFEM_VERIFY(j < end,
"diagonal entry not found in row = " << row);
597 if (
J[j] == row) {
break; }
600 for ( ; j > start; j--)
622 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
623 "Trying to access element outside of the matrix. "
624 <<
"height = " <<
height <<
", "
625 <<
"width = " <<
width <<
", "
626 <<
"i = " << i <<
", "
629 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
631 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
639 MFEM_ABORT(
"Did not find i = " << i <<
", j = " << j <<
" in matrix.");
645 static const real_t zero = 0.0;
647 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
648 "Trying to access element outside of the matrix. "
649 <<
"height = " <<
height <<
", "
650 <<
"width = " <<
width <<
", "
651 <<
"i = " << i <<
", "
659 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
671 if (node_p->Column == j)
673 return node_p->Value;
683 MFEM_VERIFY(
height ==
width,
"Matrix must be square, not height = "
685 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
689 const auto II = this->
ReadI();
690 const auto JJ = this->
ReadJ();
696 const int begin = II[i];
697 const int end = II[i+1];
699 for (j = begin; j < end; j++)
717 int num_rows = this->
Height();
718 int num_cols = this->
Width();
733 for (
int r=0; r<
height; r++)
738 for (
int cj=0; cj<this->
RowSize(r); cj++)
740 B(r, col[cj]) = val[cj];
754 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
755 <<
") must match matrix width (" <<
width <<
")");
756 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
757 <<
") must match matrix height (" <<
height <<
")");
765 for (
int i = 0; i <
height; i++)
769 for ( ; row != NULL; row = row->
Prev)
779#ifndef MFEM_USE_LEGACY_OPENMP
783 auto d_J =
Read(
J, nnz);
784 auto d_A =
Read(
A, nnz);
789 if (nnz == 0) {
return;}
792#ifdef MFEM_USE_CUDA_OR_HIP
799#if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
801 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateCsr)(
805 const_cast<int *
>(d_I),
806 const_cast<int *
>(d_J),
807 const_cast<real_t *
>(d_A),
808 MFEM_CU_or_HIP(SPARSE_INDEX_32I),
809 MFEM_CU_or_HIP(SPARSE_INDEX_32I),
810 MFEM_CU_or_HIP(SPARSE_INDEX_BASE_ZERO),
811 MFEM_CUDA_or_HIP_REAL_T));
814 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateDnVec)(&
vecX_descr,
816 const_cast<real_t *
>(d_x),
817 MFEM_CUDA_or_HIP_REAL_T));
818 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseCreateDnVec)(&
vecY_descr, y.
Size(), d_y,
819 MFEM_CUDA_or_HIP_REAL_T));
822 cusparseSetMatIndexBase(
matA_descr, CUSPARSE_INDEX_BASE_ZERO);
823 cusparseSetMatType(
matA_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
828 size_t newBufferSize = 0;
830 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseSpMV_bufferSize)(
832 MFEM_CU_or_HIP(SPARSE_OPERATION_NON_TRANSPOSE),
838 MFEM_CUDA_or_HIP_REAL_T,
857#if HIP_VERSION_MAJOR >= 7
858 MFEM_CHECK_SPARSE(hipsparseSpMV_preprocess(
860 MFEM_CU_or_HIP(SPARSE_OPERATION_NON_TRANSPOSE),
866 MFEM_CUDA_or_HIP_REAL_T,
872#if CUDA_VERSION >= 10010 || defined(MFEM_USE_HIP)
874 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDnVecSetValues)(
vecX_descr,
875 const_cast<real_t *
>(d_x)));
876 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDnVecSetValues)(
vecY_descr, d_y));
879 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseSpMV)(
881 MFEM_CU_or_HIP(SPARSE_OPERATION_NON_TRANSPOSE),
887 MFEM_CUDA_or_HIP_REAL_T,
891#ifdef MFEM_USE_SINGLE
896 CUSPARSE_OPERATION_NON_TRANSPOSE,
902 const_cast<real_t *
>(d_A),
903 const_cast<int *
>(d_I),
904 const_cast<int *
>(d_J),
905 const_cast<real_t *
>(d_x),
917 const int end = d_I[i+1];
918 for (
int j = d_I[i]; j < end; j++)
920 d += d_A[j] * d_x[d_J[j]];
930 const int *Jp =
J, *Ip =
I;
932 #pragma omp parallel for
933 for (
int i = 0; i <
height; i++)
936 const int end = Ip[i+1];
937 for (
int j = Ip[i]; j < end; j++)
939 d += Ap[j] * xp[Jp[j]];
957 <<
") must match matrix height (" <<
height <<
")");
958 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
959 <<
") must match matrix width (" <<
width <<
")");
966 for (
int i = 0; i <
height; i++)
970 for ( ; row != NULL; row = row->
Prev)
989 const int nnz = Ip[
height];
993 for (
int i = 0; i <
height; i++)
996 const int end = Ip[i+1];
997 for (
int j = Ip[i]; j < end; j++)
999 const int Jj = Jp[j];
1000 yp[Jj] += Ap[j] * xi;
1031 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1033 const int n = rows.
Size();
1035 auto d_rows = rows.
Read();
1037 auto d_J =
Read(
J, nnz);
1038 auto d_A =
Read(
A, nnz);
1039 auto d_x = x.
Read();
1040 auto d_y = y.
Write();
1043 const int r = d_rows[i];
1044 const int end = d_I[r + 1];
1046 for (
int j = d_I[r]; j < end; j++)
1048 a += d_A[j] * d_x[d_J[j]];
1057 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1059 for (
int i = 0; i < rows.
Size(); i++)
1064 for (
int j =
I[r]; j < end; j++)
1066 val +=
A[j] * x(
J[j]);
1074 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
1075 MFEM_ASSERT(x.
Size() ==
Width(),
"Input vector size (" << x.
Size()
1076 <<
") must match matrix width (" <<
Width() <<
")");
1083 auto d_J =
Read(
J, nnz);
1089 const int end = d_I[i+1];
1090 for (
int j = d_I[i]; j < end; j++)
1105 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
1106 MFEM_ASSERT(x.
Size() ==
Height(),
"Input vector size (" << x.
Size()
1107 <<
") must match matrix height (" <<
Height() <<
")");
1117 for (
int i = 0; i <
Height(); i++)
1122 for (
int j =
I[i]; j < end; j++)
1132 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
1133 <<
") must match matrix width (" <<
width <<
")");
1134 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
1135 <<
") must match matrix height (" <<
height <<
")");
1146 for (
int i = 0; i <
height; i++)
1150 for ( ; row != NULL; row = row->
Prev)
1163 auto d_J =
Read(
J, nnz);
1164 auto d_A =
Read(
A, nnz);
1165 auto d_x = x.
Read();
1170 const int end = d_I[i+1];
1171 for (
int j = d_I[i]; j < end; j++)
1173 d += std::abs(d_A[j]) * d_x[d_J[j]];
1181 MFEM_ASSERT(
height == x.
Size(),
"Input vector size (" << x.
Size()
1182 <<
") must match matrix height (" <<
height <<
")");
1183 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
1184 <<
") must match matrix width (" <<
width <<
")");
1192 for (
int i = 0; i <
height; i++)
1196 for ( ; row != NULL; row = row->
Prev)
1211 for (
int i = 0; i <
height; i++)
1214 const int end =
I[i+1];
1215 for (
int j =
I[i]; j < end; j++)
1217 const int Jj =
J[j];
1218 y[Jj] += std::abs(
A[j]) * xi;
1227 <<
" must be equal to Width() = " <<
Width());
1229 <<
" must be equal to Height() = " <<
Height());
1242 for (
int i = 0; i <
height; i++)
1247 for (
int j =
I[i], end =
I[i+1]; j < end; j++)
1249 a +=
A[j] * x(
J[j]);
1256 a += np->Value * x(np->Column);
1271 auto d_x = x.
Write();
1275 for (
int j = d_I[i], end = d_I[i+1]; j < end; j++)
1284 for (
int i = 0; i <
height; i++)
1298 MFEM_VERIFY(irow <
height,
1299 "row " << irow <<
" not in matrix with height " <<
height);
1304 for (
int j =
I[irow], end =
I[irow+1]; j < end; j++)
1313 a += fabs(np->Value);
1322 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
1324 atol = std::abs(tol);
1326 fix_empty_rows =
height ==
width ? fix_empty_rows :
false;
1334 for (i = 0, nz = 0; i <
height; i++)
1337 for (j =
I[i]; j <
I[i+1]; j++)
1338 if (std::abs(
A[j]) > atol)
1343 if (fix_empty_rows && !found) { nz++; }
1351 for (i = 0, nz = 0; i <
height; i++)
1355 for (j =
I[i]; j <
I[i+1]; j++)
1356 if (std::abs(
A[j]) > atol)
1361 if ( lastCol > newJ[nz] )
1368 if (fix_empty_rows && !found)
1396 for (i = 1; i <=
height; i++)
1399 for (aux =
Rows[i-1]; aux != NULL; aux = aux->
Prev)
1401 if (skip_zeros && aux->
Value == 0.0)
1403 if (skip_zeros == 2) {
continue; }
1404 if ((i-1) != aux->
Column) {
continue; }
1410 if (other->Column == (i-1))
1413 found_val = other->Value;
1417 if (found && found_val == 0.0) {
continue; }
1422 if (fix_empty_rows && !nr) { nr = 1; }
1431 for (j = i = 0; i <
height; i++)
1435 for (aux =
Rows[i]; aux != NULL; aux = aux->
Prev)
1437 if (skip_zeros && aux->
Value == 0.0)
1439 if (skip_zeros == 2) {
continue; }
1440 if (i != aux->
Column) {
continue; }
1446 if (other->Column == i)
1449 found_val = other->Value;
1453 if (found && found_val == 0.0) {
continue; }
1459 if ( lastCol >
J[j] )
1468 if (fix_empty_rows && !nr)
1476#ifdef MFEM_USE_MEMALLOC
1480 for (i = 0; i <
height; i++)
1483 while (node_p != NULL)
1486 node_p = node_p->
Prev;
1499 int nr = (
height + br - 1)/br, nc = (
width + bc - 1)/bc;
1501 for (
int j = 0; j < bc; j++)
1503 for (
int i = 0; i < br; i++)
1506 for (
int k = 0; k <= nr; k++)
1510 blocks(i,j) =
new SparseMatrix(bI, NULL, NULL, nr, nc);
1514 for (
int gr = 0; gr <
height; gr++)
1516 int bi = gr/nr, i = gr%nr + 1;
1519 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1523 blocks(bi,
J[j]/nc)->I[i]++;
1531 if (n_p->Value != 0.0)
1533 blocks(bi, n_p->Column/nc)->I[i]++;
1539 for (
int j = 0; j < bc; j++)
1541 for (
int i = 0; i < br; i++)
1545 for (
int k = 1; k <= nr; k++)
1547 rs =
b.I[k],
b.I[k] = nnz, nnz += rs;
1554 for (
int gr = 0; gr <
height; gr++)
1556 int bi = gr/nr, i = gr%nr + 1;
1559 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1564 b.J[
b.I[i]] =
J[j] % nc;
1574 if (n_p->Value != 0.0)
1577 b.J[
b.I[i]] = n_p->Column % nc;
1578 b.A[
b.I[i]] = n_p->Value;
1600 for (
int i = 1; i <
height; i++)
1602 for (
int j =
I[i]; j <
I[i+1]; j++)
1606 symm = std::max(symm, std::abs(
A[j]-(*
this)(
J[j],i)));
1613 for (
int i = 0; i <
height; i++)
1615 for (
RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->
Prev)
1617 int col = node_p->Column;
1620 symm = std::max(symm, std::abs(node_p->Value-(*
this)(col,i)));
1630 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1633 for (i = 1; i <
height; i++)
1635 for (j =
I[i]; j <
I[i+1]; j++)
1639 A[j] += (*this)(
J[j],i);
1641 (*this)(
J[j],i) =
A[j];
1658 for (
int i = 0; i <
height; i++)
1660 for (
RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->
Prev)
1677 for (
int j = 0; j < nnz; j++)
1679 m = std::max(m, std::abs(
A[j]));
1684 for (
int i = 0; i <
height; i++)
1688 m = std::max(m, std::abs(n_p->Value));
1704 for (
int i = 0; i < nz; i++)
1706 counter += (std::abs(Ap[i]) <= tol);
1711 for (
int i = 0; i <
height; i++)
1715 counter += (std::abs(aux->Value) <= tol);
1736 for (
int i = 0; i <
height; i++)
1756 MFEM_ASSERT(row < height && row >= 0,
1757 "Row " << row <<
" not in matrix of height " <<
height);
1759 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
1761 for (aux =
Rows[row]; aux != NULL; aux = aux->
Prev)
1772 MFEM_ASSERT(row < height && row >= 0,
1773 "Row " << row <<
" not in matrix of height " <<
height);
1774 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1776 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1781 for (
int i=
I[row]; i <
I[row+1]; ++i)
1788 for (aux =
Rows[row]; aux != NULL; aux = aux->
Prev)
1802 MFEM_ASSERT(col < width && col >= 0,
1803 "Col " << col <<
" not in matrix of width " <<
width);
1804 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1806 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1812 for (
int jpos = 0; jpos != nnz; ++jpos)
1822 for (
int i = 0; i <
height; i++)
1826 if (aux->Column == col)
1846 for (
int i = 0; i <
height; i++)
1848 for (
int jpos =
I[i]; jpos !=
I[i+1]; ++jpos)
1854 (*b)(i) -=
A[jpos] * (*x)(
J[jpos] );
1863 for (
int i = 0; i <
height; i++)
1867 if (cols[aux -> Column])
1871 (*b)(i) -= aux -> Value * (*x)(aux -> Column);
1885 for (
int row = 0; row <
height; row++)
1887 for (nd =
Rows[row]; nd != NULL; nd = nd->
Prev)
1889 if (col_marker[nd->
Column])
1899 for (
int row = 0; row <
height; row++)
1901 for (
int j =
I[row]; j <
I[row+1]; j++)
1903 if (col_marker[
J[j]])
1905 Ae.
Add(row,
J[j],
A[j]);
1917 MFEM_ASSERT(rc < height && rc >= 0,
1918 "Row " << rc <<
" not in matrix of height " <<
height);
1925 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1927 const int col =
J[j];
1933 rhs(rc) =
A[j] *
sol;
1944 mfem_error(
"SparseMatrix::EliminateRowCol () #2");
1951 for (
int k =
I[col]; 1; k++)
1955 mfem_error(
"SparseMatrix::EliminateRowCol () #3");
1957 else if (
J[k] == rc)
1959 rhs(col) -=
sol *
A[k];
1971 const int col = aux->Column;
1977 rhs(rc) = aux->Value *
sol;
1988 mfem_error(
"SparseMatrix::EliminateRowCol () #4");
1999 mfem_error(
"SparseMatrix::EliminateRowCol () #5");
2001 else if (node->Column == rc)
2003 rhs(col) -=
sol * node->Value;
2017 MFEM_ASSERT(rc < height && rc >= 0,
2018 "Row " << rc <<
" not in matrix of height " <<
height);
2019 MFEM_ASSERT(
sol.Size() == rhs.
Width(),
"solution size (" <<
sol.Size()
2020 <<
") must match rhs width (" << rhs.
Width() <<
")");
2022 const int num_rhs = rhs.
Width();
2025 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2027 const int col =
J[j];
2033 for (
int r = 0; r < num_rhs; r++)
2035 rhs(rc,r) =
A[j] *
sol(r);
2040 for (
int r = 0; r < num_rhs; r++)
2047 for (
int r = 0; r < num_rhs; r++)
2053 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #3");
2060 for (
int k =
I[col]; 1; k++)
2064 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #4");
2066 else if (
J[k] == rc)
2068 for (
int r = 0; r < num_rhs; r++)
2070 rhs(col,r) -=
sol(r) *
A[k];
2083 const int col = aux->Column;
2089 for (
int r = 0; r < num_rhs; r++)
2091 rhs(rc,r) = aux->Value *
sol(r);
2096 for (
int r = 0; r < num_rhs; r++)
2103 for (
int r = 0; r < num_rhs; r++)
2109 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #5");
2120 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #6");
2122 else if (node->Column == rc)
2124 for (
int r = 0; r < num_rhs; r++)
2126 rhs(col,r) -=
sol(r) * node->Value;
2139 MFEM_ASSERT(rc < height && rc >= 0,
2140 "Row " << rc <<
" not in matrix of height " <<
height);
2144 const auto &II = this->
I;
2145 const auto &JJ = this->
J;
2146 for (
int j = II[rc]; j < II[rc+1]; j++)
2148 const int col = JJ[j];
2163 for (
int k = II[col]; 1; k++)
2167 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
2169 else if (JJ[k] == rc)
2182 for (aux =
Rows[rc]; aux != NULL; aux = aux->
Prev)
2184 const int col = aux->
Column;
2199 for (node =
Rows[col]; 1; node = node->
Prev)
2203 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
2205 else if (node->
Column == rc)
2220 MFEM_ASSERT(rc < height && rc >= 0,
2221 "Row " << rc <<
" not in matrix of height " <<
height);
2225 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2227 const int col =
J[j];
2235 for (
int k =
I[col]; 1; k++)
2239 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
2241 else if (
J[k] == rc)
2254 for (aux =
Rows[rc]; aux != NULL; aux = aux->
Prev)
2256 const int col = aux->
Column;
2264 for (node =
Rows[col]; 1; node = node->
Prev)
2268 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
2270 else if (node->
Column == rc)
2287 for (nd =
Rows[rc]; nd != NULL; nd = nd->
Prev)
2289 const int col = nd->
Column;
2305 mfem_error(
"SparseMatrix::EliminateRowCol #1");
2313 for (nd2 =
Rows[col]; 1; nd2 = nd2->
Prev)
2317 mfem_error(
"SparseMatrix::EliminateRowCol #2");
2319 else if (nd2->
Column == rc)
2331 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2333 const int col =
J[j];
2339 Ae.
Add(rc, rc,
A[j] - 1.0);
2343 Ae.
Add(rc, rc,
A[j]);
2349 mfem_error(
"SparseMatrix::EliminateRowCol #3");
2355 Ae.
Add(rc, col,
A[j]);
2357 for (
int k =
I[col];
true; k++)
2361 mfem_error(
"SparseMatrix::EliminateRowCol #4");
2363 else if (
J[k] == rc)
2365 Ae.
Add(col, rc,
A[k]);
2378 const int n_ess_dofs = ess_dofs.
Size();
2379 const auto ess_dofs_d = ess_dofs.
Read();
2380 const auto dI =
ReadI();
2381 const auto dJ =
ReadJ();
2386 const int idof = ess_dofs_d[i];
2387 for (
int j=dI[idof]; j<dI[idof+1]; ++j)
2389 const int jdof = dJ[j];
2393 for (
int k=dI[jdof]; k<dI[jdof+1]; ++k)
2420 for (
int i = 0; i <
height; i++)
2422 if (
I[i+1] ==
I[i]+1 && fabs(
A[
I[i]]) < 1e-16)
2431 for (
int i = 0; i <
height; i++)
2434 for (
int j =
I[i]; j <
I[i+1]; j++)
2438 if (zero <= threshold)
2440 for (
int j =
I[i]; j <
I[i+1]; j++)
2442 A[j] = (
J[j] == i) ? 1.0 : 0.0;
2457 for (
int i = 0; i < s; i++)
2461 for (n_p = R[i]; n_p != NULL; n_p = n_p->
Prev)
2463 const int c = n_p->
Column;
2470 sum += n_p->
Value * yp[c];
2474 if (diag_p != NULL && diag_p->
Value != 0.0)
2476 yp[i] = (xp[i] - sum) / diag_p->
Value;
2478 else if (xp[i] == sum)
2484 mfem_error(
"SparseMatrix::Gauss_Seidel_forw()");
2498 for (
int i = 0, j = Ip[0]; i < s; i++)
2500 const int end = Ip[i+1];
2503 for ( ; j < end; j++)
2505 const int c = Jp[j];
2512 sum += Ap[j] * yp[c];
2516 if (d >= 0 && Ap[d] != 0.0)
2518 yp[i] = (xp[i] - sum) / Ap[d];
2520 else if (xp[i] == sum)
2526 mfem_error(
"SparseMatrix::Gauss_Seidel_forw(...) #2");
2540 for (
int i =
height-1; i >= 0; i--)
2544 for (n_p = R[i]; n_p != NULL; n_p = n_p->
Prev)
2546 const int c = n_p->
Column;
2553 sum += n_p->
Value * yp[c];
2557 if (diag_p != NULL && diag_p->
Value != 0.0)
2559 yp[i] = (xp[i] - sum) / diag_p->
Value;
2561 else if (xp[i] == sum)
2567 mfem_error(
"SparseMatrix::Gauss_Seidel_back()");
2581 for (
int i = s-1, j = Ip[s]-1; i >= 0; i--)
2583 const int beg = Ip[i];
2586 for ( ; j >= beg; j--)
2588 const int c = Jp[j];
2595 sum += Ap[j] * yp[c];
2599 if (d >= 0 && Ap[d] != 0.0)
2601 yp[i] = (xp[i] - sum) / Ap[d];
2603 else if (xp[i] == sum)
2609 mfem_error(
"SparseMatrix::Gauss_Seidel_back(...) #2");
2617 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2620 for (
int i = 0; i <
height; i++)
2624 for (
int j =
I[i]; j <
I[i+1]; j++)
2632 if (d >= 0 &&
A[d] != 0.0)
2642 mfem_error(
"SparseMatrix::GetJacobiScaling() #2");
2649 real_t sc,
bool use_abs_diag)
const
2651 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2653 for (
int i = 0; i <
height; i++)
2657 for (
int j =
I[i]; j <
I[i+1]; j++)
2665 sum -=
A[j] * x0(
J[j]);
2668 if (d >= 0 &&
A[d] != 0.0)
2670 const real_t diag = (use_abs_diag) ? fabs(
A[d]) :
A[d];
2671 x1(i) = sc * (sum / diag) + (1.0 - sc) * x0(i);
2681 real_t sc,
bool use_abs_diag)
const
2683 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2687 const bool use_dev =
b.UseDevice() || x.
UseDevice();
2689 const auto Ap =
Read(
A, nnz, use_dev);
2691 const auto Jp =
Read(
J, nnz, use_dev);
2693 const auto bp =
b.Read(use_dev);
2694 auto xp = x.
Write(use_dev);
2698 const int end = Ip[i+1];
2699 for (
int j = Ip[i];
true; j++)
2703 MFEM_ABORT_KERNEL(
"Diagonal not found in SparseMatrix::DiagScale");
2707 const real_t diag = (use_abs_diag) ? fabs(Ap[j]) : Ap[j];
2710 MFEM_ABORT_KERNEL(
"Zero diagonal in SparseMatrix::DiagScale");
2712 xp[i] = sc * bp[i] / diag;
2719template <
bool useFabs>
2727 const auto bp =
b.Read(useDevice);
2728 const auto x0p = x0.
Read(useDevice);
2729 auto x1p = x1.
Write(useDevice);
2731 const auto Ip =
Read(I, height+1, useDevice);
2738 for (
int j = Ip[i]; j < Ip[i+1]; j++)
2740 resi -= Ap[j] * x0p[Jp[j]];
2743 norm += fabs(Ap[j]);
2752 x1p[i] = x0p[i] + sc * resi /
norm;
2758 MFEM_ABORT_KERNEL(
"L1 norm of row is zero.");
2762 MFEM_ABORT_KERNEL(
"sum of row is zero.");
2771 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2772 JacobiDispatch<true>(
b,x0,x1,
I,
J,
A,
height,sc);
2778 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2779 JacobiDispatch<false>(
b,x0,x1,
I,
J,
A,
height,sc);
2785 int i, j, gi, gj, s, t;
2795 for (i = 0; i < rows.
Size(); i++)
2797 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2800 "Trying to insert a row " << gi <<
" outside the matrix height "
2803 for (j = 0; j < cols.
Size(); j++)
2805 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2807 MFEM_ASSERT(gj <
width,
2808 "Trying to insert a column " << gj <<
" outside the matrix width "
2811 if (skip_zeros &&
a == 0.0)
2816 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2821 if (t < 0) {
a = -
a; }
2833 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2836 "Trying to set a row " << gi <<
" outside the matrix height "
2838 if ((gj=j) < 0) { gj = -1-gj, t = -s; }
2840 MFEM_ASSERT(gj <
width,
2841 "Trying to set a column " << gj <<
" outside the matrix width "
2843 if (t < 0) {
a = -
a; }
2852 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2855 "Trying to insert a row " << gi <<
" outside the matrix height "
2857 if ((gj=j) < 0) { gj = -1-gj, t = -s; }
2859 MFEM_ASSERT(gj <
width,
2860 "Trying to insert a column " << gj <<
" outside the matrix width "
2862 if (t < 0) {
a = -
a; }
2869 int i, j, gi, gj, s, t;
2872 for (i = 0; i < rows.
Size(); i++)
2874 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2877 "Trying to set a row " << gi <<
" outside the matrix height "
2880 for (j = 0; j < cols.
Size(); j++)
2883 if (skip_zeros &&
a == 0.0)
2888 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2893 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2895 MFEM_ASSERT(gj <
width,
2896 "Trying to set a column " << gj <<
" outside the matrix width "
2898 if (t < 0) {
a = -
a; }
2910 int i, j, gi, gj, s, t;
2913 for (i = 0; i < rows.
Size(); i++)
2915 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2918 "Trying to set a row " << gi <<
" outside the matrix height "
2921 for (j = 0; j < cols.
Size(); j++)
2924 if (skip_zeros &&
a == 0.0)
2929 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2934 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2936 MFEM_ASSERT(gj <
width,
2937 "Trying to set a column " << gj <<
" outside the matrix width "
2939 if (t < 0) {
a = -
a; }
2949 int i, j, gi, gj, s, t;
2952 for (i = 0; i < rows.
Size(); i++)
2954 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2957 "Trying to read a row " << gi <<
" outside the matrix height "
2960 for (j = 0; j < cols.
Size(); j++)
2962 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2964 MFEM_ASSERT(gj <
width,
2965 "Trying to read a column " << gj <<
" outside the matrix width "
2968 subm(i, j) = (t < 0) ? (-
a) : (
a);
2983 "Trying to query a row " << gi <<
" outside the matrix height "
2987 return (
Rows[gi] == NULL);
2991 return (
I[gi] ==
I[gi+1]);
3000 if ((gi=row) < 0) { gi = -1-gi; }
3002 "Trying to read a row " << gi <<
" outside the matrix height "
3006 for (n =
Rows[gi], j = 0; n; n = n->
Prev)
3012 for (n =
Rows[gi], j = 0; n; n = n->
Prev, j++)
3027 cols.
MakeRef(
const_cast<int*
>((
const int*)
J) + j,
I[gi+1]-j);
3030 MFEM_ASSERT(row >= 0,
"Row not valid: " << row <<
", height: " <<
height);
3041 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
3044 "Trying to set a row " << gi <<
" outside the matrix height "
3050 for (
int j = 0; j < cols.
Size(); j++)
3052 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
3054 MFEM_ASSERT(gj <
width,
3055 "Trying to set a column " << gj <<
" outside the matrix"
3056 " width " <<
width);
3058 if (t < 0) {
a = -
a; }
3066 MFEM_ASSERT(cols.
Size() == srow.
Size(),
"");
3068 for (
int i =
I[gi], j = 0; j < cols.
Size(); j++, i++)
3070 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
3072 MFEM_ASSERT(gj <
width,
3073 "Trying to set a column " << gj <<
" outside the matrix"
3074 " width " <<
width);
3085 int j, gi, gj, s, t;
3088 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
3090 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
3093 "Trying to insert a row " << gi <<
" outside the matrix height "
3096 for (j = 0; j < cols.
Size(); j++)
3098 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
3100 MFEM_ASSERT(gj <
width,
3101 "Trying to insert a column " << gj <<
" outside the matrix width "
3108 if (t < 0) {
a = -
a; }
3126 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
3128 aux -> Value *= scale;
3133 int j, end =
I[i+1];
3135 for (j =
I[i]; j < end; j++)
3148 for (
int i=0; i <
height; ++i)
3151 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
3153 aux -> Value *= scale;
3161 for (
int i=0; i <
height; ++i)
3165 for (j =
I[i]; j < end; j++)
3178 for (
int i=0; i <
height; ++i)
3180 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
3182 aux -> Value *= sr(aux->
Column);
3190 for (
int i=0; i <
height; ++i)
3193 for (j =
I[i]; j < end; j++)
3204 "Mismatch of this matrix size and rhs. This height = "
3205 <<
height <<
", width = " <<
width <<
", B.height = "
3208 for (
int i = 0; i <
height; i++)
3213 for (
RowNode *aux = B.
Rows[i]; aux != NULL; aux = aux->Prev)
3215 _Add_(aux->Column, aux->Value);
3220 for (
int j = B.
I[i]; j < B.
I[i+1]; j++)
3233 for (
int i = 0; i <
height; i++)
3240 np->Value +=
a * B.
_Get_(np->Column);
3245 for (
int j =
I[i]; j <
I[i+1]; j++)
3260 for (
int i = 0; i < nnz; i++)
3267 for (
int i = 0; i <
height; i++)
3270 node_p = node_p -> Prev)
3272 node_p -> Value =
a;
3284 for (
int i = 0, nnz =
I[
height]; i < nnz; i++)
3291 for (
int i = 0; i <
height; i++)
3294 node_p = node_p -> Prev)
3296 node_p -> Value *=
a;
3311 for (i = 0; i <
height; i++)
3313 os <<
"[row " << i <<
"]\n";
3314 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->
Prev, j++)
3316 os <<
" (" << nd->
Column <<
"," << nd->
Value <<
")";
3317 if ( !((j+1) % width_) )
3334 for (i = 0; i <
height; i++)
3336 os <<
"[row " << i <<
"]\n";
3337 for (j =
I[i]; j <
I[i+1]; j++)
3339 os <<
" (" <<
J[j] <<
"," <<
A[j] <<
")";
3340 if ( !((j+1-
I[i]) % width_) )
3345 if ((j-
I[i]) % width_)
3354 os <<
"% size " <<
height <<
" " <<
width <<
"\n";
3358 ios::fmtflags old_fmt = os.flags();
3359 os.setf(ios::scientific);
3360 std::streamsize old_prec = os.precision(14);
3365 for (i = 0; i <
height; i++)
3367 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->
Prev, j++)
3369 os << i+1 <<
" " << nd->
Column+1 <<
" " << nd->
Value <<
'\n';
3379 for (i = 0; i <
height; i++)
3381 for (j =
I[i]; j <
I[i+1]; j++)
3383 os << i+1 <<
" " <<
J[j]+1 <<
" " <<
A[j] <<
'\n';
3389 os.precision(old_prec);
3396 ios::fmtflags old_fmt = os.flags();
3397 os.setf(ios::scientific);
3398 std::streamsize old_prec = os.precision(14);
3400 os <<
"(* Read file into Mathematica using: "
3401 <<
"myMat = Get[\"this_file_name\"] *)\n";
3402 os <<
"SparseArray[";
3409 for (i = 0; i <
height; i++)
3411 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->
Prev, j++, c++)
3413 os <<
"{"<< i+1 <<
", " << nd->
Column+1
3414 <<
"} -> Internal`StringToMReal[\"" << nd->
Value <<
"\"]";
3429 for (i = 0; i <
height; i++)
3431 for (j =
I[i]; j <
I[i+1]; j++, c++)
3433 os <<
"{" << i+1 <<
", " <<
J[j]+1
3434 <<
"} -> Internal`StringToMReal[\"" <<
A[j] <<
"\"]";
3444 os.precision(old_prec);
3451 ios::fmtflags old_fmt = os.flags();
3452 os.setf(ios::scientific);
3453 std::streamsize old_prec = os.precision(14);
3455 os <<
"%%MatrixMarket matrix coordinate real general" <<
'\n'
3456 <<
"% Generated by MFEM" <<
'\n';
3463 for (i = 0; i <
height; i++)
3465 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->
Prev, j++)
3467 os << i+1 <<
" " << nd->
Column+1 <<
" " << nd->
Value <<
'\n';
3477 for (i = 0; i <
height; i++)
3479 for (j =
I[i]; j <
I[i+1]; j++)
3481 os << i+1 <<
" " <<
J[j]+1 <<
" " <<
A[j] <<
'\n';
3485 os.precision(old_prec);
3491 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3501 for (i = 0; i <=
height; i++)
3503 os <<
I[i]+1 <<
'\n';
3506 for (i = 0; i <
I[
height]; i++)
3508 os <<
J[i]+1 <<
'\n';
3511 for (i = 0; i <
I[
height]; i++)
3519 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3524 os <<
width <<
'\n';
3530 for (i = 0; i <=
height; i++)
3535 for (i = 0; i <
I[
height]; i++)
3540 for (i = 0; i <
I[
height]; i++)
3548 const real_t MiB = 1024.*1024;
3560 "SparseMatrix statistics:\n"
3563 " Dimensions : " <<
height <<
" x " <<
width <<
"\n"
3564 " Number of entries (total) : " << nnz <<
"\n"
3565 " Number of entries (per row) : " << 1.*nnz/
Height() <<
"\n"
3566 " Number of stored zeros : " << nz*pz <<
"% (" << nz <<
")\n"
3567 " Number of Inf/Nan entries : " << nnf*pz <<
"% ("<< nnf <<
")\n"
3568 " Norm, max |a_ij| : " << max_norm <<
"\n"
3569 " Symmetry, max |a_ij-a_ji| : " << symm <<
"\n"
3570 " Number of small entries:\n"
3571 " |a_ij| <= 1e-12*Norm : " << ns12*pz <<
"% (" << ns12 <<
")\n"
3572 " |a_ij| <= 1e-15*Norm : " << ns15*pz <<
"% (" << ns15 <<
")\n"
3573 " |a_ij| <= 1e-18*Norm : " << ns18*pz <<
"% (" << ns18 <<
")\n";
3576 os <<
" Memory used by CSR : " <<
3577 (
sizeof(int)*(
height+1+nnz)+
sizeof(
real_t)*nnz)/MiB <<
" MiB\n";
3582#ifdef MFEM_USE_MEMALLOC
3585 for (
int i = 0; i <
height; i++)
3593 os <<
" Memory used by LIL : " << used_mem/MiB <<
" MiB\n";
3605#if !defined(MFEM_USE_MEMALLOC)
3606 for (
int i = 0; i <
height; i++)
3609 while (node_p != NULL)
3612 node_p = node_p->
Prev;
3622#ifdef MFEM_USE_MEMALLOC
3635 const int *start_j =
J;
3637 for (
const int *jptr = start_j; jptr != end_j; ++jptr)
3639 awidth = std::max(awidth, *jptr + 1);
3645 for (
int i = 0; i <
height; i++)
3647 for (aux =
Rows[i]; aux != NULL; aux = aux->
Prev)
3649 awidth = std::max(awidth, aux->
Column + 1);
3661 for (
int i = 0; i < n; i++)
3671 "Finalize must be called before Transpose. Use TransposeRowMatrix instead");
3674 const int *A_i, *A_j;
3675 int m, n, nnz, *At_i, *At_j;
3690 for (i = 0; i <= n; i++)
3694 for (i = 0; i < nnz; i++)
3698 for (i = 1; i < n; i++)
3700 At_i[i+1] += At_i[i];
3703 for (i = j = 0; i < m; i++)
3706 for ( ; j < end; j++)
3708 At_j[At_i[A_j[j]]] = i;
3709 At_data[At_i[A_j[j]]] = A_data[j];
3714 for (i = n; i > 0; i--)
3716 At_i[i] = At_i[i-1];
3727 int m, n, nnz, *At_i, *At_j;
3737 for (i = 0; i < m; i++)
3739 A.
GetRow(i, Acols, Avals);
3761 for (i = 0; i <= n; i++)
3766 for (i = 0; i < m; i++)
3768 A.
GetRow(i, Acols, Avals);
3769 for (j = 0; j<Acols.
Size(); ++j)
3774 for (i = 1; i < n; i++)
3776 At_i[i+1] += At_i[i];
3779 for (i = 0; i < m; i++)
3781 A.
GetRow(i, Acols, Avals);
3782 for (j = 0; j<Acols.
Size(); ++j)
3784 At_j[At_i[Acols[j]]] = i;
3785 At_data[At_i[Acols[j]]] = Avals[j];
3790 for (i = n; i > 0; i--)
3792 At_i[i] = At_i[i-1];
3803 int nrowsA, ncolsA, nrowsB, ncolsB;
3804 const int *A_i, *A_j, *B_i, *B_j;
3805 int *C_i, *C_j, *B_marker;
3806 const real_t *A_data, *B_data;
3808 int ia, ib, ic, ja, jb, num_nonzeros;
3809 int row_start, counter;
3818 MFEM_VERIFY(ncolsA == nrowsB,
3819 "number of columns of A (" << ncolsA
3820 <<
") must equal number of rows of B (" << nrowsB <<
")");
3829 B_marker =
new int[ncolsB];
3831 for (ib = 0; ib < ncolsB; ib++)
3840 C_i[0] = num_nonzeros = 0;
3841 for (ic = 0; ic < nrowsA; ic++)
3843 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3846 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3849 if (B_marker[jb] != ic)
3856 C_i[ic+1] = num_nonzeros;
3862 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3864 for (ib = 0; ib < ncolsB; ib++)
3873 MFEM_VERIFY(nrowsA == C->
Height() && ncolsB == C->
Width(),
3874 "Input matrix sizes do not match output sizes"
3875 <<
" nrowsA = " << nrowsA
3876 <<
", C->Height() = " << C->
Height()
3877 <<
" ncolsB = " << ncolsB
3878 <<
", C->Width() = " << C->
Width());
3886 for (ic = 0; ic < nrowsA; ic++)
3889 row_start = counter;
3890 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3893 a_entry = A_data[ia];
3894 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3897 b_entry = B_data[ib];
3898 if (B_marker[jb] < row_start)
3900 B_marker[jb] = counter;
3905 C_data[counter] = a_entry*b_entry;
3910 C_data[B_marker[jb]] += a_entry*b_entry;
3918 "With pre-allocated output matrix, number of non-zeros ("
3920 <<
") did not match number of entries changed from matrix-matrix multiply, "
3939 int nrowsA, ncolsA, nrowsB, ncolsB;
3940 int *C_i, *C_j, *B_marker;
3942 int ia, ib, ic, ja, jb, num_nonzeros;
3943 int row_start, counter;
3952 MFEM_VERIFY(ncolsA == nrowsB,
3953 "number of columns of A (" << ncolsA
3954 <<
") must equal number of rows of B (" << nrowsB <<
")");
3956 B_marker =
new int[ncolsB];
3958 for (ib = 0; ib < ncolsB; ib++)
3965 C_i[0] = num_nonzeros = 0;
3969 for (ic = 0; ic < nrowsA; ic++)
3971 A.
GetRow(ic, colsA, dataA);
3972 for (ia = 0; ia < colsA.
Size(); ia++)
3975 B.
GetRow(ja, colsB, dataB);
3976 for (ib = 0; ib < colsB.
Size(); ib++)
3979 if (B_marker[jb] != ic)
3986 C_i[ic+1] = num_nonzeros;
3992 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3994 for (ib = 0; ib < ncolsB; ib++)
4000 for (ic = 0; ic < nrowsA; ic++)
4002 row_start = counter;
4003 A.
GetRow(ic, colsA, dataA);
4004 for (ia = 0; ia < colsA.
Size(); ia++)
4007 a_entry = dataA[ia];
4008 B.
GetRow(ja, colsB, dataB);
4009 for (ib = 0; ib < colsB.
Size(); ib++)
4012 b_entry = dataB[ib];
4013 if (B_marker[jb] < row_start)
4015 B_marker[jb] = counter;
4017 C_data[counter] = a_entry*b_entry;
4022 C_data[B_marker[jb]] += a_entry*b_entry;
4037 for (
int j = 0; j < B.
Width(); ++j)
4041 A.
Mult(columnB, columnC);
4051 Mult (R, *AP, *RAP_);
4094 int i, At_nnz, *At_j;
4098 At_nnz = At -> NumNonZeroElems();
4099 At_j = At -> GetJ();
4100 At_data = At -> GetData();
4101 for (i = 0; i < At_nnz; i++)
4103 At_data[i] *= D(At_j[i]);
4114 int ncols = A.
Width();
4128 int * marker =
new int[ncols];
4129 std::fill(marker, marker+ncols, -1);
4131 int num_nonzeros = 0, jcol;
4133 for (
int ic = 0; ic < nrows; ic++)
4135 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
4141 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
4144 if (marker[jcol] != ic)
4150 C_i[ic+1] = num_nonzeros;
4156 for (
int ia = 0; ia < ncols; ia++)
4162 for (
int ic = 0; ic < nrows; ic++)
4164 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
4168 C_data[pos] =
a*A_data[ia];
4172 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
4175 if (marker[jcol] < C_i[ic])
4178 C_data[pos] =
b*B_data[ib];
4184 C_data[marker[jcol]] +=
b*B_data[ib];
4190 return new SparseMatrix(C_i, C_j, C_data, nrows, ncols);
4195 return Add(1.,A,1.,B);
4200 MFEM_ASSERT(Ai.
Size() > 0,
"invalid size Ai.Size() = " << Ai.
Size());
4205 for (
int i=1; i < Ai.
Size(); ++i)
4207 result =
Add(*accumulate, *Ai[i]);
4213 accumulate = result;
4223 for (
int r = 0; r < B.
Height(); r++)
4227 for (
int i=0; i<A.
RowSize(r); i++)
4229 B(r, colA[i]) +=
alpha * valA[i];
4242 for (
int i=0; i<mA; i++)
4244 for (
int j=0; j<nA; j++)
4246 C->
AddMatrix(A(i,j), B, i * mB, j * nB);
4260 for (
int i=0; i<mA; i++)
4262 for (
int j=0; j<nA; j++)
4264 for (
int r=0; r<mB; r++)
4269 for (
int cj=0; cj<B.
RowSize(r); cj++)
4271 C->
Set(i * mB + r, j * nB + colB[cj], A(i,j) * valB[cj]);
4289 for (
int r=0; r<mA; r++)
4294 for (
int aj=0; aj<A.
RowSize(r); aj++)
4296 for (
int i=0; i<mB; i++)
4298 for (
int j=0; j<nB; j++)
4300 C->
Set(r * mB + i, colA[aj] * nB + j, valA[aj] * B(i, j));
4318 for (
int ar=0; ar<mA; ar++)
4323 for (
int aj=0; aj<A.
RowSize(ar); aj++)
4325 for (
int br=0; br<mB; br++)
4330 for (
int bj=0; bj<B.
RowSize(br); bj++)
4332 C->
Set(ar * mB + br, colA[aj] * nB + colB[bj],
4333 valA[aj] * valB[bj]);
4356#ifdef MFEM_USE_MEMALLOC
4366#ifdef MFEM_USE_CUDA_OR_HIP
4369#ifdef MFEM_CUDA_1897_WORKAROUND
4372 MFEM_Cu_or_Hip(MemFree)(
dBuffer);
4381 MFEM_CHECK_SPARSE(MFEM_cu_or_hip(sparseDestroy)(
handle));
4384#ifndef MFEM_CUDA_1897_WORKAROUND
4387 MFEM_Cu_or_Hip(MemFree)(
dBuffer);
Abstract data type for sparse matrices.
virtual int NumNonZeroElems() const =0
Returns the number of non-zeros in a matrix.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const =0
Gets the columns indexes and values for row row.
Dynamic 2D array using row-major layout.
Memory< T > & GetMemory()
Return a reference to the Memory object used by the Array.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Data type dense matrix using column-major storage.
void GetColumnReference(int c, Vector &col)
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0<=i.
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Abstract data type for matrix inverse.
size_t MemoryUsage() const
Class used by MFEM to store pointers to host and/or device memory.
void SetHostPtrOwner(bool own) const
Set/clear the ownership flag for the host pointer. Ownership indicates whether the pointer will be de...
int Capacity() const
Return the size of the allocated memory.
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
bool Empty() const
Return true if the Memory object is empty, see Reset().
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
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 Delete()
Delete the owned pointers and reset the Memory object.
void ClearOwnerFlags() const
Clear the ownership flags for the host and device pointers, as well as any internal data allocated by...
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
@ DIAG_ONE
Set the diagonal value to one.
@ DIAG_KEEP
Keep the diagonal value.
@ DIAG_ZERO
Set the diagonal value to zero.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
int GetRow(const int row, Array< int > &cols, Vector &srow) const override
Extract all column indices and values from a given row.
void PrintCSR2(std::ostream &out) const
Prints a sparse matrix to stream out in CSR format.
const int * HostReadJ() const
void GetDiag(Vector &d) const
Returns the Diagonal of A.
real_t GetRowNorml1(int irow) const
For i = irow compute .
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
bool isSorted
Are the columns sorted already.
void Gauss_Seidel_back(const Vector &x, Vector &y) const
bool RowIsEmpty(const int row) const
void ClearColPtr() const
Reset the "current row" set by calling SetColPtr(). This method must be called between any two calls ...
MatrixInverse * Inverse() const override
This virtual method is not supported: it always returns NULL.
void Jacobi3(const Vector &b, const Vector &x0, Vector &x1, real_t sc=1.0) const
real_t * ReadWriteData(bool on_dev=true)
Memory< real_t > A
Array with size I[height], containing the actual entries of the sparse matrix, as indexed by the I ar...
void EliminateRowCol(int rc, const real_t sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate row rc and column rc and modify the rhs using sol.
SparseMatrix & operator*=(real_t a)
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
void SetWidth(int width_=-1)
Change the width of a SparseMatrix.
MemAlloc< RowNode, 1024 > RowNodeAlloc
bool Empty() const
Check if the SparseMatrix is empty.
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm) const
SparseMatrix * At
Transpose of A. Owned. Used to perform MultTranspose() on devices.
void PartAddMult(const Array< int > &rows, const Vector &x, Vector &y, const real_t a=1.0) const
void GetRowSums(Vector &x) const
For all i compute .
void AbsMult(const Vector &x, Vector &y) const override
y = |A| * x, using entry-wise absolute values of matrix A
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
bool Finalized() const
Returns whether or not CSR format has been finalized.
void EliminateBC(const Array< int > &ess_dofs, DiagonalPolicy diag_policy)
Eliminate essential (Dirichlet) boundary conditions.
void PrintInfo(std::ostream &out) const
Print various sparse matrix statistics.
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 int i, const int j, const real_t val)
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...
void Jacobi(const Vector &b, const Vector &x0, Vector &x1, real_t sc, bool use_abs_diag=false) const
void SetColPtr(const int row) const
Initialize the SparseMatrix for fast access to the entries of the given row which becomes the "curren...
void SetDiagIdentity()
If a row contains only one diag entry of zero, set it to 1.
void Gauss_Seidel_forw(const Vector &x, Vector &y) const
Gauss-Seidel forward and backward iterations over a vector x.
void MakeRef(const SparseMatrix &master)
Clear the contents of the SparseMatrix and make it a reference to master.
int CheckFinite() const
Count the number of entries that are NOT finite, i.e. Inf or Nan.
Memory< int > J
Array with size I[height], containing the column indices for all matrix entries, as indexed by the I ...
void EliminateCol(int col, DiagonalPolicy dpolicy=DIAG_ZERO)
Eliminates the column col from the matrix.
void EnsureMultTranspose() const
Ensures that the matrix is capable of performing MultTranspose(), AddMultTranspose(),...
void Print(std::ostream &out=mfem::out, int width_=4) const override
Prints matrix to stream out.
void _Add_(const int col, const real_t a)
Add a value to an entry in the "current row". See SetColPtr().
SparseMatrix()
Create an empty SparseMatrix.
cusparseSpMatDescr_t matA_descr
real_t & Elem(int i, int j) override
Returns reference to a_{ij}.
virtual void PrintMathematica(std::ostream &out=mfem::out) const
Prints matrix as a SparseArray for importing into Mathematica.
void ClearGPUSparse()
Clear the cuSPARSE/hipSPARSE descriptors. This must be called after releasing the device memory of A.
void Threshold(real_t tol, bool fix_empty_rows=false)
Remove entries smaller in absolute value than a given tolerance tol. If fix_empty_rows is true,...
void SetSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void PrintMatlab(std::ostream &out=mfem::out) const override
Prints matrix in matlab format.
const int * ReadI(bool on_dev=true) const
real_t InnerProduct(const Vector &x, const Vector &y) const
Compute y^t A x.
Memory< int > I
Array with size (height+1) containing the row offsets.
real_t & operator()(int i, int j)
Returns reference to A[i][j].
const real_t * HostReadData() const
void PrintMM(std::ostream &out=mfem::out) const
Prints matrix in Matrix Market sparse format.
void ScaleColumns(const Vector &sr)
this = this * diag(sr);
void PrintCSR(std::ostream &out) const
Prints matrix to stream out in hypre_CSRMatrix format.
void Swap(SparseMatrix &other)
int * ReadWriteJ(bool on_dev=true)
cusparseDnVecDescr_t vecY_descr
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
RowNode ** Rows
Array of linked lists, one for every row. This array represents the linked list (LIL) storage format.
real_t & SearchRow(const int col)
Perform a fast search for an entry in the "current row". See SetColPtr().
static int SparseMatrixCount
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void Symmetrize()
(*this) = 1/2 ((*this) + (*this)^t)
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
y += At * x (default) or y += a * At * x
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
real_t GetJacobiScaling() const
Determine appropriate scaling for Jacobi iteration.
int RowSize(const int i) const
Returns the number of elements in row i.
real_t * HostReadWriteData()
int CountSmallElems(real_t tol) const
Count the number of entries with |a_ij| <= tol.
const int * ReadJ(bool on_dev=true) const
int MaxRowSize() const
Returns the maximum number of elements among all rows.
real_t _Get_(const int col) const
Read the value of an entry in the "current row". See SetColPtr().
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
y += A * x (default) or y += a * A * x
virtual ~SparseMatrix()
Destroys sparse matrix.
SparseMatrix & operator=(const SparseMatrix &rhs)
Assignment operator: deep copy.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
void OverrideSize(int height_, int width_)
Sets the height and width of the matrix.
static cusparseHandle_t handle
void EliminateRow(int row, const real_t sol, Vector &rhs)
Eliminates a column from the transpose matrix.
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
SparseMatrix & operator+=(const SparseMatrix &B)
Add the sparse matrix 'B' to '*this'. This operation will cause an error if '*this' is finalized and ...
void Clear()
Clear the contents of the SparseMatrix.
void ResetTranspose() const
void EliminateRowColDiag(int rc, real_t value)
Perform elimination and set the diagonal entry to the given value.
real_t * GetRowEntries(const int row)
Return a pointer to the entries in a row.
void ScaleRows(const Vector &sl)
this = diag(sl) * this;
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
void DiagScale(const Vector &b, Vector &x, real_t sc=1.0, bool use_abs_diag=false) const
x = sc b / A_ii. When use_abs_diag = true, |A_ii| is used.
void AbsMultTranspose(const Vector &x, Vector &y) const override
y = |At| * x, using entry-wise absolute values of the transpose of matrix A
real_t * GetData()
Return the element data, i.e. the array A.
void SetSubMatrixTranspose(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void BuildTranspose() const
Build and store internally the transpose of this matrix which will be used in the methods AddMultTran...
void SortColumnIndices()
Sort the column indices corresponding to each row.
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
real_t IsSymmetric() const
Returns max_{i,j} |(i,j)-(j,i)| for a finalized matrix.
DenseMatrix * ToDenseMatrix() const
Produces a DenseMatrix from a SparseMatrix.
void _Set_(const int col, const real_t a)
Set an entry in the "current row". See SetColPtr().
void EliminateZeroRows(const real_t threshold=1e-12) override
If a row contains only zeros, set its diagonal to 1.
void EliminateCols(const Array< int > &cols, const Vector *x=NULL, Vector *b=NULL)
Eliminate all columns i for which cols[i] != 0.
cusparseDnVecDescr_t vecX_descr
const real_t * ReadData(bool on_dev=true) const
void ScaleRow(const int row, const real_t scale)
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
void Jacobi2(const Vector &b, const Vector &x0, Vector &x1, real_t sc=1.0) const
static bool use_gpu_vendor_sparse_if_available
Use the GPU vendor sparse library (cusparse/hipsparse), if available, for sparse matrix operations....
int ActualWidth() const
Returns the actual Width of the matrix.
const int * HostReadI() const
void Set(const int i, const int j, const real_t val)
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void Neg()
(*this) = -(*this)
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
int Size() const
Returns the size of the vector.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void SetSize(int s)
Resize the vector to size s.
void NewDataAndSize(real_t *d, int s)
Set the Vector data and size, deleting the old data, if owned.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
DenseMatrix * OuterProduct(const DenseMatrix &A, const DenseMatrix &B)
Produces a block matrix with blocks A_{ij}*B.
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 mfem_error(const char *msg)
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
const T * HostRead(const Memory< T > &mem, int size)
Shortcut to Read(const Memory<T> &mem, int size, false)
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,...
bool IsFinite(const real_t &val)
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
int CheckFinite(const real_t *v, const int n)
T * HostWrite(Memory< T > &mem, int size)
Shortcut to Write(const Memory<T> &mem, int size, false)
SparseMatrix * MultAbstractSparseMatrix(const AbstractSparseMatrix &A, const AbstractSparseMatrix &B)
Matrix product of sparse matrices. A and B do not need to be CSR matrices.
SparseMatrix * TransposeAbstractSparseMatrix(const AbstractSparseMatrix &A, int useActualWidth)
Transpose of a sparse matrix. A does not need to be a CSR matrix.
SparseMatrix * Mult_AtDA(const SparseMatrix &A, const Vector &D, SparseMatrix *OAtDA)
Matrix multiplication A^t D A. All matrices must be finalized.
MemoryType
Memory types supported by MFEM.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
SparseMatrix * TransposeMult(const SparseMatrix &A, const SparseMatrix &B)
C = A^T B.
void forall(int N, lambda &&body)
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
void forall_switch(bool use_dev, int N, lambda &&body)
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
void SparseMatrixFunction(SparseMatrix &S, real_t(*f)(real_t))
Applies f() to each element of the matrix (after it is finalized).
real_t sol(const Vector &x)
MFEM_HOST_DEVICE real_t norm(const Complex &z)
@ HIP_MASK
Biwise-OR of all HIP backends.
@ CPU_MASK
Biwise-OR of all CPU backends.
@ CUDA_MASK
Biwise-OR of all CUDA backends.