15 #include "../general/table.hpp"
16 #include "../general/sort_pairs.hpp"
34 Rows(new RowNode *[nrows]),
42 for (
int i = 0; i < nrows; i++)
47 #ifdef MFEM_USE_MEMALLOC
64 #ifdef MFEM_USE_MEMALLOC
70 bool ownij,
bool owna,
bool issorted)
82 #ifdef MFEM_USE_MEMALLOC
90 A =
new double[ nnz ];
91 for (
int i=0; i<nnz; ++i)
107 #ifdef MFEM_USE_MEMALLOC
110 I =
new int[nrows + 1];
111 J =
new int[nrows * rowsize];
112 A =
new double[nrows * rowsize];
114 for (
int i = 0; i <= nrows; i++)
125 const int nnz = mat.I[
height];
130 memcpy(I, mat.I,
sizeof(
int)*(
height+1));
131 memcpy(J, mat.J,
sizeof(
int)*nnz);
141 memcpy(A, mat.A,
sizeof(
double)*nnz);
145 #ifdef MFEM_USE_MEMALLOC
151 #ifdef MFEM_USE_MEMALLOC
154 Rows =
new RowNode *[
height];
155 for (
int i = 0; i <
height; i++)
157 RowNode **node_pp = &Rows[i];
158 for (RowNode *node_p = mat.Rows[i]; node_p; node_p = node_p->Prev)
160 #ifdef MFEM_USE_MEMALLOC
161 RowNode *new_node_p = NodesMem->
Alloc();
163 RowNode *new_node_p =
new RowNode;
165 new_node_p->Value = node_p->Value;
166 new_node_p->Column = node_p->Column;
167 *node_pp = new_node_p;
168 node_pp = &new_node_p->Prev;
183 isSorted = mat.isSorted;
188 MFEM_ASSERT(master.
Finalized(),
"'master' must be finalized");
197 void SparseMatrix::SetEmpty()
206 #ifdef MFEM_USE_MEMALLOC
209 ownGraph = ownData = isSorted =
false;
222 return I[gi+1]-I[gi];
226 RowNode *row = Rows[gi];
227 for ( ; row != NULL; row = row->Prev)
228 if (row->Value != 0.0)
241 for (
int i=0; i <
height; ++i)
243 rowSize = I[i+1]-I[i];
244 out = (out > rowSize) ? out : rowSize;
249 for (
int i=0; i <
height; ++i)
252 out = (out > rowSize) ? out : rowSize;
261 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
268 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
275 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
282 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
289 if (newWidth ==
width)
294 else if ( newWidth == -1)
300 else if (newWidth >
width)
305 delete [] ColPtrNode;
306 ColPtrNode =
static_cast<RowNode **
>(NULL);
311 ColPtrJ =
static_cast<int *
>(NULL);
319 "The new width needs to be bigger or equal to the actual width");
327 MFEM_VERIFY(
Finalized(),
"Matrix is not Finalized!");
335 for (
int j = 0, i = 0; i <
height; i++)
339 for (
int k = 0; k < row.
Size(); k++)
345 for (
int k = 0; k < row.
Size(); k++, j++)
368 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
369 "Trying to access element outside of the matrix. "
370 <<
"height = " <<
height <<
", "
371 <<
"width = " <<
width <<
", "
372 <<
"i = " << i <<
", "
375 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
378 for (k = I[i]; k < end; k++)
384 MFEM_ABORT(
"Did not find i = " << i <<
", j = " << j <<
" in matrix.");
391 static const double zero = 0.0;
393 MFEM_ASSERT(i < height && i >= 0 && j < width && j >= 0,
394 "Trying to access element outside of the matrix. "
395 <<
"height = " <<
height <<
", "
396 <<
"width = " <<
width <<
", "
397 <<
"i = " << i <<
", "
400 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
402 for (k = I[i]; k < end; k++)
414 "Matrix must be square, not height = " <<
height <<
", width = " <<
width);
415 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
420 for (
int i = 0; i <
height; i++)
424 for (j = I[i]; j < end; j++)
448 "Input vector size (" << x.
Size() <<
") must match matrix width (" <<
width
451 "Output vector size (" << y.
Size() <<
") must match matrix height (" <<
height
455 double *Ap = A, *yp = y.
GetData();
456 const double *xp = x.
GetData();
461 for (i = 0; i <
height; i++)
463 RowNode *row = Rows[i];
465 for ( ; row != NULL; row = row->Prev)
467 b += row->Value * xp[row->Column];
475 int *Jp = J, *Ip = I;
479 #ifndef MFEM_USE_OPENMP
480 for (i = j = 0; i <
height; i++)
483 for (end = Ip[i+1]; j < end; j++)
485 d += Ap[j] * xp[Jp[j]];
490 #pragma omp parallel for private(j,end)
491 for (i = 0; i <
height; i++)
494 for (j = Ip[i], end = Ip[i+1]; j < end; j++)
496 d += Ap[j] * xp[Jp[j]];
503 for (i = j = 0; i <
height; i++)
506 for (end = Ip[i+1]; j < end; j++)
508 d += Ap[j] * xp[Jp[j]];
521 const double a)
const
524 "Input vector size (" << x.
Size() <<
") must match matrix height (" <<
height
527 "Output vector size (" << y.
Size() <<
") must match matrix width (" <<
width
536 for (i = 0; i <
height; i++)
538 RowNode *row = Rows[i];
540 for ( ; row != NULL; row = row->Prev)
542 yp[row->Column] += row->Value * b;
548 for (i = 0; i <
height; i++)
550 double xi = a * x(i);
552 for (j = I[i]; j < end; j++)
562 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
564 for (
int i = 0; i < rows.
Size(); i++)
569 for (
int j = I[r]; j < end; j++)
580 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
582 for (
int i = 0; i < rows.
Size(); i++)
587 for (
int j = I[r]; j < end; j++)
589 val += A[j] * x(J[j]);
597 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
598 MFEM_ASSERT(x.
Size() ==
Width(),
"Input vector size (" << x.
Size()
599 <<
") must match matrix width (" <<
Width() <<
")");
604 for (
int i = 0; i <
Height(); i++)
607 for (
int j = I[i]; j < end; j++)
621 MFEM_ASSERT(
Finalized(),
"Matrix must be finalized.");
622 MFEM_ASSERT(x.
Size() ==
Height(),
"Input vector size (" << x.
Size()
623 <<
") must match matrix height (" <<
Height() <<
")");
628 for (
int i = 0; i <
Height(); i++)
633 for (
int j = I[i]; j < end; j++)
644 <<
" must be equal to Width() = " <<
Width());
646 <<
" must be equal to Height() = " <<
Height());
648 for (
int i = 0; i <
height; i++)
652 for (
int j = I[i], end = I[i+1]; j < end; j++)
657 for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
659 a += np->Value * x(np->Column);
669 for (
int i = 0; i <
height; i++)
673 for (
int j = I[i], end = I[i+1]; j < end; j++)
678 for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
688 MFEM_VERIFY(irow <
height,
689 "row " << irow <<
" not in matrix with height " <<
height);
693 for (
int j = I[irow], end = I[irow+1]; j < end; j++)
698 for (RowNode *np = Rows[irow]; np != NULL; np = np->Prev)
700 a += fabs(np->Value);
716 delete [] ColPtrNode;
721 for (i = 1; i <=
height; i++)
724 for (aux = Rows[i-1]; aux != NULL; aux = aux->Prev)
725 if (!skip_zeros || aux->Value != 0.0)
737 for (j = i = 0; i <
height; i++)
740 for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
742 if (!skip_zeros || aux->Value != 0.0)
747 if ( lastCol > J[j] )
758 #ifdef MFEM_USE_MEMALLOC
762 for (i = 0; i <
height; i++)
764 RowNode *node_p = Rows[i];
765 while (node_p != NULL)
768 node_p = node_p->Prev;
781 int nr = (
height + br - 1)/br, nc = (
width + bc - 1)/bc;
783 for (
int j = 0; j < bc; j++)
785 for (
int i = 0; i < br; i++)
787 int *bI =
new int[nr + 1];
788 for (
int k = 0; k <= nr; k++)
796 for (
int gr = 0; gr <
height; gr++)
798 int bi = gr/nr, i = gr%nr + 1;
801 for (
int j = I[gr]; j < I[gr+1]; j++)
805 blocks(bi, J[j]/nc)->I[i]++;
811 for (RowNode *n_p = Rows[gr]; n_p != NULL; n_p = n_p->Prev)
813 if (n_p->Value != 0.0)
815 blocks(bi, n_p->Column/nc)->I[i]++;
821 for (
int j = 0; j < bc; j++)
823 for (
int i = 0; i < br; i++)
827 for (
int k = 1; k <= nr; k++)
829 rs = b.I[k], b.I[k] = nnz, nnz += rs;
832 b.A =
new double[nnz];
836 for (
int gr = 0; gr <
height; gr++)
838 int bi = gr/nr, i = gr%nr + 1;
841 for (
int j = I[gr]; j < I[gr+1]; j++)
846 b.J[b.I[i]] = J[j] % nc;
854 for (RowNode *n_p = Rows[gr]; n_p != NULL; n_p = n_p->Prev)
856 if (n_p->Value != 0.0)
859 b.J[b.I[i]] = n_p->Column % nc;
860 b.A[b.I[i]] = n_p->Value;
870 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
876 for (i = 1; i <
height; i++)
877 for (j = I[i]; j < I[i+1]; j++)
880 a = fabs ( A[j] - (*
this)(J[j],i) );
892 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
895 for (i = 1; i <
height; i++)
896 for (j = I[i]; j < I[i+1]; j++)
899 A[j] += (*this)(J[j],i);
901 (*this)(J[j],i) = A[j];
915 for (
int i = 0; i <
height; i++)
916 for (RowNode *node_p = Rows[i]; node_p != NULL; node_p = node_p->Prev)
932 for (
int j = 0; j < nnz; j++)
934 m = std::max(m, fabs(A[j]));
939 for (
int i = 0; i <
height; i++)
940 for (RowNode *n_p = Rows[i]; n_p != NULL; n_p = n_p->Prev)
942 m = std::max(m, fabs(n_p->Value));
957 for (i = 0; i < nz; i++)
958 if (fabs(Ap[i]) < tol)
967 for (i = 0; i <
height; i++)
968 for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
969 if (fabs(aux -> Value) < tol)
987 MFEM_ASSERT(row < height && row >= 0,
988 "Row " << row <<
" not in matrix of height " <<
height);
990 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
992 for (aux = Rows[row]; aux != NULL; aux = aux->Prev)
994 rhs(aux->Column) -= sol * aux->Value;
1003 MFEM_ASSERT(row < height && row >= 0,
1004 "Row " << row <<
" not in matrix of height " <<
height);
1006 "if setOneDiagonal, must be rectangular matrix, not height = "
1010 for (
int i=I[row]; i < I[row+1]; ++i)
1015 for (aux = Rows[row]; aux != NULL; aux = aux->Prev)
1030 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
1032 for (
int i = 0; i <
height; i++)
1033 for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
1034 if (aux -> Column == col)
1044 for (
int i = 0; i <
height; i++)
1045 for (
int jpos = I[i]; jpos != I[i+1]; ++jpos)
1046 if (cols[ J[jpos]] )
1050 (*b)(i) -= A[jpos] * (*x)( J[jpos] );
1058 for (
int i = 0; i <
height; i++)
1059 for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
1060 if (cols[aux -> Column])
1064 (*b)(i) -= aux -> Value * (*x)(aux -> Column);
1076 MFEM_ASSERT(rc < height && rc >= 0,
1077 "Row " << rc <<
" not in matrix of height " <<
height);
1081 for (
int j = I[rc]; j < I[rc+1]; j++)
1083 if ((col = J[j]) == rc)
1087 rhs(rc) = A[j] * sol;
1098 for (
int k = I[col]; 1; k++)
1102 mfem_error(
"SparseMatrix::EliminateRowCol () #2");
1104 else if (J[k] == rc)
1106 rhs(col) -= sol * A[k];
1116 for (RowNode *aux = Rows[rc]; aux != NULL; aux = aux->Prev)
1118 if ((col = aux->Column) == rc)
1122 rhs(rc) = aux->Value * sol;
1133 for (RowNode *node = Rows[col]; 1; node = node->Prev)
1137 mfem_error(
"SparseMatrix::EliminateRowCol () #3");
1139 else if (node->Column == rc)
1141 rhs(col) -= sol * node->Value;
1155 int num_rhs = rhs.
Width();
1157 MFEM_ASSERT(rc < height && rc >= 0,
1158 "Row " << rc <<
" not in matrix of height " <<
height);
1159 MFEM_ASSERT(sol.
Size() == num_rhs,
"solution size (" << sol.
Size()
1160 <<
") must match rhs width (" << num_rhs <<
")");
1163 for (
int j = I[rc]; j < I[rc+1]; j++)
1164 if ((col = J[j]) == rc)
1167 for (
int r = 0; r < num_rhs; r++)
1169 rhs(rc,r) = A[j] * sol(r);
1175 for (
int r = 0; r < num_rhs; r++)
1183 for (
int k = I[col]; 1; k++)
1186 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #3");
1188 else if (J[k] == rc)
1190 for (
int r = 0; r < num_rhs; r++)
1192 rhs(col,r) -= sol(r) * A[k];
1199 for (RowNode *aux = Rows[rc]; aux != NULL; aux = aux->Prev)
1200 if ((col = aux->Column) == rc)
1203 for (
int r = 0; r < num_rhs; r++)
1205 rhs(rc,r) = aux->Value * sol(r);
1211 for (
int r = 0; r < num_rhs; r++)
1219 for (RowNode *node = Rows[col]; 1; node = node->Prev)
1222 mfem_error(
"SparseMatrix::EliminateRowColMultipleRHS() #4");
1224 else if (node->Column == rc)
1226 for (
int r = 0; r < num_rhs; r++)
1228 rhs(col,r) -= sol(r) * node->Value;
1240 MFEM_ASSERT(rc < height && rc >= 0,
1241 "Row " << rc <<
" not in matrix of height " <<
height);
1245 for (
int j = I[rc]; j < I[rc+1]; j++)
1246 if ((col = J[j]) == rc)
1256 for (
int k = I[col]; 1; k++)
1259 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
1261 else if (J[k] == rc)
1270 RowNode *aux, *node;
1272 for (aux = Rows[rc]; aux != NULL; aux = aux->Prev)
1274 if ((col = aux->Column) == rc)
1284 for (node = Rows[col]; 1; node = node->Prev)
1287 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
1289 else if (node->Column == rc)
1305 MFEM_ASSERT(rc < height && rc >= 0,
1306 "Row " << rc <<
" not in matrix of height " <<
height);
1310 for (
int j = I[rc]; j < I[rc+1]; j++)
1311 if ((col = J[j]) == rc)
1318 for (
int k = I[col]; 1; k++)
1321 mfem_error(
"SparseMatrix::EliminateRowCol() #2");
1323 else if (J[k] == rc)
1332 RowNode *aux, *node;
1334 for (aux = Rows[rc]; aux != NULL; aux = aux->Prev)
1336 if ((col = aux->Column) == rc)
1343 for (node = Rows[col]; 1; node = node->Prev)
1346 mfem_error(
"SparseMatrix::EliminateRowCol() #3");
1348 else if (node->Column == rc)
1365 for (nd = Rows[rc]; nd != NULL; nd = nd->Prev)
1367 if ((col = nd->Column) == rc)
1371 Ae.
Add(rc, rc, nd->Value - 1.0);
1377 Ae.
Add(rc, col, nd->Value);
1379 for (nd2 = Rows[col]; 1; nd2 = nd2->Prev)
1385 else if (nd2->Column == rc)
1387 Ae.
Add(col, rc, nd2->Value);
1397 for (
int j = I[rc]; j < I[rc+1]; j++)
1399 if ((col = J[j]) == rc)
1403 Ae.
Add(rc, rc, A[j] - 1.0);
1409 Ae.
Add(rc, col, A[j]);
1411 for (
int k = I[col];
true; k++)
1417 else if (J[k] == rc)
1419 Ae.
Add(col, rc, A[k]);
1431 for (
int i = 0; i <
height; i++)
1432 if (I[i+1] == I[i]+1 && fabs(A[I[i]]) < 1e-16)
1443 for (i = 0; i <
height; i++)
1446 for (j = I[i]; j < I[i+1]; j++)
1452 for (j = I[i]; j < I[i+1]; j++)
1468 double sum, *yp = y.
GetData();
1469 const double *xp = x.
GetData();
1473 RowNode *diag_p, *n_p, **R = Rows;
1475 for (i = 0; i < s; i++)
1479 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
1480 if ((c = n_p->Column) == i)
1486 sum += n_p->Value * yp[c];
1489 if (diag_p != NULL && diag_p->Value != 0.0)
1491 yp[i] = (xp[i] - sum) / diag_p->Value;
1493 else if (xp[i] == sum)
1499 mfem_error(
"SparseMatrix::Gauss_Seidel_forw()");
1505 int j, end, d, *Ip = I, *Jp = J;
1509 for (i = 0; i < s; i++)
1514 for ( ; j < end; j++)
1515 if ((c = Jp[j]) == i)
1521 sum += Ap[j] * yp[c];
1524 if (d >= 0 && Ap[d] != 0.0)
1526 yp[i] = (xp[i] - sum) / Ap[d];
1528 else if (xp[i] == sum)
1534 mfem_error(
"SparseMatrix::Gauss_Seidel_forw(...) #2");
1543 double sum, *yp = y.
GetData();
1544 const double *xp = x.
GetData();
1548 RowNode *diag_p, *n_p, **R = Rows;
1550 for (i =
height-1; i >= 0; i--)
1554 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev)
1555 if ((c = n_p->Column) == i)
1561 sum += n_p->Value * yp[c];
1564 if (diag_p != NULL && diag_p->Value != 0.0)
1566 yp[i] = (xp[i] - sum) / diag_p->Value;
1568 else if (xp[i] == sum)
1574 mfem_error(
"SparseMatrix::Gauss_Seidel_back()");
1580 int j, beg, d, *Ip = I, *Jp = J;
1584 for (i =
height-1; i >= 0; i--)
1589 for ( ; j >= beg; j--)
1590 if ((c = Jp[j]) == i)
1596 sum += Ap[j] * yp[c];
1599 if (d >= 0 && Ap[d] != 0.0)
1601 yp[i] = (xp[i] - sum) / Ap[d];
1603 else if (xp[i] == sum)
1609 mfem_error(
"SparseMatrix::Gauss_Seidel_back(...) #2");
1617 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1620 for (
int i = 0; i <
height; i++)
1624 for (
int j = I[i]; j < I[i+1]; j++)
1632 if (d >= 0 && A[d] != 0.0)
1634 double a = 1.8 * fabs(A[d]) / norm;
1642 mfem_error(
"SparseMatrix::GetJacobiScaling() #2");
1651 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1653 for (
int i = 0; i <
height; i++)
1657 for (
int j = I[i]; j < I[i+1]; j++)
1665 sum -= A[j] * x0(J[j]);
1668 if (d >= 0 && A[d] != 0.0)
1670 x1(i) = sc * (sum / A[d]) + (1.0 - sc) * x0(i);
1681 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1683 bool scale = (sc != 1.0);
1684 for (
int i = 0, j = 0; i <
height; i++)
1689 MFEM_VERIFY(j != end,
"Couldn't find diagonal in row. i = " << i
1691 <<
", I[i+1] = " << end );
1694 MFEM_VERIFY(std::abs(A[j]) > 0.0,
"Diagonal " << j <<
" must be nonzero");
1697 x(i) = sc * b(i) / A[j];
1714 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1716 for (
int i = 0; i <
height; i++)
1718 double resi = b(i), norm = 0.0;
1719 for (
int j = I[i]; j < I[i+1]; j++)
1721 resi -= A[j] * x0(J[j]);
1726 x1(i) = x0(i) + sc * resi / norm;
1730 MFEM_ABORT(
"L1 norm of row " << i <<
" is zero.");
1738 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
1740 for (
int i = 0; i <
height; i++)
1742 double resi = b(i), sum = 0.0;
1743 for (
int j = I[i]; j < I[i+1]; j++)
1745 resi -= A[j] * x0(J[j]);
1750 x1(i) = x0(i) + sc * resi / sum;
1754 MFEM_ABORT(
"sum of row " << i <<
" is zero.");
1762 int i, j, gi, gj, s, t;
1765 for (i = 0; i < rows.
Size(); i++)
1767 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
1770 "Trying to insert a row " << gi <<
" outside the matrix height "
1773 for (j = 0; j < cols.
Size(); j++)
1775 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
1777 MFEM_ASSERT(gj <
width,
1778 "Trying to insert a column " << gj <<
" outside the matrix width "
1781 if (skip_zeros && a == 0.0)
1785 if (&rows != &cols || subm(j, i) == 0.0)
1790 if (t < 0) { a = -a; }
1802 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
1805 "Trying to insert a row " << gi <<
" outside the matrix height "
1807 if ((gj=j) < 0) { gj = -1-gj, t = -s; }
1809 MFEM_ASSERT(gj <
width,
1810 "Trying to insert a column " << gj <<
" outside the matrix width "
1812 if (t < 0) { a = -a; }
1821 if ((gi=i) < 0) { gi = -1-gi, s = -1; }
1824 "Trying to insert a row " << gi <<
" outside the matrix height "
1826 if ((gj=j) < 0) { gj = -1-gj, t = -s; }
1828 MFEM_ASSERT(gj <
width,
1829 "Trying to insert a column " << gj <<
" outside the matrix width "
1831 if (t < 0) { a = -a; }
1838 int i, j, gi, gj, s, t;
1841 for (i = 0; i < rows.
Size(); i++)
1843 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
1846 "Trying to insert a row " << gi <<
" outside the matrix height "
1849 for (j = 0; j < cols.
Size(); j++)
1852 if (skip_zeros && a == 0.0)
1856 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
1858 MFEM_ASSERT(gj <
width,
1859 "Trying to insert a column " << gj <<
" outside the matrix width "
1861 if (t < 0) { a = -a; }
1873 int i, j, gi, gj, s, t;
1876 for (i = 0; i < rows.
Size(); i++)
1878 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
1881 "Trying to insert a row " << gi <<
" outside the matrix height "
1884 for (j = 0; j < cols.
Size(); j++)
1887 if (skip_zeros && a == 0.0)
1891 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
1893 MFEM_ASSERT(gj <
width,
1894 "Trying to insert a column " << gj <<
" outside the matrix width "
1896 if (t < 0) { a = -a; }
1906 int i, j, gi, gj, s, t;
1909 for (i = 0; i < rows.
Size(); i++)
1911 if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
1914 "Trying to insert a row " << gi <<
" outside the matrix height "
1917 for (j = 0; j < cols.
Size(); j++)
1919 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
1921 MFEM_ASSERT(gj <
width,
1922 "Trying to insert a column " << gj <<
" outside the matrix width "
1925 subm(i, j) = (t < 0) ? (-a) : (a);
1940 "Trying to insert a row " << gi <<
" outside the matrix height "
1944 return (Rows[gi] == NULL);
1948 return (I[gi] == I[gi+1]);
1957 if ((gi=row) < 0) { gi = -1-gi; }
1959 "Trying to insert a row " << gi <<
" outside the matrix height "
1963 for (n = Rows[gi], j = 0; n; n = n->Prev)
1969 for (n = Rows[gi], j = 0; n; n = n->Prev, j++)
1971 cols[j] = n->Column;
1984 cols.
MakeRef(J + j, I[gi+1]-j);
1986 MFEM_ASSERT(row >= 0,
"Row not valid: " << row );
1997 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2000 "Trying to insert a row " << gi <<
" outside the matrix height "
2006 for (
int j = 0; j < cols.
Size(); j++)
2008 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2010 MFEM_ASSERT(gj <
width,
2011 "Trying to insert a column " << gj <<
" outside the matrix"
2012 " width " <<
width);
2014 if (t < 0) { a = -a; }
2022 MFEM_ASSERT(cols.
Size() == srow.
Size(),
"");
2024 for (
int i = I[gi], j = 0; j < cols.
Size(); j++, i++)
2026 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2028 MFEM_ASSERT(gj <
width,
2029 "Trying to insert a column " << gj <<
" outside the matrix"
2030 " width " <<
width);
2042 int j, gi, gj, s, t;
2045 MFEM_VERIFY(!
Finalized(),
"Matrix must NOT be finalized.");
2047 if ((gi=row) < 0) { gi = -1-gi, s = -1; }
2050 "Trying to insert a row " << gi <<
" outside the matrix height "
2053 for (j = 0; j < cols.
Size(); j++)
2055 if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
2057 MFEM_ASSERT(gj <
width,
2058 "Trying to insert a column " << gj <<
" outside the matrix width "
2065 if (t < 0) { a = -a; }
2083 for (aux = Rows[i]; aux != NULL; aux = aux -> Prev)
2085 aux -> Value *= scale;
2090 int j, end = I[i+1];
2092 for (j = I[i]; j < end; j++)
2105 for (
int i=0; i <
height; ++i)
2108 for (aux = Rows[i]; aux != NULL; aux = aux -> Prev)
2110 aux -> Value *= scale;
2118 for (
int i=0; i <
height; ++i)
2122 for (j = I[i]; j < end; j++)
2135 for (
int i=0; i <
height; ++i)
2137 for (aux = Rows[i]; aux != NULL; aux = aux -> Prev)
2139 aux -> Value *= sr(aux->Column);
2147 for (
int i=0; i <
height; ++i)
2150 for (j = I[i]; j < end; j++)
2161 "Mismatch of this matrix size and rhs. This height = "
2162 <<
height <<
", width = " <<
width <<
", B.height = "
2165 for (
int i = 0; i <
height; i++)
2170 for (RowNode *aux = B.Rows[i]; aux != NULL; aux = aux->Prev)
2172 _Add_(aux->Column, aux->Value);
2177 for (
int j = B.I[i]; j < B.I[i+1]; j++)
2179 _Add_(B.J[j], B.A[j]);
2190 for (
int i = 0; i <
height; i++)
2195 for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
2197 np->Value += a * B.
_Get_(np->Column);
2202 for (
int j = I[i]; j < I[i+1]; j++)
2204 A[j] += a * B.
_Get_(J[j]);
2214 for (
int i = 0, nnz = I[
height]; i < nnz; i++)
2219 for (
int i = 0; i <
height; i++)
2220 for (RowNode *node_p = Rows[i]; node_p != NULL;
2221 node_p = node_p -> Prev)
2223 node_p -> Value = a;
2232 for (
int i = 0, nnz = I[
height]; i < nnz; i++)
2237 for (
int i = 0; i <
height; i++)
2238 for (RowNode *node_p = Rows[i]; node_p != NULL;
2239 node_p = node_p -> Prev)
2241 node_p -> Value *= a;
2254 for (i = 0; i <
height; i++)
2256 out <<
"[row " << i <<
"]\n";
2257 for (nd = Rows[i], j = 0; nd != NULL; nd = nd->Prev, j++)
2259 out <<
" (" << nd->Column <<
"," << nd->Value <<
")";
2260 if ( !((j+1) % _width) )
2273 for (i = 0; i <
height; i++)
2275 out <<
"[row " << i <<
"]\n";
2276 for (j = I[i]; j < I[i+1]; j++)
2278 out <<
" (" << J[j] <<
"," << A[j] <<
")";
2279 if ( !((j+1-I[i]) % _width) )
2284 if ((j-I[i]) % _width)
2293 out <<
"% size " <<
height <<
" " <<
width <<
"\n";
2296 ios::fmtflags old_fmt = out.flags();
2297 out.setf(ios::scientific);
2298 std::streamsize old_prec = out.precision(14);
2300 for (i = 0; i <
height; i++)
2301 for (j = I[i]; j < I[i+1]; j++)
2303 out << i+1 <<
" " << J[j]+1 <<
" " << A[j] <<
'\n';
2305 out.precision(old_prec);
2312 ios::fmtflags old_fmt = out.flags();
2313 out.setf(ios::scientific);
2314 std::streamsize old_prec = out.precision(14);
2316 out <<
"%%MatrixMarket matrix coordinate real general" <<
'\n'
2317 <<
"% Generated by MFEM" <<
'\n';
2320 for (i = 0; i <
height; i++)
2321 for (j = I[i]; j < I[i+1]; j++)
2323 out << i+1 <<
" " << J[j]+1 <<
" " << A[j] <<
'\n';
2325 out.precision(old_prec);
2331 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2337 for (i = 0; i <=
height; i++)
2339 out << I[i]+1 <<
'\n';
2342 for (i = 0; i < I[
height]; i++)
2344 out << J[i]+1 <<
'\n';
2347 for (i = 0; i < I[
height]; i++)
2349 out << A[i] <<
'\n';
2355 MFEM_VERIFY(
Finalized(),
"Matrix must be finalized.");
2360 out <<
width <<
'\n';
2362 for (i = 0; i <=
height; i++)
2364 out << I[i] <<
'\n';
2367 for (i = 0; i < I[
height]; i++)
2369 out << J[i] <<
'\n';
2372 for (i = 0; i < I[
height]; i++)
2374 out << A[i] <<
'\n';
2378 void SparseMatrix::Destroy()
2380 if (I != NULL && ownGraph)
2384 if (J != NULL && ownGraph)
2388 if (A != NULL && ownData)
2395 #if !defined(MFEM_USE_MEMALLOC)
2396 for (
int i = 0; i <
height; i++)
2398 RowNode *aux, *node_p = Rows[i];
2399 while (node_p != NULL)
2402 node_p = node_p->Prev;
2410 if (ColPtrJ != NULL)
2414 if (ColPtrNode != NULL)
2416 delete [] ColPtrNode;
2418 #ifdef MFEM_USE_MEMALLOC
2419 if (NodesMem != NULL)
2432 int *end_j = J + I[
height];
2433 for (
int *jptr = start_j; jptr != end_j; ++jptr)
2435 awidth = std::max(awidth, *jptr + 1);
2441 for (
int i = 0; i <
height; i++)
2443 for (aux = Rows[i]; aux != NULL; aux = aux->Prev)
2445 awidth = std::max(awidth, aux->Column + 1);
2457 for (
int i = 0; i < n; i++)
2467 "Finalize must be called before Transpose. Use TransposeRowMatrix instead");
2470 int m, n, nnz, *A_i, *A_j, *At_i, *At_j;
2471 double *A_data, *At_data;
2480 At_i =
new int[n+1];
2481 At_j =
new int[nnz];
2482 At_data =
new double[nnz];
2484 for (i = 0; i <= n; i++)
2488 for (i = 0; i < nnz; i++)
2492 for (i = 1; i < n; i++)
2494 At_i[i+1] += At_i[i];
2497 for (i = j = 0; i < m; i++)
2500 for ( ; j < end; j++)
2502 At_j[At_i[A_j[j]]] = i;
2503 At_data[At_i[A_j[j]]] = A_data[j];
2508 for (i = n; i > 0; i--)
2510 At_i[i] = At_i[i-1];
2521 int m, n, nnz, *At_i, *At_j;
2531 for (i = 0; i < m; i++)
2533 A.
GetRow(i, Acols, Avals);
2551 At_i =
new int[n+1];
2552 At_j =
new int[nnz];
2553 At_data =
new double[nnz];
2555 for (i = 0; i <= n; i++)
2560 for (i = 0; i < m; i++)
2562 A.
GetRow(i, Acols, Avals);
2563 for (j = 0; j<Acols.
Size(); ++j)
2568 for (i = 1; i < n; i++)
2570 At_i[i+1] += At_i[i];
2573 for (i = 0; i < m; i++)
2575 A.
GetRow(i, Acols, Avals);
2576 for (j = 0; j<Acols.
Size(); ++j)
2578 At_j[At_i[Acols[j]]] = i;
2579 At_data[At_i[Acols[j]]] = Avals[j];
2584 for (i = n; i > 0; i--)
2586 At_i[i] = At_i[i-1];
2597 int nrowsA, ncolsA, nrowsB, ncolsB;
2598 int *A_i, *A_j, *B_i, *B_j, *C_i, *C_j, *B_marker;
2599 double *A_data, *B_data, *C_data;
2600 int ia, ib, ic, ja, jb, num_nonzeros;
2601 int row_start, counter;
2602 double a_entry, b_entry;
2610 MFEM_VERIFY(ncolsA == nrowsB,
2611 "number of columns of A (" << ncolsA
2612 <<
") must equal number of rows of B (" << nrowsB <<
")");
2621 B_marker =
new int[ncolsB];
2623 for (ib = 0; ib < ncolsB; ib++)
2630 C_i =
new int[nrowsA+1];
2632 C_i[0] = num_nonzeros = 0;
2633 for (ic = 0; ic < nrowsA; ic++)
2635 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
2638 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
2641 if (B_marker[jb] != ic)
2648 C_i[ic+1] = num_nonzeros;
2651 C_j =
new int[num_nonzeros];
2652 C_data =
new double[num_nonzeros];
2654 C =
new SparseMatrix (C_i, C_j, C_data, nrowsA, ncolsB);
2656 for (ib = 0; ib < ncolsB; ib++)
2665 MFEM_VERIFY(nrowsA == C -> Height() && ncolsB == C -> Width(),
2666 "Input matrix sizes do not match output sizes"
2667 <<
" nrowsA = " << nrowsA
2668 <<
", C->Height() = " << C->
Height()
2669 <<
" ncolsB = " << ncolsB
2670 <<
", C->Width() = " << C->
Width());
2674 C_data = C -> GetData();
2678 for (ic = 0; ic < nrowsA; ic++)
2681 row_start = counter;
2682 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++)
2685 a_entry = A_data[ia];
2686 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++)
2689 b_entry = B_data[ib];
2690 if (B_marker[jb] < row_start)
2692 B_marker[jb] = counter;
2697 C_data[counter] = a_entry*b_entry;
2702 C_data[B_marker[jb]] += a_entry*b_entry;
2710 "With pre-allocated output matrix, number of non-zeros ("
2712 <<
") did not match number of entries changed from matrix-matrix multiply, "
2723 int nrowsA, ncolsA, nrowsB, ncolsB;
2724 int *C_i, *C_j, *B_marker;
2726 int ia, ib, ic, ja, jb, num_nonzeros;
2727 int row_start, counter;
2728 double a_entry, b_entry;
2736 MFEM_VERIFY(ncolsA == nrowsB,
2737 "number of columns of A (" << ncolsA
2738 <<
") must equal number of rows of B (" << nrowsB <<
")");
2740 B_marker =
new int[ncolsB];
2742 for (ib = 0; ib < ncolsB; ib++)
2747 C_i =
new int[nrowsA+1];
2749 C_i[0] = num_nonzeros = 0;
2753 for (ic = 0; ic < nrowsA; ic++)
2755 A.
GetRow(ic, colsA, dataA);
2756 for (ia = 0; ia < colsA.
Size(); ia++)
2759 B.
GetRow(ja, colsB, dataB);
2760 for (ib = 0; ib < colsB.
Size(); ib++)
2763 if (B_marker[jb] != ic)
2770 C_i[ic+1] = num_nonzeros;
2773 C_j =
new int[num_nonzeros];
2774 C_data =
new double[num_nonzeros];
2776 C =
new SparseMatrix(C_i, C_j, C_data, nrowsA, ncolsB);
2778 for (ib = 0; ib < ncolsB; ib++)
2784 for (ic = 0; ic < nrowsA; ic++)
2786 row_start = counter;
2787 A.
GetRow(ic, colsA, dataA);
2788 for (ia = 0; ia < colsA.
Size(); ia++)
2791 a_entry = dataA[ia];
2792 B.
GetRow(ja, colsB, dataB);
2793 for (ib = 0; ib < colsB.
Size(); ib++)
2796 b_entry = dataB[ib];
2797 if (B_marker[jb] < row_start)
2799 B_marker[jb] = counter;
2801 C_data[counter] = a_entry*b_entry;
2806 C_data[B_marker[jb]] += a_entry*b_entry;
2821 for (
int j = 0; j < B.
Width(); ++j)
2825 A.
Mult(columnB, columnC);
2835 Mult (R, *AP, *_RAP);
2865 int i, At_nnz, *At_j;
2869 At_nnz = At -> NumNonZeroElems();
2870 At_j = At -> GetJ();
2871 At_data = At -> GetData();
2872 for (i = 0; i < At_nnz; i++)
2874 At_data[i] *= D(At_j[i]);
2885 int ncols = A.
Width();
2887 int * C_i =
new int[nrows+1];
2891 int * A_i = A.
GetI();
2892 int * A_j = A.
GetJ();
2893 double * A_data = A.
GetData();
2895 int * B_i = B.
GetI();
2896 int * B_j = B.
GetJ();
2897 double * B_data = B.
GetData();
2899 int * marker =
new int[ncols];
2900 std::fill(marker, marker+ncols, -1);
2902 int num_nonzeros = 0, jcol;
2904 for (
int ic = 0; ic < nrows; ic++)
2906 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
2912 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
2915 if (marker[jcol] != ic)
2921 C_i[ic+1] = num_nonzeros;
2924 C_j =
new int[num_nonzeros];
2925 C_data =
new double[num_nonzeros];
2927 for (
int ia = 0; ia < ncols; ia++)
2933 for (
int ic = 0; ic < nrows; ic++)
2935 for (
int ia = A_i[ic]; ia < A_i[ic+1]; ia++)
2939 C_data[pos] = a*A_data[ia];
2943 for (
int ib = B_i[ic]; ib < B_i[ic+1]; ib++)
2946 if (marker[jcol] < C_i[ic])
2949 C_data[pos] = b*B_data[ib];
2955 C_data[marker[jcol]] += b*B_data[ib];
2961 return new SparseMatrix(C_i, C_j, C_data, nrows, ncols);
2966 return Add(1.,A,1.,B);
2971 MFEM_ASSERT(Ai.
Size() > 0,
"invalid size Ai.Size() = " << Ai.
Size());
2976 for (
int i=1; i < Ai.
Size(); ++i)
2978 result =
Add(*accumulate, *Ai[i]);
2984 accumulate = result;
3002 #ifdef MFEM_USE_MEMALLOC
double GetJacobiScaling() const
Determine appropriate scaling for Jacobi iteration.
int Size() const
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.
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 _Add_(const int col, const double a)
void NewDataAndSize(double *d, int s)
void Clear()
Clear the contents of the SparseMatrix.
void Print(std::ostream &out=std::cout, int width_=4) const
Prints matrix to stream out.
void DiagScale(const Vector &b, Vector &x, double sc=1.0) const
void MakeRef(const SparseMatrix &master)
void SetSize(int s)
Resize the vector if the new size is different.
double & SearchRow(const int col)
void PrintMM(std::ostream &out=std::cout) const
Prints matrix in Matrix Market sparse format.
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, but treat all elements 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.
Abstract data type for sparse matrices.
SparseMatrix & operator+=(const SparseMatrix &B)
void EliminateRowCol(int rc, const double sol, Vector &rhs, int d=0)
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.
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const
y += At * x (default) or y += a * At * x
Abstract data type for matrix inverse.
virtual int NumNonZeroElems() const =0
Returns the number of non-zeros in a matrix.
void EliminateRowColMultipleRHS(int rc, const Vector &sol, DenseMatrix &rhs, int d=0)
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.
void SortColumnIndices()
Sort the column indices corresponding to each row.
void _Set_(const int col, const double a)
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, but treat all elements 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
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
void ScaleRow(const int row, const double scale)
int ActualWidth()
Returns the actual Width of the matrix.
void Symmetrize()
(*this) = 1/2 ((*this) + (*this)^t)
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
void EliminateCol(int col)
void ScaleColumns(const Vector &sr)
void PrintCSR2(std::ostream &out) const
Prints a sparse matrix to stream out in CSR format.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
SparseMatrix()
Create an empty SparseMatrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows.
void EliminateCols(Array< int > &cols, Vector *x=NULL, Vector *b=NULL)
Eliminate all columns 'i' for which cols[i] != 0.
void SetWidth(int width_=-1)
Change the width of a SparseMatrix.
HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P)
Returns the matrix P^t * A * P.
double IsSymmetric() const
Returns max_{i,j} |(i,j)-(j,i)| for a finalized matrix.
void SetDiagIdentity()
If a row contains only one diag entry of zero, set it to 1.
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
void ScaleRows(const Vector &sl)
void Sort()
Sorts the array. This requires operator< to be defined for T.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const =0
virtual void Finalize(int skip_zeros=1)
void EliminateZeroRows()
If a row contains only zeros, set its diagonal to 1.
double * GetData() const
Return element data.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
int * GetI() const
Return the array I.
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)
void SparseMatrixFunction(SparseMatrix &S, double(*f)(double))
Applies f() to each element of the matrix (after it is finalized).
virtual MatrixInverse * Inverse() const
Returns a pointer to approximation of the matrix inverse.
void Swap(Array< T > &, Array< T > &)
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
SparseMatrix & operator=(double a)
void SetSubMatrixTranspose(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void mfem_error(const char *msg)
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
void Set(const int i, const int j, const double a)
void PrintMatlab(std::ostream &out=std::cout) const
Prints matrix in matlab format.
void GetColumnReference(int c, Vector &col)
void Gauss_Seidel_back(const Vector &x, Vector &y) const
void Gauss_Seidel_forw(const Vector &x, Vector &y) const
Gauss-Seidel forward and backward iterations over a vector x.
void EliminateRow(int row, const double sol, Vector &rhs)
Eliminates a column from the transpose matrix.
void GetDiag(Vector &d) const
Returns the Diagonal of A.
double GetRowNorml1(int irow) const
For i = irow compute .
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.
SparseMatrix & operator*=(double a)
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
void MakeRef(T *, int)
Make this Array a reference to a pointer.
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm)
void Jacobi2(const Vector &b, const Vector &x0, Vector &x1, double sc=1.0) const
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.
double _Get_(const int col) const
void Swap(SparseMatrix &other)
int * GetJ() const
Return the array J.
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.
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)