15 #include "../general/forall.hpp"
16 #include "../general/table.hpp"
17 #include "../general/sort_pairs.hpp"
44 if (!handle) { cusparseCreate(&handle); }
60 #if CUDA_VERSION >= 10010
61 cusparseDestroySpMat(matA_descr);
62 cusparseDestroyDnVec(vecX_descr);
63 cusparseDestroyDnVec(vecY_descr);
65 cusparseDestroyMatDescr(matA_descr);
74 Rows(new RowNode *[nrows]),
86 for (
int i = 0; i < nrows; i++)
91 #ifdef MFEM_USE_MEMALLOC
108 A.
Wrap(data,
I[height],
true);
110 #ifdef MFEM_USE_MEMALLOC
118 bool ownij,
bool owna,
bool issorted)
129 #ifdef MFEM_USE_MEMALLOC
135 A.
Wrap(data,
I[height], owna);
141 for (
int i=0; i<nnz; ++i)
158 #ifdef MFEM_USE_MEMALLOC
162 J.
New(nrows * rowsize);
163 A.
New(nrows * rowsize);
165 for (
int i = 0; i <= nrows; i++)
198 #ifdef MFEM_USE_MEMALLOC
204 #ifdef MFEM_USE_MEMALLOC
208 for (
int i = 0; i <
height; i++)
210 RowNode **node_pp = &
Rows[i];
211 for (RowNode *node_p = mat.
Rows[i]; node_p; node_p = node_p->Prev)
213 #ifdef MFEM_USE_MEMALLOC
216 RowNode *new_node_p =
new RowNode;
218 new_node_p->Value = node_p->Value;
219 new_node_p->Column = node_p->Column;
220 *node_pp = new_node_p;
221 node_pp = &new_node_p->Prev;
249 #ifdef MFEM_USE_MEMALLOC
256 for (
int i = 0; i <=
height; i++)
261 for (
int r=0; r<
height; r++)
282 MFEM_ASSERT(master.
Finalized(),
"'master' must be finalized");
303 #ifdef MFEM_USE_MEMALLOC
321 return I[gi+1]-
I[gi];
325 RowNode *row =
Rows[gi];
326 for ( ; row != NULL; row = row->Prev)
327 if (row->Value != 0.0)
340 for (
int i=0; i <
height; ++i)
342 rowSize =
I[i+1]-
I[i];
343 out = (out > rowSize) ? out : rowSize;
348 for (
int i=0; i <
height; ++i)
351 out = (out > rowSize) ? out : rowSize;
360 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
367 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
374 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
381 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
388 if (newWidth ==
width)
393 else if (newWidth == -1)
399 else if (newWidth >
width)
410 ColPtrJ =
static_cast<int *
>(NULL);
418 "The new width needs to be bigger or equal to the actual width");
426 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
438 for (
int j = 0, i = 0; i <
height; i++)
442 for (
int k = 0; k < row.
Size(); k++)
448 for (
int k = 0; k < row.
Size(); k++, j++)
459 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
461 for (
int row = 0, end = 0; row <
height; row++)
465 for (j = start;
true; j++)
467 MFEM_VERIFY(j < end,
"diagonal entry not found in row = " << row);
468 if (
J[j] == row) {
break; }
470 const double diag =
A[j];
471 for ( ; j > start; j--)
493 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
494 "Trying to access element outside of the matrix. "
495 <<
"height = " <<
height <<
", "
496 <<
"width = " <<
width <<
", "
497 <<
"i = " << i <<
", "
500 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
502 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
510 MFEM_ABORT(
"Did not find i = " << i <<
", j = " << j <<
" in matrix.");
516 static const double zero = 0.0;
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 <<
", "
527 for (
int k =
I[i], end =
I[i+1]; k < end; k++)
537 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
539 if (node_p->Column == j)
541 return node_p->Value;
551 MFEM_VERIFY(
height ==
width,
"Matrix must be square, not height = "
553 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
557 const auto I = this->
ReadI();
558 const auto J = this->
ReadJ();
564 const int begin =
I[i];
565 const int end =
I[i+1];
567 for (j = begin; j < end; j++)
585 int num_rows = this->
Height();
586 int num_cols = this->
Width();
601 for (
int r=0; r<
height; r++)
606 for (
int cj=0; cj<this->
RowSize(r); cj++)
608 B(r, col[cj]) = val[cj];
622 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
623 <<
") must match matrix width (" <<
width <<
")");
624 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
625 <<
") must match matrix height (" <<
height <<
")");
633 for (
int i = 0; i <
height; i++)
635 RowNode *row =
Rows[i];
637 for ( ; row != NULL; row = row->Prev)
639 b += row->Value * xp[row->Column];
647 #ifndef MFEM_USE_LEGACY_OPENMP
650 auto d_I =
Read(
I, height+1);
651 auto d_J =
Read(
J, nnz);
652 auto d_A =
Read(
A, nnz);
657 if (nnz == 0) {
return;}
662 const double beta = 1.0;
667 #if CUDA_VERSION >= 10010
670 const_cast<int *
>(d_I),
671 const_cast<int *>(d_J),
const_cast<double *
>(d_A), CUSPARSE_INDEX_32I,
672 CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_64F);
675 cusparseCreateDnVec(&
vecX_descr, x.
Size(),
const_cast<double *
>(d_x),
680 cusparseSetMatIndexBase(
matA_descr, CUSPARSE_INDEX_BASE_ZERO);
681 cusparseSetMatType(
matA_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
688 size_t newBufferSize = 0;
690 #if CUDA_VERSION >= 11020
691 cusparseSpMV_bufferSize(
handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
694 CUSPARSE_SPMV_CSR_ALG1, &newBufferSize);
695 #elif CUDA_VERSION >= 10010
696 cusparseSpMV_bufferSize(
handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
699 CUSPARSE_CSRMV_ALG1, &newBufferSize);
710 #if CUDA_VERSION >= 11020
712 cusparseDnVecSetValues(
vecX_descr, const_cast<double *>(d_x));
718 #elif CUDA_VERSION >= 10010
720 cusparseDnVecSetValues(
vecX_descr, const_cast<double *>(d_x));
727 cusparseDcsrmv(
handle, CUSPARSE_OPERATION_NON_TRANSPOSE,
730 const_cast<double *
>(d_A), const_cast<int *>(d_I),
const_cast<int *
>(d_J),
731 const_cast<double *>(d_x), &beta, d_y);
738 MFEM_FORALL(i, height,
741 const int end = d_I[i+1];
742 for (
int j = d_I[i]; j < end; j++)
744 d += d_A[j] * d_x[d_J[j]];
752 const double *Ap =
A, *xp = x.
GetData();
754 const int *Jp =
J, *Ip =
I;
756 #pragma omp parallel for
757 for (
int i = 0; i <
height; i++)
760 const int end = Ip[i+1];
761 for (
int j = Ip[i]; j < end; j++)
763 d += Ap[j] * xp[Jp[j]];
778 const double a)
const
781 <<
") must match matrix height (" <<
height <<
")");
782 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
783 <<
") must match matrix width (" <<
width <<
")");
789 for (
int i = 0; i <
height; i++)
791 RowNode *row =
Rows[i];
793 for ( ; row != NULL; row = row->Prev)
795 yp[row->Column] += row->Value *
b;
808 "enabled; see BuildTranspose() for details.");
809 for (
int i = 0; i <
height; i++)
811 const double xi = a * x[i];
812 const int end =
I[i+1];
813 for (
int j =
I[i]; j < end; j++)
839 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
841 const int n = rows.
Size();
843 auto d_rows = rows.
Read();
845 auto d_J =
Read(
J, nnz);
846 auto d_A =
Read(
A, nnz);
848 auto d_y = y.
Write();
851 const int r = d_rows[i];
852 const int end = d_I[r + 1];
854 for (
int j = d_I[r]; j < end; j++)
856 a += d_A[j] * d_x[d_J[j]];
865 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
867 for (
int i = 0; i < rows.
Size(); i++)
872 for (
int j =
I[r]; j < end; j++)
874 val +=
A[j] * x(
J[j]);
882 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
883 MFEM_ASSERT(x.
Size() ==
Width(),
"Input vector size (" << x.
Size()
884 <<
") must match matrix width (" <<
Width() <<
")");
890 auto d_I =
Read(
I, height+1);
891 auto d_J =
Read(
J, nnz);
894 MFEM_FORALL(i, height,
897 const int end = d_I[i+1];
898 for (
int j = d_I[i]; j < end; j++)
913 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
914 MFEM_ASSERT(x.
Size() ==
Height(),
"Input vector size (" << x.
Size()
915 <<
") must match matrix height (" <<
Height() <<
")");
920 for (
int i = 0; i <
Height(); i++)
925 for (
int j =
I[i]; j < end; j++)
935 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
936 <<
") must match matrix width (" <<
width <<
")");
937 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
938 <<
") must match matrix height (" <<
height <<
")");
949 for (
int i = 0; i <
height; i++)
951 RowNode *row =
Rows[i];
953 for ( ; row != NULL; row = row->Prev)
955 b += std::abs(row->Value) * xp[row->Column];
965 auto d_I =
Read(
I, height+1);
966 auto d_J =
Read(
J, nnz);
967 auto d_A =
Read(
A, nnz);
970 MFEM_FORALL(i, height,
973 const int end = d_I[i+1];
974 for (
int j = d_I[i]; j < end; j++)
976 d += std::abs(d_A[j]) * d_x[d_J[j]];
985 <<
") must match matrix height (" <<
height <<
")");
986 MFEM_ASSERT(
width == y.
Size(),
"Output vector size (" << y.
Size()
987 <<
") must match matrix width (" <<
width <<
")");
995 for (
int i = 0; i <
height; i++)
997 RowNode *row =
Rows[i];
999 for ( ; row != NULL; row = row->Prev)
1001 yp[row->Column] += fabs(row->Value) *
b;
1014 "enabled; see BuildTranspose() for details.");
1015 for (
int i = 0; i <
height; i++)
1017 const double xi = x[i];
1018 const int end =
I[i+1];
1019 for (
int j =
I[i]; j < end; j++)
1021 const int Jj =
J[j];
1022 y[Jj] += std::abs(
A[j]) * xi;
1031 <<
" must be equal to Width() = " <<
Width());
1033 <<
" must be equal to Height() = " <<
Height());
1046 for (
int i = 0; i <
height; i++)
1051 for (
int j =
I[i], end =
I[i+1]; j < end; j++)
1053 a +=
A[j] * x(
J[j]);
1058 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
1060 a += np->Value * x(np->Column);
1071 for (
int i = 0; i <
height; i++)
1076 for (
int j =
I[i], end =
I[i+1]; j < end; j++)
1083 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
1094 MFEM_VERIFY(irow <
height,
1095 "row " << irow <<
" not in matrix with height " <<
height);
1100 for (
int j =
I[irow], end =
I[irow+1]; j < end; j++)
1107 for (RowNode *np =
Rows[irow]; np != NULL; np = np->Prev)
1109 a += fabs(np->Value);
1118 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
1120 atol = std::abs(tol);
1122 fix_empty_rows =
height ==
width ? fix_empty_rows :
false;
1130 for (i = 0, nz = 0; i <
height; i++)
1133 for (j =
I[i]; j <
I[i+1]; j++)
1134 if (std::abs(
A[j]) > atol)
1139 if (fix_empty_rows && !found) { nz++; }
1147 for (i = 0, nz = 0; i <
height; i++)
1151 for (j =
I[i]; j <
I[i+1]; j++)
1152 if (std::abs(
A[j]) > atol)
1157 if ( lastCol > newJ[nz] )
1164 if (fix_empty_rows && !found)
1172 I.
Wrap(newI, height+1,
true);
1173 J.
Wrap(newJ,
I[height],
true);
1174 A.
Wrap(newA,
I[height],
true);
1192 for (i = 1; i <=
height; i++)
1195 for (aux =
Rows[i-1]; aux != NULL; aux = aux->Prev)
1197 if (skip_zeros && aux->Value == 0.0)
1199 if (skip_zeros == 2) {
continue; }
1200 if ((i-1) != aux->Column) {
continue; }
1204 for (RowNode *other =
Rows[aux->Column]; other != NULL; other = other->Prev)
1206 if (other->Column == (i-1))
1209 found_val = other->Value;
1213 if (found && found_val == 0.0) {
continue; }
1218 if (fix_empty_rows && !nr) { nr = 1; }
1227 for (j = i = 0; i <
height; i++)
1231 for (aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1233 if (skip_zeros && aux->Value == 0.0)
1235 if (skip_zeros == 2) {
continue; }
1236 if (i != aux->Column) {
continue; }
1240 for (RowNode *other =
Rows[aux->Column]; other != NULL; other = other->Prev)
1242 if (other->Column == i)
1245 found_val = other->Value;
1249 if (found && found_val == 0.0) {
continue; }
1255 if ( lastCol >
J[j] )
1264 if (fix_empty_rows && !nr)
1272 #ifdef MFEM_USE_MEMALLOC
1276 for (i = 0; i <
height; i++)
1278 RowNode *node_p =
Rows[i];
1279 while (node_p != NULL)
1282 node_p = node_p->Prev;
1295 int nr = (
height + br - 1)/br, nc = (
width + bc - 1)/bc;
1297 for (
int j = 0; j < bc; j++)
1299 for (
int i = 0; i < br; i++)
1302 for (
int k = 0; k <= nr; k++)
1306 blocks(i,j) =
new SparseMatrix(bI, NULL, NULL, nr, nc);
1310 for (
int gr = 0; gr <
height; gr++)
1312 int bi = gr/nr, i = gr%nr + 1;
1315 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1319 blocks(bi,
J[j]/nc)->I[i]++;
1325 for (RowNode *n_p =
Rows[gr]; n_p != NULL; n_p = n_p->Prev)
1327 if (n_p->Value != 0.0)
1329 blocks(bi, n_p->Column/nc)->I[i]++;
1335 for (
int j = 0; j < bc; j++)
1337 for (
int i = 0; i < br; i++)
1341 for (
int k = 1; k <= nr; k++)
1343 rs = b.
I[k], b.
I[k] = nnz, nnz += rs;
1350 for (
int gr = 0; gr <
height; gr++)
1352 int bi = gr/nr, i = gr%nr + 1;
1355 for (
int j =
I[gr]; j <
I[gr+1]; j++)
1360 b.
J[b.
I[i]] =
J[j] % nc;
1368 for (RowNode *n_p =
Rows[gr]; n_p != NULL; n_p = n_p->Prev)
1370 if (n_p->Value != 0.0)
1373 b.
J[b.
I[i]] = n_p->Column % nc;
1374 b.
A[b.
I[i]] = n_p->Value;
1396 for (
int i = 1; i <
height; i++)
1398 for (
int j =
I[i]; j <
I[i+1]; j++)
1402 symm = std::max(symm, std::abs(
A[j]-(*
this)(
J[j],i)));
1409 for (
int i = 0; i <
height; i++)
1411 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
1413 int col = node_p->Column;
1416 symm = std::max(symm, std::abs(node_p->Value-(*
this)(col,i)));
1426 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1429 for (i = 1; i <
height; i++)
1431 for (j =
I[i]; j <
I[i+1]; j++)
1435 A[j] += (*this)(
J[j],i);
1437 (*this)(J[j],i) = A[j];
1453 for (
int i = 0; i <
height; i++)
1455 for (RowNode *node_p =
Rows[i]; node_p != NULL; node_p = node_p->Prev)
1472 for (
int j = 0; j < nnz; j++)
1474 m = std::max(m, std::abs(
A[j]));
1479 for (
int i = 0; i <
height; i++)
1481 for (RowNode *n_p =
Rows[i]; n_p != NULL; n_p = n_p->Prev)
1483 m = std::max(m, std::abs(n_p->Value));
1497 const double *Ap =
A;
1499 for (
int i = 0; i < nz; i++)
1501 counter += (std::abs(Ap[i]) <= tol);
1506 for (
int i = 0; i <
height; i++)
1508 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1510 counter += (std::abs(aux->Value) <= tol);
1531 for (
int i = 0; i <
height; i++)
1533 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1551 MFEM_ASSERT(row < height && row >= 0,
1552 "Row " << row <<
" not in matrix of height " <<
height);
1554 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
1556 for (aux =
Rows[row]; aux != NULL; aux = aux->Prev)
1558 rhs(aux->Column) -= sol * aux->Value;
1567 MFEM_ASSERT(row < height && row >= 0,
1568 "Row " << row <<
" not in matrix of height " <<
height);
1569 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1571 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1576 for (
int i=
I[row]; i <
I[row+1]; ++i)
1583 for (aux =
Rows[row]; aux != NULL; aux = aux->Prev)
1597 MFEM_ASSERT(col < width && col >= 0,
1598 "Col " << col <<
" not in matrix of width " <<
width);
1599 MFEM_ASSERT(dpolicy !=
DIAG_KEEP,
"Diagonal policy must not be DIAG_KEEP");
1601 "if dpolicy == DIAG_ONE, matrix must be square, not height = "
1607 for (
int jpos = 0; jpos != nnz; ++jpos)
1617 for (
int i = 0; i <
height; i++)
1619 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1621 if (aux->Column == col)
1640 for (
int i = 0; i <
height; i++)
1642 for (
int jpos =
I[i]; jpos !=
I[i+1]; ++jpos)
1648 (*b)(i) -=
A[jpos] * (*x)(
J[jpos] );
1657 for (
int i = 0; i <
height; i++)
1659 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
1661 if (cols[aux -> Column])
1665 (*b)(i) -= aux -> Value * (*x)(aux -> Column);
1679 for (
int row = 0; row <
height; row++)
1681 for (nd =
Rows[row]; nd != NULL; nd = nd->Prev)
1683 if (col_marker[nd->Column])
1685 Ae.
Add(row, nd->Column, nd->Value);
1693 for (
int row = 0; row <
height; row++)
1695 for (
int j =
I[row]; j <
I[row+1]; j++)
1697 if (col_marker[
J[j]])
1699 Ae.
Add(row,
J[j],
A[j]);
1711 MFEM_ASSERT(rc < height && rc >= 0,
1712 "Row " << rc <<
" not in matrix of height " <<
height);
1716 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1718 const int col =
J[j];
1724 rhs(rc) =
A[j] * sol;
1735 mfem_error(
"SparseMatrix::EliminateRowCol () #2");
1742 for (
int k = I[col]; 1; k++)
1746 mfem_error(
"SparseMatrix::EliminateRowCol () #3");
1748 else if (
J[k] == rc)
1750 rhs(col) -= sol *
A[k];
1760 for (RowNode *aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
1762 const int col = aux->Column;
1768 rhs(rc) = aux->Value * sol;
1779 mfem_error(
"SparseMatrix::EliminateRowCol () #4");
1786 for (RowNode *node =
Rows[col]; 1; node = node->Prev)
1790 mfem_error(
"SparseMatrix::EliminateRowCol () #5");
1792 else if (node->Column == rc)
1794 rhs(col) -= sol * node->Value;
1808 MFEM_ASSERT(rc < height && rc >= 0,
1809 "Row " << rc <<
" not in matrix of height " <<
height);
1810 MFEM_ASSERT(sol.
Size() == rhs.
Width(),
"solution size (" << sol.
Size()
1811 <<
") must match rhs width (" << rhs.
Width() <<
")");
1813 const int num_rhs = rhs.
Width();
1816 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1818 const int col =
J[j];
1824 for (
int r = 0; r < num_rhs; r++)
1826 rhs(rc,r) =
A[j] * sol(r);
1831 for (
int r = 0; r < num_rhs; r++)
1838 for (
int r = 0; r < num_rhs; r++)
1844 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #3");
1851 for (
int k = I[col]; 1; k++)
1855 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #4");
1857 else if (
J[k] == rc)
1859 for (
int r = 0; r < num_rhs; r++)
1861 rhs(col,r) -= sol(r) *
A[k];
1872 for (RowNode *aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
1874 const int col = aux->Column;
1880 for (
int r = 0; r < num_rhs; r++)
1882 rhs(rc,r) = aux->Value * sol(r);
1887 for (
int r = 0; r < num_rhs; r++)
1894 for (
int r = 0; r < num_rhs; r++)
1900 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #5");
1907 for (RowNode *node =
Rows[col]; 1; node = node->Prev)
1911 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #6");
1913 else if (node->Column == rc)
1915 for (
int r = 0; r < num_rhs; r++)
1917 rhs(col,r) -= sol(r) * node->Value;
1930 MFEM_ASSERT(rc < height && rc >= 0,
1931 "Row " << rc <<
" not in matrix of height " <<
height);
1935 const auto &
I = this->
I;
1936 const auto &
J = this->
J;
1937 for (
int j =
I[rc]; j <
I[rc+1]; j++)
1939 const int col =
J[j];
1954 for (
int k = I[col]; 1; k++)
1958 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
1960 else if (
J[k] == rc)
1971 RowNode *aux, *node;
1973 for (aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
1975 const int col = aux->Column;
1990 for (node =
Rows[col]; 1; node = node->Prev)
1994 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
1996 else if (node->Column == rc)
2011 MFEM_ASSERT(rc < height && rc >= 0,
2012 "Row " << rc <<
" not in matrix of height " <<
height);
2016 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2018 const int col =
J[j];
2026 for (
int k = I[col]; 1; k++)
2030 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
2032 else if (
J[k] == rc)
2043 RowNode *aux, *node;
2045 for (aux =
Rows[rc]; aux != NULL; aux = aux->Prev)
2047 const int col = aux->Column;
2055 for (node =
Rows[col]; 1; node = node->Prev)
2059 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
2061 else if (node->Column == rc)
2078 for (nd =
Rows[rc]; nd != NULL; nd = nd->Prev)
2080 const int col = nd->Column;
2086 Ae.
Add(rc, rc, nd->Value - 1.0);
2090 Ae.
Add(rc, rc, nd->Value);
2096 mfem_error(
"SparseMatrix::EliminateRowCol #1");
2102 Ae.
Add(rc, col, nd->Value);
2104 for (nd2 =
Rows[col]; 1; nd2 = nd2->Prev)
2108 mfem_error(
"SparseMatrix::EliminateRowCol #2");
2110 else if (nd2->Column == rc)
2112 Ae.
Add(col, rc, nd2->Value);
2122 for (
int j =
I[rc]; j <
I[rc+1]; j++)
2124 const int col =
J[j];
2130 Ae.
Add(rc, rc,
A[j] - 1.0);
2134 Ae.
Add(rc, rc,
A[j]);
2140 mfem_error(
"SparseMatrix::EliminateRowCol #3");
2146 Ae.
Add(rc, col,
A[j]);
2148 for (
int k = I[col];
true; k++)
2152 mfem_error(
"SparseMatrix::EliminateRowCol #4");
2154 else if (
J[k] == rc)
2156 Ae.
Add(col, rc,
A[k]);
2168 for (
int i = 0; i <
height; i++)
2170 if (
I[i+1] ==
I[i]+1 && fabs(
A[
I[i]]) < 1e-16)
2179 for (
int i = 0; i <
height; i++)
2182 for (
int j =
I[i]; j <
I[i+1]; j++)
2186 if (zero <= threshold)
2188 for (
int j = I[i]; j < I[i+1]; j++)
2190 A[j] = (
J[j] == i) ? 1.0 : 0.0;
2201 const double *xp = x.
GetData();
2202 RowNode *diag_p, *n_p, **R =
Rows;
2205 for (
int i = 0; i <
s; i++)
2209 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
2211 const int c = n_p->Column;
2218 sum += n_p->Value * yp[c];
2222 if (diag_p != NULL && diag_p->Value != 0.0)
2224 yp[i] = (xp[i] - sum) / diag_p->Value;
2226 else if (xp[i] == sum)
2232 mfem_error(
"SparseMatrix::Gauss_Seidel_forw()");
2246 for (
int i = 0, j = Ip[0]; i <
s; i++)
2248 const int end = Ip[i+1];
2251 for ( ; j < end; j++)
2253 const int c = Jp[j];
2260 sum += Ap[j] * yp[c];
2264 if (d >= 0 && Ap[d] != 0.0)
2266 yp[i] = (xp[i] - sum) / Ap[d];
2268 else if (xp[i] == sum)
2274 mfem_error(
"SparseMatrix::Gauss_Seidel_forw(...) #2");
2285 const double *xp = x.
GetData();
2286 RowNode *diag_p, *n_p, **R =
Rows;
2288 for (
int i =
height-1; i >= 0; i--)
2292 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
2294 const int c = n_p->Column;
2301 sum += n_p->Value * yp[c];
2305 if (diag_p != NULL && diag_p->Value != 0.0)
2307 yp[i] = (xp[i] - sum) / diag_p->Value;
2309 else if (xp[i] == sum)
2315 mfem_error(
"SparseMatrix::Gauss_Seidel_back()");
2329 for (
int i = s-1, j = Ip[s]-1; i >= 0; i--)
2331 const int beg = Ip[i];
2334 for ( ; j >= beg; j--)
2336 const int c = Jp[j];
2343 sum += Ap[j] * yp[c];
2347 if (d >= 0 && Ap[d] != 0.0)
2349 yp[i] = (xp[i] - sum) / Ap[d];
2351 else if (xp[i] == sum)
2357 mfem_error(
"SparseMatrix::Gauss_Seidel_back(...) #2");
2365 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2368 for (
int i = 0; i <
height; i++)
2372 for (
int j =
I[i]; j <
I[i+1]; j++)
2380 if (d >= 0 &&
A[d] != 0.0)
2382 double a = 1.8 * fabs(
A[d]) / norm;
2390 mfem_error(
"SparseMatrix::GetJacobiScaling() #2");
2399 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2401 for (
int i = 0; i <
height; i++)
2405 for (
int j =
I[i]; j <
I[i+1]; j++)
2413 sum -=
A[j] * x0(
J[j]);
2416 if (d >= 0 &&
A[d] != 0.0)
2418 x1(i) = sc * (sum /
A[d]) + (1.0 - sc) * x0(i);
2429 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2435 const auto Ap =
Read(
A, nnz, use_dev);
2437 const auto Jp =
Read(
J, nnz, use_dev);
2439 const auto bp = b.
Read(use_dev);
2440 auto xp = x.
Write(use_dev);
2442 MFEM_FORALL_SWITCH(use_dev, i, H,
2444 const int end = Ip[i+1];
2445 for (
int j = Ip[i];
true; j++)
2449 MFEM_ABORT_KERNEL(
"Diagonal not found in SparseMatrix::DiagScale");
2453 if (!(std::abs(Ap[j]) > 0.0))
2455 MFEM_ABORT_KERNEL(
"Zero diagonal in SparseMatrix::DiagScale");
2457 xp[i] = sc * bp[i] / Ap[j];
2467 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2469 for (
int i = 0; i <
height; i++)
2471 double resi =
b(i), norm = 0.0;
2472 for (
int j =
I[i]; j <
I[i+1]; j++)
2474 resi -=
A[j] * x0(
J[j]);
2479 x1(i) = x0(i) + sc * resi / norm;
2483 MFEM_ABORT(
"L1 norm of row " << i <<
" is zero.");
2491 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2493 for (
int i = 0; i <
height; i++)
2495 double resi =
b(i), sum = 0.0;
2496 for (
int j =
I[i]; j <
I[i+1]; j++)
2498 resi -=
A[j] * x0(
J[j]);
2503 x1(i) = x0(i) + sc * resi / sum;
2507 MFEM_ABORT(
"sum of row " << i <<
" is zero.");
2515 int i, j, gi, gj,
s,
t;
2525 for (i = 0; i < rows.
Size(); i++)
2527 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2530 "Trying to insert a row " << gi <<
" outside the matrix height "
2533 for (j = 0; j < cols.
Size(); j++)
2535 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2537 MFEM_ASSERT(gj <
width,
2538 "Trying to insert a column " << gj <<
" outside the matrix width "
2541 if (skip_zeros && a == 0.0)
2546 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2551 if (t < 0) { a = -
a; }
2563 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2566 "Trying to set a row " << gi <<
" outside the matrix height "
2568 if ((gj=j) < 0) { gj = -1-gj, t = -
s; }
2570 MFEM_ASSERT(gj <
width,
2571 "Trying to set a column " << gj <<
" outside the matrix width "
2573 if (t < 0) { a = -
a; }
2582 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
2585 "Trying to insert a row " << gi <<
" outside the matrix height "
2587 if ((gj=j) < 0) { gj = -1-gj, t = -
s; }
2589 MFEM_ASSERT(gj <
width,
2590 "Trying to insert a column " << gj <<
" outside the matrix width "
2592 if (t < 0) { a = -
a; }
2599 int i, j, gi, gj,
s,
t;
2602 for (i = 0; i < rows.
Size(); i++)
2604 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2607 "Trying to set a row " << gi <<
" outside the matrix height "
2610 for (j = 0; j < cols.
Size(); j++)
2613 if (skip_zeros && a == 0.0)
2618 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2623 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2625 MFEM_ASSERT(gj <
width,
2626 "Trying to set a column " << gj <<
" outside the matrix width "
2628 if (t < 0) { a = -
a; }
2640 int i, j, gi, gj,
s,
t;
2643 for (i = 0; i < rows.
Size(); i++)
2645 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2648 "Trying to set a row " << gi <<
" outside the matrix height "
2651 for (j = 0; j < cols.
Size(); j++)
2654 if (skip_zeros && a == 0.0)
2659 if (skip_zeros == 2 || &rows != &cols || subm(j, i) == 0.0)
2664 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2666 MFEM_ASSERT(gj <
width,
2667 "Trying to set a column " << gj <<
" outside the matrix width "
2669 if (t < 0) { a = -
a; }
2679 int i, j, gi, gj,
s,
t;
2682 for (i = 0; i < rows.
Size(); i++)
2684 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
2687 "Trying to read a row " << gi <<
" outside the matrix height "
2690 for (j = 0; j < cols.
Size(); j++)
2692 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2694 MFEM_ASSERT(gj <
width,
2695 "Trying to read a column " << gj <<
" outside the matrix width "
2698 subm(i, j) = (t < 0) ? (-a) : (
a);
2713 "Trying to query a row " << gi <<
" outside the matrix height "
2717 return (
Rows[gi] == NULL);
2721 return (
I[gi] ==
I[gi+1]);
2730 if ((gi=row) < 0) { gi = -1-gi; }
2732 "Trying to read a row " << gi <<
" outside the matrix height "
2736 for (n =
Rows[gi], j = 0; n; n = n->Prev)
2742 for (n =
Rows[gi], j = 0; n; n = n->Prev, j++)
2744 cols[j] = n->Column;
2757 cols.
MakeRef(const_cast<int*>((
const int*)
J) + j,
I[gi+1]-j);
2759 const_cast<double*>((
const double*)
A) + j, cols.
Size());
2760 MFEM_ASSERT(row >= 0,
"Row not valid: " << row <<
", height: " <<
height);
2771 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2774 "Trying to set a row " << gi <<
" outside the matrix height "
2780 for (
int j = 0; j < cols.
Size(); j++)
2782 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2784 MFEM_ASSERT(gj <
width,
2785 "Trying to set a column " << gj <<
" outside the matrix"
2786 " width " <<
width);
2788 if (t < 0) { a = -
a; }
2796 MFEM_ASSERT(cols.
Size() == srow.
Size(),
"");
2798 for (
int i =
I[gi], j = 0; j < cols.
Size(); j++, i++)
2800 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2802 MFEM_ASSERT(gj <
width,
2803 "Trying to set a column " << gj <<
" outside the matrix"
2804 " width " <<
width);
2815 int j, gi, gj,
s,
t;
2818 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
2820 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2823 "Trying to insert a row " << gi <<
" outside the matrix height "
2826 for (j = 0; j < cols.
Size(); j++)
2828 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -
s; }
2830 MFEM_ASSERT(gj <
width,
2831 "Trying to insert a column " << gj <<
" outside the matrix width "
2838 if (t < 0) { a = -
a; }
2856 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2858 aux -> Value *= scale;
2863 int j, end =
I[i+1];
2865 for (j =
I[i]; j < end; j++)
2878 for (
int i=0; i <
height; ++i)
2881 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2883 aux -> Value *= scale;
2891 for (
int i=0; i <
height; ++i)
2895 for (j =
I[i]; j < end; j++)
2908 for (
int i=0; i <
height; ++i)
2910 for (aux =
Rows[i]; aux != NULL; aux = aux -> Prev)
2912 aux -> Value *= sr(aux->Column);
2920 for (
int i=0; i <
height; ++i)
2923 for (j =
I[i]; j < end; j++)
2934 "Mismatch of this matrix size and rhs. This height = "
2935 <<
height <<
", width = " <<
width <<
", B.height = "
2938 for (
int i = 0; i <
height; i++)
2943 for (RowNode *aux = B.
Rows[i]; aux != NULL; aux = aux->Prev)
2945 _Add_(aux->Column, aux->Value);
2950 for (
int j = B.
I[i]; j < B.
I[i+1]; j++)
2963 for (
int i = 0; i <
height; i++)
2968 for (RowNode *np =
Rows[i]; np != NULL; np = np->Prev)
2970 np->Value += a * B.
_Get_(np->Column);
2975 for (
int j =
I[i]; j <
I[i+1]; j++)
2990 for (
int i = 0; i < nnz; i++)
2997 for (
int i = 0; i <
height; i++)
2999 for (RowNode *node_p =
Rows[i]; node_p != NULL;
3000 node_p = node_p -> Prev)
3002 node_p -> Value =
a;
3014 for (
int i = 0, nnz =
I[
height]; i < nnz; i++)
3021 for (
int i = 0; i <
height; i++)
3023 for (RowNode *node_p =
Rows[i]; node_p != NULL;
3024 node_p = node_p -> Prev)
3026 node_p -> Value *=
a;
3041 for (i = 0; i <
height; i++)
3043 out <<
"[row " << i <<
"]\n";
3044 for (nd =
Rows[i], j = 0; nd != NULL; nd = nd->Prev, j++)
3046 out <<
" (" << nd->Column <<
"," << nd->Value <<
")";
3047 if ( !((j+1) % width_) )
3064 for (i = 0; i <
height; i++)
3066 out <<
"[row " << i <<
"]\n";
3067 for (j =
I[i]; j <
I[i+1]; j++)
3069 out <<
" (" <<
J[j] <<
"," <<
A[j] <<
")";
3070 if ( !((j+1-I[i]) % width_) )
3075 if ((j-I[i]) % width_)
3084 out <<
"% size " <<
height <<
" " <<
width <<
"\n";
3087 ios::fmtflags old_fmt = out.flags();
3088 out.setf(ios::scientific);
3089 std::streamsize old_prec = out.precision(14);
3091 for (i = 0; i <
height; i++)
3093 for (j =
I[i]; j <
I[i+1]; j++)
3095 out << i+1 <<
" " <<
J[j]+1 <<
" " <<
A[j] <<
'\n';
3098 out.precision(old_prec);
3105 ios::fmtflags old_fmt = out.flags();
3106 out.setf(ios::scientific);
3107 std::streamsize old_prec = out.precision(14);
3109 out <<
"%%MatrixMarket matrix coordinate real general" <<
'\n'
3110 <<
"% Generated by MFEM" <<
'\n';
3113 for (i = 0; i <
height; i++)
3115 for (j =
I[i]; j <
I[i+1]; j++)
3117 out << i+1 <<
" " <<
J[j]+1 <<
" " <<
A[j] <<
'\n';
3120 out.precision(old_prec);
3126 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3132 for (i = 0; i <=
height; i++)
3134 out <<
I[i]+1 <<
'\n';
3137 for (i = 0; i <
I[
height]; i++)
3139 out <<
J[i]+1 <<
'\n';
3142 for (i = 0; i < I[
height]; i++)
3144 out <<
A[i] <<
'\n';
3150 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
3155 out <<
width <<
'\n';
3157 for (i = 0; i <=
height; i++)
3159 out <<
I[i] <<
'\n';
3162 for (i = 0; i <
I[
height]; i++)
3164 out <<
J[i] <<
'\n';
3167 for (i = 0; i < I[
height]; i++)
3169 out <<
A[i] <<
'\n';
3175 const double MiB = 1024.*1024;
3177 double pz = 100./nnz;
3187 "SparseMatrix statistics:\n"
3190 " Dimensions : " <<
height <<
" x " <<
width <<
"\n"
3191 " Number of entries (total) : " << nnz <<
"\n"
3192 " Number of entries (per row) : " << 1.*nnz/
Height() <<
"\n"
3193 " Number of stored zeros : " << nz*pz <<
"% (" << nz <<
")\n"
3194 " Number of Inf/Nan entries : " << nnf*pz <<
"% ("<< nnf <<
")\n"
3195 " Norm, max |a_ij| : " << max_norm <<
"\n"
3196 " Symmetry, max |a_ij-a_ji| : " << symm <<
"\n"
3197 " Number of small entries:\n"
3198 " |a_ij| <= 1e-12*Norm : " << ns12*pz <<
"% (" << ns12 <<
")\n"
3199 " |a_ij| <= 1e-15*Norm : " << ns15*pz <<
"% (" << ns15 <<
")\n"
3200 " |a_ij| <= 1e-18*Norm : " << ns18*pz <<
"% (" << ns18 <<
")\n";
3203 out <<
" Memory used by CSR : " <<
3204 (
sizeof(int)*(
height+1+nnz)+
sizeof(double)*nnz)/MiB <<
" MiB\n";
3208 size_t used_mem =
sizeof(RowNode*)*
height;
3209 #ifdef MFEM_USE_MEMALLOC
3212 for (
int i = 0; i <
height; i++)
3214 for (RowNode *aux =
Rows[i]; aux != NULL; aux = aux->Prev)
3216 used_mem +=
sizeof(RowNode);
3220 out <<
" Memory used by LIL : " << used_mem/MiB <<
" MiB\n";
3232 #if !defined(MFEM_USE_MEMALLOC)
3233 for (
int i = 0; i <
height; i++)
3235 RowNode *aux, *node_p =
Rows[i];
3236 while (node_p != NULL)
3239 node_p = node_p->Prev;
3249 #ifdef MFEM_USE_MEMALLOC
3262 const int *start_j =
J;
3264 for (
const int *jptr = start_j; jptr != end_j; ++jptr)
3266 awidth = std::max(awidth, *jptr + 1);
3272 for (
int i = 0; i <
height; i++)
3274 for (aux =
Rows[i]; aux != NULL; aux = aux->Prev)
3276 awidth = std::max(awidth, aux->Column + 1);
3288 for (
int i = 0; i < n; i++)
3298 "Finalize must be called before Transpose. Use TransposeRowMatrix instead");
3301 const int *A_i, *A_j;
3302 int m, n, nnz, *At_i, *At_j;
3303 const double *A_data;
3317 for (i = 0; i <= n; i++)
3321 for (i = 0; i < nnz; i++)
3325 for (i = 1; i < n; i++)
3327 At_i[i+1] += At_i[i];
3330 for (i = j = 0; i < m; i++)
3333 for ( ; j < end; j++)
3335 At_j[At_i[A_j[j]]] = i;
3336 At_data[At_i[A_j[j]]] = A_data[j];
3341 for (i = n; i > 0; i--)
3343 At_i[i] = At_i[i-1];
3354 int m, n, nnz, *At_i, *At_j;
3364 for (i = 0; i < m; i++)
3366 A.
GetRow(i, Acols, Avals);
3388 for (i = 0; i <= n; i++)
3393 for (i = 0; i < m; i++)
3395 A.
GetRow(i, Acols, Avals);
3396 for (j = 0; j<Acols.
Size(); ++j)
3401 for (i = 1; i < n; i++)
3403 At_i[i+1] += At_i[i];
3406 for (i = 0; i < m; i++)
3408 A.
GetRow(i, Acols, Avals);
3409 for (j = 0; j<Acols.
Size(); ++j)
3411 At_j[At_i[Acols[j]]] = i;
3412 At_data[At_i[Acols[j]]] = Avals[j];
3417 for (i = n; i > 0; i--)
3419 At_i[i] = At_i[i-1];
3430 int nrowsA, ncolsA, nrowsB, ncolsB;
3431 const int *A_i, *A_j, *B_i, *B_j;
3432 int *C_i, *C_j, *B_marker;
3433 const double *A_data, *B_data;
3435 int ia, ib, ic, ja, jb, num_nonzeros;
3436 int row_start, counter;
3437 double a_entry, b_entry;
3445 MFEM_VERIFY(ncolsA == nrowsB,
3446 "number of columns of A (" << ncolsA
3447 <<
") must equal number of rows of B (" << nrowsB <<
")");
3456 B_marker =
new int[ncolsB];
3458 for (ib = 0; ib < ncolsB; ib++)
3467 C_i[0] = num_nonzeros = 0;
3468 for (ic = 0; ic < nrowsA; ic++)
3470 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3473 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3476 if (B_marker[jb] != ic)
3483 C_i[ic+1] = num_nonzeros;
3489 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3491 for (ib = 0; ib < ncolsB; ib++)
3500 MFEM_VERIFY(nrowsA == C->
Height() && ncolsB == C->
Width(),
3501 "Input matrix sizes do not match output sizes"
3502 <<
" nrowsA = " << nrowsA
3503 <<
", C->Height() = " << C->
Height()
3504 <<
" ncolsB = " << ncolsB
3505 <<
", C->Width() = " << C->
Width());
3513 for (ic = 0; ic < nrowsA; ic++)
3516 row_start = counter;
3517 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3520 a_entry = A_data[ia];
3521 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
3524 b_entry = B_data[ib];
3525 if (B_marker[jb] < row_start)
3527 B_marker[jb] = counter;
3532 C_data[counter] = a_entry*b_entry;
3537 C_data[B_marker[jb]] += a_entry*b_entry;
3545 "With pre-allocated output matrix, number of non-zeros ("
3547 <<
") did not match number of entries changed from matrix-matrix multiply, "
3566 int nrowsA, ncolsA, nrowsB, ncolsB;
3567 int *C_i, *C_j, *B_marker;
3569 int ia, ib, ic, ja, jb, num_nonzeros;
3570 int row_start, counter;
3571 double a_entry, b_entry;
3579 MFEM_VERIFY(ncolsA == nrowsB,
3580 "number of columns of A (" << ncolsA
3581 <<
") must equal number of rows of B (" << nrowsB <<
")");
3583 B_marker =
new int[ncolsB];
3585 for (ib = 0; ib < ncolsB; ib++)
3592 C_i[0] = num_nonzeros = 0;
3596 for (ic = 0; ic < nrowsA; ic++)
3598 A.
GetRow(ic, colsA, dataA);
3599 for (ia = 0; ia < colsA.
Size(); ia++)
3602 B.
GetRow(ja, colsB, dataB);
3603 for (ib = 0; ib < colsB.
Size(); ib++)
3606 if (B_marker[jb] != ic)
3613 C_i[ic+1] = num_nonzeros;
3619 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
3621 for (ib = 0; ib < ncolsB; ib++)
3627 for (ic = 0; ic < nrowsA; ic++)
3629 row_start = counter;
3630 A.
GetRow(ic, colsA, dataA);
3631 for (ia = 0; ia < colsA.
Size(); ia++)
3634 a_entry = dataA[ia];
3635 B.
GetRow(ja, colsB, dataB);
3636 for (ib = 0; ib < colsB.
Size(); ib++)
3639 b_entry = dataB[ib];
3640 if (B_marker[jb] < row_start)
3642 B_marker[jb] = counter;
3644 C_data[counter] = a_entry*b_entry;
3649 C_data[B_marker[jb]] += a_entry*b_entry;
3664 for (
int j = 0; j < B.
Width(); ++j)
3668 A.
Mult(columnB, columnC);
3678 Mult (R, *AP, *RAP_);
3721 int i, At_nnz, *At_j;
3725 At_nnz = At -> NumNonZeroElems();
3726 At_j = At -> GetJ();
3727 At_data = At -> GetData();
3728 for (i = 0; i < At_nnz; i++)
3730 At_data[i] *= D(At_j[i]);
3741 int ncols = A.
Width();
3747 const int *A_i = A.
GetI();
3748 const int *A_j = A.
GetJ();
3749 const double *A_data = A.
GetData();
3751 const int *B_i = B.
GetI();
3752 const int *B_j = B.
GetJ();
3753 const double *B_data = B.
GetData();
3755 int * marker =
new int[ncols];
3756 std::fill(marker, marker+ncols, -1);
3758 int num_nonzeros = 0, jcol;
3760 for (
int ic = 0; ic < nrows; ic++)
3762 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3768 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
3771 if (marker[jcol] != ic)
3777 C_i[ic+1] = num_nonzeros;
3783 for (
int ia = 0; ia < ncols; ia++)
3789 for (
int ic = 0; ic < nrows; ic++)
3791 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
3795 C_data[pos] = a*A_data[ia];
3799 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
3802 if (marker[jcol] < C_i[ic])
3805 C_data[pos] = b*B_data[ib];
3811 C_data[marker[jcol]] += b*B_data[ib];
3817 return new SparseMatrix(C_i, C_j, C_data, nrows, ncols);
3822 return Add(1.,A,1.,B);
3827 MFEM_ASSERT(Ai.
Size() > 0,
"invalid size Ai.Size() = " << Ai.
Size());
3832 for (
int i=1; i < Ai.
Size(); ++i)
3834 result =
Add(*accumulate, *Ai[i]);
3840 accumulate = result;
3850 for (
int r = 0; r < B.
Height(); r++)
3854 for (
int i=0; i<A.
RowSize(r); i++)
3856 B(r, colA[i]) += alpha * valA[i];
3869 for (
int i=0; i<mA; i++)
3871 for (
int j=0; j<nA; j++)
3873 C->
AddMatrix(A(i,j), B, i * mB, j * nB);
3887 for (
int i=0; i<mA; i++)
3889 for (
int j=0; j<nA; j++)
3891 for (
int r=0; r<mB; r++)
3896 for (
int cj=0; cj<B.
RowSize(r); cj++)
3898 C->
Set(i * mB + r, j * nB + colB[cj], A(i,j) * valB[cj]);
3916 for (
int r=0; r<mA; r++)
3921 for (
int aj=0; aj<A.
RowSize(r); aj++)
3923 for (
int i=0; i<mB; i++)
3925 for (
int j=0; j<nB; j++)
3927 C->
Set(r * mB + i, colA[aj] * nB + j, valA[aj] * B(i, j));
3945 for (
int ar=0; ar<mA; ar++)
3950 for (
int aj=0; aj<A.
RowSize(ar); aj++)
3952 for (
int br=0; br<mB; br++)
3957 for (
int bj=0; bj<B.
RowSize(br); bj++)
3959 C->
Set(ar * mB + br, colA[aj] * nB + colB[bj],
3960 valA[aj] * valB[bj]);
3983 #ifdef MFEM_USE_MEMALLOC
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.
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 i, const int j, const double a)
void * CuMemFree(void *dptr)
Frees device memory and returns destination ptr.
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
void DiagScale(const Vector &b, Vector &x, double sc=1.0) 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. The Memory is not reset by this method, i.e. it will, generally, not be Empty() after this call.
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.
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
void ClearCuSparse()
Clear the CuSparse descriptors. This must be called after releasing the device memory of A...
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 PrintInfo(std::ostream &out) const
Print various sparse matrix statistics.
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
static bool IsDisabled()
The opposite of IsEnabled().
virtual double & Elem(int i, int j)
Returns reference to a_{ij}.
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 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);
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().
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.
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)
Dynamic 2D array using row-major layout.
void Jacobi(const Vector &b, const Vector &x0, Vector &x1, double sc) const
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.
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 Set(const int i, const int j, const double a)
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.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as 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.
void * CuMemAlloc(void **dptr, size_t bytes)
Allocates device memory and returns destination ptr.
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)