MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 // Implementation of sparse matrix 00013 00014 #include <iostream> 00015 #include <iomanip> 00016 #include <math.h> 00017 00018 #include "linalg.hpp" 00019 #include "../general/table.hpp" 00020 00021 SparseMatrix::SparseMatrix(int nrows, int ncols) 00022 : Matrix(nrows) 00023 { 00024 I = NULL; 00025 J = NULL; 00026 A = NULL; 00027 00028 Rows = new RowNode *[nrows]; 00029 width = (ncols) ? (ncols) : (nrows); 00030 for (int i = 0; i < nrows; i++) 00031 Rows[i] = NULL; 00032 ColPtr.Node = NULL; 00033 } 00034 00035 int SparseMatrix::RowSize(int i) 00036 { 00037 if (I) 00038 return I[i+1]-I[i]; 00039 00040 int s = 0; 00041 RowNode *row = Rows[i]; 00042 for ( ; row != NULL; row = row->Prev) 00043 if (row->Value != 0.0) 00044 s++; 00045 return s; 00046 } 00047 00048 double &SparseMatrix::Elem(int i, int j) 00049 { 00050 return operator()(i,j); 00051 } 00052 00053 const double &SparseMatrix::Elem(int i, int j) const 00054 { 00055 return operator()(i,j); 00056 } 00057 00058 double &SparseMatrix::operator()(int i, int j) 00059 { 00060 int k, end; 00061 00062 #ifdef MFEM_DEBUG 00063 if (i >= size || i < 0 || j >= width || j < 0) 00064 mfem_error("SparseMatrix::operator() #1"); 00065 #endif 00066 00067 if (A == NULL) 00068 mfem_error("SparseMatrix::operator() #2"); 00069 00070 end = I[i+1]; 00071 for (k = I[i]; k < end; k++) 00072 if (J[k] == j) 00073 return A[k]; 00074 00075 mfem_error("SparseMatrix::operator() #3"); 00076 return A[0]; 00077 } 00078 00079 const double &SparseMatrix::operator()(int i, int j) const 00080 { 00081 int k, end; 00082 static const double zero = 0.0; 00083 00084 #ifdef MFEM_DEBUG 00085 if (i >= size || i < 0 || j >= width || j < 0) 00086 mfem_error("SparseMatrix::operator() const #1"); 00087 #endif 00088 00089 if (A == NULL) 00090 mfem_error("SparseMatrix::operator() const #2"); 00091 end = I[i+1]; 00092 for (k = I[i]; k < end; k++) 00093 if (J[k] == j) 00094 return A[k]; 00095 00096 return zero; 00097 } 00098 00099 void SparseMatrix::Mult(const Vector &x, Vector &y) const 00100 { 00101 y = 0.0; 00102 AddMult(x, y); 00103 } 00104 00105 void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const 00106 { 00107 #ifdef MFEM_DEBUG 00108 if (( width != x.Size() ) || ( size != y.Size() )) 00109 mfem_error("SparseMatrix::AddMult() #1"); 00110 #endif 00111 00112 int i, j, end; 00113 double *Ap = A, *yp = y.GetData(); 00114 const double *xp = x.GetData(); 00115 00116 if (Ap == NULL) 00117 { 00118 // The matrix is not finalized, but multiplication is still possible 00119 for (i = 0; i < size; i++) 00120 { 00121 RowNode *row = Rows[i]; 00122 double b = 0.0; 00123 for ( ; row != NULL; row = row->Prev) 00124 b += row->Value * xp[row->Column]; 00125 *yp += a * b; 00126 yp++; 00127 } 00128 return; 00129 } 00130 00131 int *Jp = J, *Ip = I; 00132 00133 j = *Ip; 00134 if (a == 1.0) 00135 { 00136 #ifndef MFEM_USE_OPENMP 00137 for (i = 0; i < size; i++) 00138 { 00139 double d = 0.0; 00140 Ip++; 00141 end = (*Ip); 00142 for ( ; j < end; j++) 00143 { 00144 d += (*Ap) * xp[*Jp]; 00145 Ap++; 00146 Jp++; 00147 } 00148 *yp += d; 00149 yp++; 00150 } 00151 #else 00152 #pragma omp parallel for private(j,end) 00153 for (i = 0; i < size; i++) 00154 { 00155 double d = 0.0; 00156 for (j = Ip[i], end = Ip[i+1]; j < end; j++) 00157 { 00158 d += Ap[j] * xp[Jp[j]]; 00159 } 00160 yp[i] += d; 00161 } 00162 #endif 00163 } 00164 else 00165 for (i = 0; i < size; i++) 00166 { 00167 double d = 0.0; 00168 Ip++; 00169 end = (*Ip); 00170 for ( ; j < end; j++) 00171 { 00172 d += (*Ap) * xp[*Jp]; 00173 Ap++; 00174 Jp++; 00175 } 00176 *yp += a * d; 00177 yp++; 00178 } 00179 } 00180 00181 void SparseMatrix::MultTranspose(const Vector &x, Vector &y) const 00182 { 00183 y = 0.0; 00184 AddMultTranspose(x, y); 00185 } 00186 00187 void SparseMatrix::AddMultTranspose(const Vector &x, Vector &y, 00188 const double a) const 00189 { 00190 #ifdef MFEM_DEBUG 00191 if (( size != x.Size() ) || ( width != y.Size() )) 00192 mfem_error("SparseMatrix::AddMultTranspose() #1"); 00193 #endif 00194 00195 int i, j, end; 00196 double *yp = y.GetData(); 00197 00198 if (A == NULL) 00199 { 00200 // The matrix is not finalized, but multiplication is still possible 00201 for (i = 0; i < size; i++) 00202 { 00203 RowNode *row = Rows[i]; 00204 double b = a * x(i); 00205 for ( ; row != NULL; row = row->Prev) 00206 yp[row->Column] += row->Value * b; 00207 } 00208 return; 00209 } 00210 00211 for (i = 0; i < size; i++) 00212 { 00213 double xi = a * x(i); 00214 end = I[i+1]; 00215 for(j = I[i]; j < end; j++) 00216 { 00217 yp[J[j]] += A[j]*xi; 00218 } 00219 } 00220 } 00221 00222 void SparseMatrix::PartMult( 00223 const Array<int> &rows, const Vector &x, Vector &y) 00224 { 00225 if (A) 00226 { 00227 for (int i = 0; i < rows.Size(); i++) 00228 { 00229 int r = rows[i]; 00230 int end = I[r+1]; 00231 double a = 0.0; 00232 for (int j = I[r]; j < end; j++) 00233 a += A[j] * x(J[j]); 00234 y(r) = a; 00235 } 00236 } 00237 else 00238 { 00239 mfem_error("SparseMatrix::PartMult"); 00240 } 00241 } 00242 00243 double SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const 00244 { 00245 double prod = 0.0; 00246 for (int i = 0; i < size; i++) 00247 { 00248 double a = 0.0; 00249 if (A) 00250 for (int j = I[i], end = I[i+1]; j < end; j++) 00251 a += A[j] * x(J[j]); 00252 else 00253 for (RowNode *np = Rows[i]; np != NULL; np = np->Prev) 00254 a += np->Value * x(np->Column); 00255 prod += a * y(i); 00256 } 00257 00258 return prod; 00259 } 00260 00261 void SparseMatrix::GetRowSums(Vector &x) const 00262 { 00263 for (int i = 0; i < size; i++) 00264 { 00265 double a = 0.0; 00266 if (A) 00267 for (int j = I[i], end = I[i+1]; j < end; j++) 00268 a += A[j]; 00269 else 00270 for (RowNode *np = Rows[i]; np != NULL; np = np->Prev) 00271 a += np->Value; 00272 x(i) = a; 00273 } 00274 } 00275 00276 void SparseMatrix::Finalize(int skip_zeros) 00277 { 00278 int i, j, nr, nz; 00279 RowNode *aux; 00280 00281 delete [] ColPtr.Node; 00282 ColPtr.J = NULL; 00283 00284 I = new int[size+1]; 00285 I[0] = 0; 00286 for (i = 1; i <= size; i++) 00287 { 00288 nr = 0; 00289 for (aux = Rows[i-1]; aux != NULL; aux = aux->Prev) 00290 if (!skip_zeros || aux->Value != 0.0) 00291 nr++; 00292 I[i] = I[i-1] + nr; 00293 } 00294 nz = I[size]; 00295 J = new int[nz]; 00296 A = new double[nz]; 00297 for (j = i = 0; i < size; i++) 00298 for (aux = Rows[i]; aux != NULL; aux = aux->Prev) 00299 if (!skip_zeros || aux->Value != 0.0) 00300 { 00301 J[j] = aux->Column; 00302 A[j] = aux->Value; 00303 j++; 00304 } 00305 #ifdef MFEM_USE_MEMALLOC 00306 NodesMem.Clear(); 00307 #else 00308 for (i = 0; i < size; i++) 00309 { 00310 RowNode *node_p = Rows[i]; 00311 while (node_p != NULL) 00312 { 00313 aux = node_p; 00314 node_p = node_p->Prev; 00315 delete aux; 00316 } 00317 } 00318 #endif 00319 delete [] Rows; 00320 Rows = NULL; 00321 } 00322 00323 void SparseMatrix::GetBlocks(Array2D<SparseMatrix *> &blocks) const 00324 { 00325 if (A) 00326 mfem_error("SparseMatrix::GetBlocks : matrix is finalized!"); 00327 00328 int br = blocks.NumRows(), bc = blocks.NumCols(); 00329 int nr = (size + br - 1)/br, nc = (width + bc - 1)/bc; 00330 00331 for (int j = 0; j < bc; j++) 00332 for (int i = 0; i < br; i++) 00333 { 00334 int *bI = new int[nr + 1]; 00335 for (int k = 0; k <= nr; k++) 00336 bI[k] = 0; 00337 blocks(i,j) = new SparseMatrix(bI, NULL, NULL, nr, nc); 00338 } 00339 00340 for (int gr = 0; gr < size; gr++) 00341 { 00342 int bi = gr/nr, i = gr%nr + 1; 00343 for (RowNode *n_p = Rows[gr]; n_p != NULL; n_p = n_p->Prev) 00344 if (n_p->Value != 0.0) 00345 blocks(bi,n_p->Column/nc)->I[i]++; 00346 } 00347 00348 for (int j = 0; j < bc; j++) 00349 for (int i = 0; i < br; i++) 00350 { 00351 SparseMatrix &b = *blocks(i,j); 00352 int nnz = 0, rs; 00353 for (int k = 1; k <= nr; k++) 00354 rs = b.I[k], b.I[k] = nnz, nnz += rs; 00355 b.J = new int[nnz]; 00356 b.A = new double[nnz]; 00357 } 00358 00359 for (int gr = 0; gr < size; gr++) 00360 { 00361 int bi = gr/nr, i = gr%nr + 1; 00362 for (RowNode *n_p = Rows[gr]; n_p != NULL; n_p = n_p->Prev) 00363 if (n_p->Value != 0.0) 00364 { 00365 SparseMatrix &b = *blocks(bi,n_p->Column/nc); 00366 b.J[b.I[i]] = n_p->Column % nc; 00367 b.A[b.I[i]] = n_p->Value; 00368 b.I[i]++; 00369 } 00370 } 00371 } 00372 00373 double SparseMatrix::IsSymmetric() const 00374 { 00375 if (A == NULL) 00376 mfem_error("SparseMatrix::IsSymmetric()"); 00377 00378 int i, j; 00379 double a, max; 00380 00381 max = 0.0; 00382 for (i = 1; i < size; i++) 00383 for (j = I[i]; j < I[i+1]; j++) 00384 if (J[j] < i) 00385 { 00386 a = fabs ( A[j] - (*this)(J[j],i) ); 00387 if (max < a) 00388 max = a; 00389 } 00390 00391 return max; 00392 } 00393 00394 void SparseMatrix::Symmetrize() 00395 { 00396 if (A == NULL) 00397 mfem_error("SparseMatrix::Symmetrize()"); 00398 00399 int i, j; 00400 for (i = 1; i < size; i++) 00401 for (j = I[i]; j < I[i+1]; j++) 00402 if (J[j] < i) 00403 { 00404 A[j] += (*this)(J[j],i); 00405 A[j] *= 0.5; 00406 (*this)(J[j],i) = A[j]; 00407 } 00408 } 00409 00410 int SparseMatrix::NumNonZeroElems() const 00411 { 00412 if (A != NULL) // matrix is finalized 00413 { 00414 return I[size]; 00415 } 00416 else 00417 { 00418 int nnz = 0; 00419 00420 for (int i = 0; i < size; i++) 00421 for (RowNode *node_p = Rows[i]; node_p != NULL; node_p = node_p->Prev) 00422 nnz++; 00423 00424 return nnz; 00425 } 00426 } 00427 00428 double SparseMatrix::MaxNorm() const 00429 { 00430 double m = 0.0; 00431 00432 if (A) 00433 { 00434 int nnz = I[size]; 00435 for (int j = 0; j < nnz; j++) 00436 m = fmax(m, fabs(A[j])); 00437 } 00438 else 00439 { 00440 for (int i = 0; i < size; i++) 00441 for (RowNode *n_p = Rows[i]; n_p != NULL; n_p = n_p->Prev) 00442 m = fmax(m, fabs(n_p->Value)); 00443 } 00444 return m; 00445 } 00446 00447 int SparseMatrix::CountSmallElems(double tol) 00448 { 00449 int i, counter = 0; 00450 00451 if (A) 00452 { 00453 int nz = I[size]; 00454 double *Ap = A; 00455 00456 for (i = 0; i < nz; i++) 00457 if (fabs(Ap[i]) < tol) 00458 counter++; 00459 } 00460 else 00461 { 00462 RowNode *aux; 00463 00464 for (i = 0; i < size; i++) 00465 for (aux = Rows[i]; aux != NULL; aux = aux->Prev) 00466 if (fabs(aux -> Value) < tol) 00467 counter++; 00468 } 00469 00470 return counter; 00471 } 00472 00473 MatrixInverse *SparseMatrix::Inverse() const 00474 { 00475 return NULL; 00476 } 00477 00478 void SparseMatrix::EliminateRow(int row, const double sol, Vector &rhs) 00479 { 00480 RowNode *aux; 00481 00482 #ifdef MFEM_DEBUG 00483 if ( row >= size || row < 0 ) 00484 mfem_error("SparseMatrix::EliminateRow () #1"); 00485 #endif 00486 00487 if (Rows == NULL) 00488 mfem_error("SparseMatrix::EliminateRow () #2"); 00489 00490 for (aux = Rows[row]; aux != NULL; aux = aux->Prev) 00491 { 00492 rhs(aux->Column) -= sol * aux->Value; 00493 aux->Value = 0.0; 00494 } 00495 } 00496 00497 void SparseMatrix::EliminateRow(int row) 00498 { 00499 RowNode *aux; 00500 00501 #ifdef MFEM_DEBUG 00502 if ( row >= size || row < 0 ) 00503 mfem_error("SparseMatrix::EliminateRow () #1"); 00504 #endif 00505 00506 if (Rows == NULL) 00507 mfem_error("SparseMatrix::EliminateRow () #2"); 00508 00509 for (aux = Rows[row]; aux != NULL; aux = aux->Prev) 00510 aux->Value = 0.0; 00511 } 00512 00513 void SparseMatrix::EliminateCol(int col) 00514 { 00515 RowNode *aux; 00516 00517 if (Rows == NULL) 00518 mfem_error("SparseMatrix::EliminateCol () #1"); 00519 00520 for (int i = 0; i < size; i++) 00521 for (aux = Rows[i]; aux != NULL; aux = aux->Prev) 00522 if (aux -> Column == col) 00523 aux->Value = 0.0; 00524 } 00525 00526 void SparseMatrix::EliminateCols(Array<int> &cols, Vector *x, Vector *b) 00527 { 00528 RowNode *aux; 00529 00530 if (Rows == NULL) 00531 mfem_error("SparseMatrix::EliminateCols () #1"); 00532 00533 for (int i = 0; i < size; i++) 00534 for (aux = Rows[i]; aux != NULL; aux = aux->Prev) 00535 if (cols[aux -> Column]) 00536 { 00537 if (x && b) 00538 (*b)(i) -= aux -> Value * (*x)(aux -> Column); 00539 aux->Value = 0.0; 00540 } 00541 } 00542 00543 void SparseMatrix::EliminateRowCol(int rc, const double sol, Vector &rhs, 00544 int d) 00545 { 00546 int col; 00547 00548 #ifdef MFEM_DEBUG 00549 if ( rc >= size || rc < 0 ) 00550 mfem_error("SparseMatrix::EliminateRowCol () #1"); 00551 #endif 00552 00553 if (Rows == NULL) 00554 for (int j = I[rc]; j < I[rc+1]; j++) 00555 if ((col = J[j]) == rc) 00556 if (d) 00557 { 00558 rhs(rc) = A[j] * sol; 00559 } 00560 else 00561 { 00562 A[j] = 1.0; 00563 rhs(rc) = sol; 00564 } 00565 else 00566 { 00567 A[j] = 0.0; 00568 for (int k = I[col]; 1; k++) 00569 if (k == I[col+1]) 00570 { 00571 mfem_error("SparseMatrix::EliminateRowCol () #2"); 00572 } 00573 else if (J[k] == rc) 00574 { 00575 rhs(col) -= sol * A[k]; 00576 A[k] = 0.0; 00577 break; 00578 } 00579 } 00580 else 00581 for (RowNode *aux = Rows[rc]; aux != NULL; aux = aux->Prev) 00582 if ((col = aux->Column) == rc) 00583 if (d) 00584 { 00585 rhs(rc) = aux->Value * sol; 00586 } 00587 else 00588 { 00589 aux->Value = 1.0; 00590 rhs(rc) = sol; 00591 } 00592 else 00593 { 00594 aux->Value = 0.0; 00595 for (RowNode *node = Rows[col]; 1; node = node->Prev) 00596 if (node == NULL) 00597 { 00598 mfem_error("SparseMatrix::EliminateRowCol () #3"); 00599 } 00600 else if (node->Column == rc) 00601 { 00602 rhs(col) -= sol * node->Value; 00603 node->Value = 0.0; 00604 break; 00605 } 00606 } 00607 } 00608 00609 void SparseMatrix::EliminateRowColMultipleRHS(int rc, const Vector &sol, 00610 DenseMatrix &rhs, int d) 00611 { 00612 int col; 00613 int num_rhs = rhs.Width(); 00614 00615 #ifdef MFEM_DEBUG 00616 if (rc >= size || rc < 0) 00617 mfem_error("SparseMatrix::EliminateRowColMultipleRHS() #1"); 00618 if (sol.Size() != num_rhs) 00619 mfem_error("SparseMatrix::EliminateRowColMultipleRHS() #2"); 00620 #endif 00621 00622 if (Rows == NULL) 00623 for (int j = I[rc]; j < I[rc+1]; j++) 00624 if ((col = J[j]) == rc) 00625 if (d) 00626 { 00627 for (int r = 0; r < num_rhs; r++) 00628 rhs(rc,r) = A[j] * sol(r); 00629 } 00630 else 00631 { 00632 A[j] = 1.0; 00633 for (int r = 0; r < num_rhs; r++) 00634 rhs(rc,r) = sol(r); 00635 } 00636 else 00637 { 00638 A[j] = 0.0; 00639 for (int k = I[col]; 1; k++) 00640 if (k == I[col+1]) 00641 { 00642 mfem_error("SparseMatrix::EliminateRowColMultipleRHS() #3"); 00643 } 00644 else if (J[k] == rc) 00645 { 00646 for (int r = 0; r < num_rhs; r++) 00647 rhs(col,r) -= sol(r) * A[k]; 00648 A[k] = 0.0; 00649 break; 00650 } 00651 } 00652 else 00653 for (RowNode *aux = Rows[rc]; aux != NULL; aux = aux->Prev) 00654 if ((col = aux->Column) == rc) 00655 if (d) 00656 { 00657 for (int r = 0; r < num_rhs; r++) 00658 rhs(rc,r) = aux->Value * sol(r); 00659 } 00660 else 00661 { 00662 aux->Value = 1.0; 00663 for (int r = 0; r < num_rhs; r++) 00664 rhs(rc,r) = sol(r); 00665 } 00666 else 00667 { 00668 aux->Value = 0.0; 00669 for (RowNode *node = Rows[col]; 1; node = node->Prev) 00670 if (node == NULL) 00671 { 00672 mfem_error("SparseMatrix::EliminateRowColMultipleRHS() #4"); 00673 } 00674 else if (node->Column == rc) 00675 { 00676 for (int r = 0; r < num_rhs; r++) 00677 rhs(col,r) -= sol(r) * node->Value; 00678 node->Value = 0.0; 00679 break; 00680 } 00681 } 00682 } 00683 00684 void SparseMatrix::EliminateRowCol(int rc, int d) 00685 { 00686 int col; 00687 RowNode *aux, *node; 00688 00689 #ifdef MFEM_DEBUG 00690 if ( rc >= size || rc < 0 ) 00691 mfem_error("SparseMatrix::EliminateRowCol () #1"); 00692 #endif 00693 00694 if (Rows == NULL) 00695 mfem_error("SparseMatrix::EliminateRowCol () #2"); 00696 00697 for (aux = Rows[rc]; aux != NULL; aux = aux->Prev) 00698 { 00699 if ((col = aux->Column) == rc) 00700 { 00701 if (d == 0) 00702 aux->Value = 1.0; 00703 } 00704 else 00705 { 00706 aux->Value = 0.0; 00707 for (node = Rows[col]; 1; node = node->Prev) 00708 if (node == NULL) 00709 { 00710 mfem_error("SparseMatrix::EliminateRowCol () #3"); 00711 } 00712 else if (node->Column == rc) 00713 { 00714 node->Value = 0.0; 00715 break; 00716 } 00717 } 00718 } 00719 } 00720 00721 void SparseMatrix::EliminateRowCol(int rc, SparseMatrix &Ae, int d) 00722 { 00723 int col; 00724 00725 if (Rows) 00726 { 00727 RowNode *nd, *nd2; 00728 for (nd = Rows[rc]; nd != NULL; nd = nd->Prev) 00729 { 00730 if ((col = nd->Column) == rc) 00731 { 00732 if (d == 0) 00733 { 00734 Ae.Add(rc, rc, nd->Value - 1.0); 00735 nd->Value = 1.0; 00736 } 00737 } 00738 else 00739 { 00740 Ae.Add(rc, col, nd->Value); 00741 nd->Value = 0.0; 00742 for (nd2 = Rows[col]; 1; nd2 = nd2->Prev) 00743 { 00744 if (nd2 == NULL) 00745 { 00746 mfem_error("SparseMatrix::EliminateRowCol"); 00747 } 00748 else if (nd2->Column == rc) 00749 { 00750 Ae.Add(col, rc, nd2->Value); 00751 nd2->Value = 0.0; 00752 break; 00753 } 00754 } 00755 } 00756 } 00757 } 00758 else 00759 { 00760 for (int j = I[rc]; j < I[rc+1]; j++) 00761 if ((col = J[j]) == rc) 00762 { 00763 if (d == 0) 00764 { 00765 Ae.Add(rc, rc, A[j] - 1.0); 00766 A[j] = 1.0; 00767 } 00768 } 00769 else 00770 { 00771 Ae.Add(rc, col, A[j]); 00772 A[j] = 0.0; 00773 for (int k = I[col]; true; k++) 00774 if (k == I[col+1]) 00775 { 00776 mfem_error("SparseMatrix::EliminateRowCol"); 00777 } 00778 else if (J[k] == rc) 00779 { 00780 Ae.Add(col, rc, A[k]); 00781 A[k] = 0.0; 00782 break; 00783 } 00784 } 00785 } 00786 } 00787 00788 void SparseMatrix::SetDiagIdentity() 00789 { 00790 for (int i = 0; i < size; i++) 00791 if (I[i+1] == I[i]+1 && fabs(A[I[i]]) < 1e-16) 00792 A[I[i]] = 1.0; 00793 } 00794 00795 void SparseMatrix::EliminateZeroRows() 00796 { 00797 int i, j; 00798 double zero; 00799 00800 for (i = 0; i < size; i++) { 00801 zero = 0.0; 00802 for (j = I[i]; j < I[i+1]; j++) 00803 zero += fabs(A[j]); 00804 if (zero < 1e-12) { 00805 for (j = I[i]; j < I[i+1]; j++) 00806 if (J[j] == i) 00807 A[j] = 1.0; 00808 else 00809 A[j] = 0.0; 00810 } 00811 } 00812 } 00813 00814 void SparseMatrix::Gauss_Seidel_forw(const Vector &x, Vector &y) const 00815 { 00816 int c, i, s = size; 00817 double sum, *yp = y.GetData(); 00818 const double *xp = x.GetData(); 00819 00820 if (A == NULL) 00821 { 00822 RowNode *diag_p, *n_p, **R = Rows; 00823 00824 for (i = 0; i < s; i++) 00825 { 00826 sum = 0.0; 00827 diag_p = NULL; 00828 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev) 00829 if ((c = n_p->Column) == i) 00830 diag_p = n_p; 00831 else 00832 sum += n_p->Value * yp[c]; 00833 00834 if (diag_p != NULL && diag_p->Value != 0.0) 00835 yp[i] = (xp[i] - sum) / diag_p->Value; 00836 else 00837 if (xp[i] == sum) 00838 yp[i] = sum; 00839 else 00840 mfem_error("SparseMatrix::Gauss_Seidel_forw()"); 00841 } 00842 } 00843 else 00844 { 00845 int j, end, d, *Ip = I, *Jp = J; 00846 double *Ap = A; 00847 00848 j = Ip[0]; 00849 for (i = 0; i < s; i++) 00850 { 00851 end = Ip[i+1]; 00852 sum = 0.0; 00853 d = -1; 00854 for ( ; j < end; j++) 00855 if ((c = Jp[j]) == i) 00856 d = j; 00857 else 00858 sum += Ap[j] * yp[c]; 00859 00860 if (d >= 0 && Ap[d] != 0.0) 00861 yp[i] = (xp[i] - sum) / Ap[d]; 00862 else 00863 if (xp[i] == sum) 00864 yp[i] = sum; 00865 else 00866 mfem_error("SparseMatrix::Gauss_Seidel_forw(...) #2"); 00867 } 00868 } 00869 } 00870 00871 void SparseMatrix::Gauss_Seidel_back(const Vector &x, Vector &y) const 00872 { 00873 int i, c; 00874 double sum, *yp = y.GetData(); 00875 const double *xp = x.GetData(); 00876 00877 if (A == NULL) 00878 { 00879 RowNode *diag_p, *n_p, **R = Rows; 00880 00881 for (i = size-1; i >= 0; i--) 00882 { 00883 sum = 0.; 00884 diag_p = NULL; 00885 for (n_p = R[i]; n_p != NULL; n_p = n_p->Prev) 00886 if ((c = n_p->Column) == i) 00887 diag_p = n_p; 00888 else 00889 sum += n_p->Value * yp[c]; 00890 00891 if (diag_p != NULL && diag_p->Value != 0.0) 00892 yp[i] = (xp[i] - sum) / diag_p->Value; 00893 else 00894 if (xp[i] == sum) 00895 yp[i] = sum; 00896 else 00897 mfem_error("SparseMatrix::Gauss_Seidel_back()"); 00898 } 00899 } 00900 else 00901 { 00902 int j, beg, d, *Ip = I, *Jp = J; 00903 double *Ap = A; 00904 00905 j = Ip[size]-1; 00906 for (i = size-1; i >= 0; i--) 00907 { 00908 beg = Ip[i]; 00909 sum = 0.; 00910 d = -1; 00911 for( ; j >= beg; j--) 00912 if ((c = Jp[j]) == i) 00913 d = j; 00914 else 00915 sum += Ap[j] * yp[c]; 00916 00917 if (d >= 0 && Ap[d] != 0.0) 00918 yp[i] = (xp[i] - sum) / Ap[d]; 00919 else 00920 if (xp[i] == sum) 00921 yp[i] = sum; 00922 else 00923 mfem_error("SparseMatrix::Gauss_Seidel_back(...) #2"); 00924 } 00925 } 00926 } 00927 00928 double SparseMatrix::GetJacobiScaling() const 00929 { 00930 if (A == NULL) 00931 mfem_error("SparseMatrix::GetJacobiScaling()"); 00932 00933 double sc = 1.0; 00934 for (int i = 0; i < size; i++) 00935 { 00936 int d = -1; 00937 double norm = 0.0; 00938 for (int j = I[i]; j < I[i+1]; j++) 00939 { 00940 if (J[j] == i) 00941 d = j; 00942 norm += fabs(A[j]); 00943 } 00944 if (d >= 0 && A[d] != 0.0) 00945 { 00946 double a = 1.8 * fabs(A[d]) / norm; 00947 if (a < sc) 00948 sc = a; 00949 } 00950 else 00951 mfem_error("SparseMatrix::GetJacobiScaling() #2"); 00952 } 00953 return sc; 00954 } 00955 00956 void SparseMatrix::Jacobi(const Vector &b, const Vector &x0, Vector &x1, 00957 double sc) const 00958 { 00959 if (A == NULL) 00960 mfem_error("SparseMatrix::Jacobi(...)"); 00961 00962 for (int i = 0; i < size; i++) 00963 { 00964 int d = -1; 00965 double sum = b(i); 00966 for (int j = I[i]; j < I[i+1]; j++) 00967 { 00968 if (J[j] == i) 00969 d = j; 00970 else 00971 sum -= A[j] * x0(J[j]); 00972 } 00973 if (d >= 0 && A[d] != 0.0) 00974 x1(i) = sc * (sum / A[d]) + (1.0 - sc) * x0(i); 00975 else 00976 mfem_error("SparseMatrix::Jacobi(...) #2"); 00977 } 00978 } 00979 00980 void SparseMatrix::Jacobi2(const Vector &b, const Vector &x0, Vector &x1, 00981 double sc) const 00982 { 00983 if (A == NULL) 00984 mfem_error("SparseMatrix::Jacobi2(...)"); 00985 00986 for (int i = 0; i < size; i++) 00987 { 00988 double resi = b(i), norm = 0.0; 00989 for (int j = I[i]; j < I[i+1]; j++) 00990 { 00991 resi -= A[j] * x0(J[j]); 00992 norm += fabs(A[j]); 00993 } 00994 if (norm > 0.0) 00995 x1(i) = x0(i) + sc * resi / norm; 00996 else 00997 mfem_error("SparseMatrix::Jacobi2(...) #2"); 00998 } 00999 } 01000 01001 void SparseMatrix::AddSubMatrix(const Array<int> &rows, const Array<int> &cols, 01002 const DenseMatrix &subm, int skip_zeros) 01003 { 01004 int i, j, gi, gj, s, t; 01005 double a; 01006 01007 for (i = 0; i < rows.Size(); i++) 01008 { 01009 if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1; 01010 #ifdef MFEM_DEBUG 01011 if (gi >= size) 01012 mfem_error("SparseMatrix::AddSubMatrix(...) #1"); 01013 #endif 01014 SetColPtr(gi); 01015 for (j = 0; j < cols.Size(); j++) 01016 { 01017 if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s; 01018 #ifdef MFEM_DEBUG 01019 if (gj >= width) 01020 mfem_error("SparseMatrix::AddSubMatrix(...) #2"); 01021 #endif 01022 a = subm(i, j); 01023 if (skip_zeros && a == 0.0) 01024 { 01025 // if the element is zero do not assemble it unless this breaks 01026 // the symmetric structure 01027 if (&rows != &cols || subm(j, i) == 0.0) 01028 continue; 01029 } 01030 if (t < 0) a = -a; 01031 _Add_(gj, a); 01032 } 01033 ClearColPtr(); 01034 } 01035 } 01036 01037 void SparseMatrix::Set(const int i, const int j, const double A) 01038 { 01039 double a = A; 01040 int gi, gj, s, t; 01041 01042 if ((gi=i) < 0) gi = -1-gi, s = -1; else s = 1; 01043 #ifdef MFEM_DEBUG 01044 if (gi >= size) 01045 mfem_error("SparseMatrix::Set (...) #1"); 01046 #endif 01047 if ((gj=j) < 0) gj = -1-gj, t = -s; else t = s; 01048 #ifdef MFEM_DEBUG 01049 if (gj >= width) 01050 mfem_error("SparseMatrix::Set (...) #2"); 01051 #endif 01052 if (t < 0) a = -a; 01053 _Set_(gi, gj, a); 01054 } 01055 01056 void SparseMatrix::Add(const int i, const int j, const double A) 01057 { 01058 int gi, gj, s, t; 01059 double a = A; 01060 01061 if ((gi=i) < 0) gi = -1-gi, s = -1; else s = 1; 01062 #ifdef MFEM_DEBUG 01063 if (gi >= size) 01064 mfem_error("SparseMatrix::Add (...) #1"); 01065 #endif 01066 if ((gj=j) < 0) gj = -1-gj, t = -s; else t = s; 01067 #ifdef MFEM_DEBUG 01068 if (gj >= width) 01069 mfem_error("SparseMatrix::Add (...) #2"); 01070 #endif 01071 if (t < 0) a = -a; 01072 _Add_(gi, gj, a); 01073 } 01074 01075 void SparseMatrix::SetSubMatrix(const Array<int> &rows, const Array<int> &cols, 01076 const DenseMatrix &subm, int skip_zeros) 01077 { 01078 int i, j, gi, gj, s, t; 01079 double a; 01080 01081 for (i = 0; i < rows.Size(); i++) 01082 { 01083 if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1; 01084 #ifdef MFEM_DEBUG 01085 if (gi >= size) 01086 mfem_error("SparseMatrix::SetSubMatrix(...) #1"); 01087 #endif 01088 SetColPtr(gi); 01089 for (j = 0; j < cols.Size(); j++) 01090 { 01091 a = subm(i, j); 01092 if (skip_zeros && a == 0.0) 01093 continue; 01094 if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s; 01095 #ifdef MFEM_DEBUG 01096 if (gj >= width) 01097 mfem_error("SparseMatrix::SetSubMatrix(...) #2"); 01098 #endif 01099 if (t < 0) a = -a; 01100 _Set_(gj, a); 01101 } 01102 ClearColPtr(); 01103 } 01104 } 01105 01106 void SparseMatrix::SetSubMatrixTranspose(const Array<int> &rows, 01107 const Array<int> &cols, 01108 const DenseMatrix &subm, 01109 int skip_zeros) 01110 { 01111 int i, j, gi, gj, s, t; 01112 double a; 01113 01114 for (i = 0; i < rows.Size(); i++) 01115 { 01116 if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1; 01117 #ifdef MFEM_DEBUG 01118 if (gi >= size) 01119 mfem_error("SparseMatrix::SetSubMatrixTranspose (...) #1"); 01120 #endif 01121 SetColPtr(gi); 01122 for (j = 0; j < cols.Size(); j++) 01123 { 01124 a = subm(j, i); 01125 if (skip_zeros && a == 0.0) 01126 continue; 01127 if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s; 01128 #ifdef MFEM_DEBUG 01129 if (gj >= width) 01130 mfem_error("SparseMatrix::SetSubMatrixTranspose (...) #2"); 01131 #endif 01132 if (t < 0) a = -a; 01133 _Set_(gj, a); 01134 } 01135 ClearColPtr(); 01136 } 01137 } 01138 01139 void SparseMatrix::GetSubMatrix(const Array<int> &rows, const Array<int> &cols, 01140 DenseMatrix &subm) 01141 { 01142 int i, j, gi, gj, s, t; 01143 double a; 01144 01145 for (i = 0; i < rows.Size(); i++) 01146 { 01147 if ((gi=rows[i]) < 0) gi = -1-gi, s = -1; else s = 1; 01148 #ifdef MFEM_DEBUG 01149 if (gi >= size) 01150 mfem_error("SparseMatrix::GetSubMatrix(...) #1"); 01151 #endif 01152 SetColPtr(gi); 01153 for (j = 0; j < cols.Size(); j++) 01154 { 01155 if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s; 01156 #ifdef MFEM_DEBUG 01157 if (gj >= width) 01158 mfem_error("SparseMatrix::GetSubMatrix(...) #2"); 01159 #endif 01160 a = _Get_(gj); 01161 subm(i, j) = (t < 0) ? (-a) : (a); 01162 } 01163 ClearColPtr(); 01164 } 01165 } 01166 01167 void SparseMatrix::AddRow(const int row, const Array<int> &cols, 01168 const Vector &srow) 01169 { 01170 int j, gi, gj, s, t; 01171 double a; 01172 01173 if (Rows == NULL) 01174 mfem_error("SparseMatrix::AddRow(...) #0"); 01175 01176 if ((gi=row) < 0) gi = -1-gi, s = -1; else s = 1; 01177 #ifdef MFEM_DEBUG 01178 if (gi >= size) 01179 mfem_error("SparseMatrix::AddRow(...) #1"); 01180 #endif 01181 SetColPtr(gi); 01182 for (j = 0; j < cols.Size(); j++) 01183 { 01184 if ((gj=cols[j]) < 0) gj = -1-gj, t = -s; else t = s; 01185 #ifdef MFEM_DEBUG 01186 if (gj >= width) 01187 mfem_error("SparseMatrix::AddRow(...) #2"); 01188 #endif 01189 a = srow(j); 01190 if (a == 0.0) 01191 continue; 01192 if (t < 0) a = -a; 01193 _Add_(gj, a); 01194 } 01195 ClearColPtr(); 01196 } 01197 01198 void SparseMatrix::ScaleRow(const int row, const double scale) 01199 { 01200 int i; 01201 01202 if ((i=row) < 0) 01203 i = -1-i; 01204 if (Rows != NULL) 01205 { 01206 RowNode *aux; 01207 01208 for (aux = Rows[i]; aux != NULL; aux = aux -> Prev) 01209 aux -> Value *= scale; 01210 } 01211 else 01212 { 01213 int j, end = I[i+1]; 01214 01215 for (j = I[i]; j < end; j++) 01216 A[j] *= scale; 01217 } 01218 } 01219 01220 SparseMatrix &SparseMatrix::operator+=(SparseMatrix &B) 01221 { 01222 int i; 01223 RowNode *aux; 01224 01225 if (Rows == NULL || B.Rows == NULL) 01226 mfem_error("SparseMatrix::operator+=(...) #0"); 01227 #ifdef MFEM_DEBUG 01228 if (size != B.size || width != B.width) 01229 mfem_error("SparseMatrix::operator+=(...) #1"); 01230 #endif 01231 01232 for (i = 0; i < size; i++) 01233 { 01234 SetColPtr(i); 01235 for (aux = B.Rows[i]; aux != NULL; aux = aux->Prev) 01236 { 01237 _Add_(aux->Column, aux->Value); 01238 } 01239 ClearColPtr(); 01240 } 01241 01242 return (*this); 01243 } 01244 01245 SparseMatrix &SparseMatrix::operator=(double a) 01246 { 01247 if (Rows == NULL) 01248 for (int i = 0, nnz = I[size]; i < nnz; i++) 01249 A[i] = a; 01250 else 01251 for (int i = 0; i < size; i++) 01252 for (RowNode *node_p = Rows[i]; node_p != NULL; 01253 node_p = node_p -> Prev) 01254 node_p -> Value = a; 01255 01256 return (*this); 01257 } 01258 01259 void SparseMatrix::Print(ostream & out, int _width) const 01260 { 01261 int i, j; 01262 01263 if (A == NULL) 01264 mfem_error("SparseMatrix::Print()"); 01265 01266 for (i = 0; i < size; i++) 01267 { 01268 out << "[row " << i << "]\n"; 01269 for (j = I[i]; j < I[i+1]; j++) 01270 { 01271 out << " (" << J[j] << ","<< A[j] << ")"; 01272 if ( !((j+1-I[i]) % _width) ) 01273 out << '\n'; 01274 } 01275 if ((j-I[i]) % _width) 01276 out << '\n'; 01277 } 01278 } 01279 01280 void SparseMatrix::PrintMatlab(ostream & out) const 01281 { 01282 int i, j; 01283 ios::fmtflags old_fmt = out.setf(ios::scientific); 01284 int old_prec = out.precision(14); 01285 01286 for(i = 0; i < size; i++) 01287 for (j = I[i]; j < I[i+1]; j++) 01288 out << i+1 << " " << J[j]+1 << " " << A[j] << endl; 01289 out.precision(old_prec); 01290 out.setf(old_fmt); 01291 } 01292 01293 void SparseMatrix::PrintMM(ostream & out) const 01294 { 01295 int i, j; 01296 ios::fmtflags old_fmt = out.setf(ios::scientific); 01297 int old_prec = out.precision(14); 01298 01299 out << "%%MatrixMarket matrix coordinate real general" << endl 01300 << "% Generated by MFEM" << endl; 01301 01302 out << size << " " << width << " " << NumNonZeroElems() << endl; 01303 for(i = 0; i < size; i++) 01304 for (j = I[i]; j < I[i+1]; j++) 01305 out << i+1 << " " << J[j]+1 << " " << A[j] << endl; 01306 out.precision(old_prec); 01307 out.setf(old_fmt); 01308 } 01309 01310 void SparseMatrix::PrintCSR(ostream & out) const 01311 { 01312 if (A == NULL) 01313 mfem_error("SparseMatrix::PrintCSR()"); 01314 01315 int i; 01316 01317 out << size << '\n'; // number of rows 01318 01319 for (i = 0; i <= size; i++) 01320 out << I[i]+1 << '\n'; 01321 01322 for (i = 0; i < I[size]; i++) 01323 out << J[i]+1 << '\n'; 01324 01325 for (i = 0; i < I[size]; i++) 01326 out << A[i] << '\n'; 01327 } 01328 01329 void SparseMatrix::PrintCSR2(ostream & out) const 01330 { 01331 if (A == NULL) 01332 mfem_error("SparseMatrix::PrintCSR2()"); 01333 01334 int i; 01335 01336 out << size << '\n'; // number of rows 01337 out << width << '\n'; // number of columns 01338 01339 for (i = 0; i <= size; i++) 01340 out << I[i] << '\n'; 01341 01342 for (i = 0; i < I[size]; i++) 01343 out << J[i] << '\n'; 01344 01345 for (i = 0; i < I[size]; i++) 01346 out << A[i] << '\n'; 01347 } 01348 01349 SparseMatrix::~SparseMatrix () 01350 { 01351 if (Rows != NULL) 01352 { 01353 delete [] ColPtr.Node; 01354 #ifdef MFEM_USE_MEMALLOC 01355 // NodesMem.Clear(); // this is done implicitly 01356 #else 01357 for (int i = 0; i < size; i++) 01358 { 01359 RowNode *aux, *node_p = Rows[i]; 01360 while (node_p != NULL) 01361 { 01362 aux = node_p; 01363 node_p = node_p->Prev; 01364 delete aux; 01365 } 01366 } 01367 #endif 01368 delete [] Rows; 01369 } 01370 if (A != NULL) 01371 { 01372 delete [] ColPtr.J; 01373 delete [] I; 01374 delete [] J; 01375 delete [] A; 01376 } 01377 } 01378 01379 void SparseMatrixFunction (SparseMatrix & S, double (*f)(double)) 01380 { 01381 int n = S.NumNonZeroElems(); 01382 double * s = S.GetData(); 01383 01384 for (int i = 0; i < n; i++) 01385 s[i] = f(s[i]); 01386 } 01387 01388 SparseMatrix *Transpose (SparseMatrix &A) 01389 { 01390 int i, j, end; 01391 int m, n, nnz, *A_i, *A_j, *At_i, *At_j; 01392 double *A_data, *At_data; 01393 01394 m = A.Size(); // number of rows of A 01395 n = A.Width(); // number of columns of A 01396 nnz = A.NumNonZeroElems(); 01397 A_i = A.GetI(); 01398 A_j = A.GetJ(); 01399 A_data = A.GetData(); 01400 01401 At_i = new int[n+1]; 01402 At_j = new int[nnz]; 01403 At_data = new double[nnz]; 01404 01405 for (i = 0; i <= n; i++) 01406 At_i[i] = 0; 01407 for (i = 0; i < nnz; i++) 01408 At_i[A_j[i]+1]++; 01409 for (i = 1; i < n; i++) 01410 At_i[i+1] += At_i[i]; 01411 01412 for (i = j = 0; i < m; i++) 01413 { 01414 end = A_i[i+1]; 01415 for ( ; j < end; j++) 01416 { 01417 At_j[At_i[A_j[j]]] = i; 01418 At_data[At_i[A_j[j]]] = A_data[j]; 01419 At_i[A_j[j]]++; 01420 } 01421 } 01422 01423 for (i = n; i > 0; i--) 01424 At_i[i] = At_i[i-1]; 01425 At_i[0] = 0; 01426 01427 return new SparseMatrix (At_i, At_j, At_data, n, m); 01428 } 01429 01430 SparseMatrix *Mult (SparseMatrix &A, SparseMatrix &B, 01431 SparseMatrix *OAB) 01432 { 01433 int nrowsA, ncolsA, nrowsB, ncolsB; 01434 int *A_i, *A_j, *B_i, *B_j, *C_i, *C_j, *B_marker; 01435 double *A_data, *B_data, *C_data; 01436 int ia, ib, ic, ja, jb, num_nonzeros; 01437 int row_start, counter; 01438 double a_entry, b_entry; 01439 SparseMatrix *C; 01440 01441 nrowsA = A.Size(); 01442 ncolsA = A.Width(); 01443 nrowsB = B.Size(); 01444 ncolsB = B.Width(); 01445 01446 if (ncolsA != nrowsB) 01447 mfem_error("Sparse matrix multiplication, Mult (...) #1"); 01448 01449 A_i = A.GetI(); 01450 A_j = A.GetJ(); 01451 A_data = A.GetData(); 01452 B_i = B.GetI(); 01453 B_j = B.GetJ(); 01454 B_data = B.GetData(); 01455 01456 B_marker = new int[ncolsB]; 01457 01458 for (ib = 0; ib < ncolsB; ib++) 01459 B_marker[ib] = -1; 01460 01461 if (OAB == NULL) 01462 { 01463 C_i = new int[nrowsA+1]; 01464 01465 C_i[0] = num_nonzeros = 0; 01466 for (ic = 0; ic < nrowsA; ic++) 01467 { 01468 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++) 01469 { 01470 ja = A_j[ia]; 01471 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++) 01472 { 01473 jb = B_j[ib]; 01474 if (B_marker[jb] != ic) 01475 { 01476 B_marker[jb] = ic; 01477 num_nonzeros++; 01478 } 01479 } 01480 } 01481 C_i[ic+1] = num_nonzeros; 01482 } 01483 01484 C_j = new int[num_nonzeros]; 01485 C_data = new double[num_nonzeros]; 01486 01487 C = new SparseMatrix (C_i, C_j, C_data, nrowsA, ncolsB); 01488 01489 for (ib = 0; ib < ncolsB; ib++) 01490 B_marker[ib] = -1; 01491 } 01492 else 01493 { 01494 C = OAB; 01495 01496 if (nrowsA != C -> Size() || ncolsB != C -> Width()) 01497 mfem_error("Sparse matrix multiplication, Mult (...) #2"); 01498 01499 C_i = C -> GetI(); 01500 C_j = C -> GetJ(); 01501 C_data = C -> GetData(); 01502 } 01503 01504 counter = 0; 01505 for (ic = 0; ic < nrowsA; ic++) 01506 { 01507 // row_start = C_i[ic]; 01508 row_start = counter; 01509 for (ia = A_i[ic]; ia < A_i[ic+1]; ia++) 01510 { 01511 ja = A_j[ia]; 01512 a_entry = A_data[ia]; 01513 for (ib = B_i[ja]; ib < B_i[ja+1]; ib++) 01514 { 01515 jb = B_j[ib]; 01516 b_entry = B_data[ib]; 01517 if (B_marker[jb] < row_start) 01518 { 01519 B_marker[jb] = counter; 01520 if (OAB == NULL) 01521 C_j[counter] = jb; 01522 C_data[counter] = a_entry*b_entry; 01523 counter++; 01524 } 01525 else 01526 C_data[B_marker[jb]] += a_entry*b_entry; 01527 } 01528 } 01529 } 01530 01531 if (OAB != NULL && counter != OAB -> NumNonZeroElems()) 01532 mfem_error("Sparse matrix multiplication, Mult (...) #3"); 01533 01534 delete [] B_marker; 01535 01536 return C; 01537 } 01538 01539 SparseMatrix *RAP (SparseMatrix &A, SparseMatrix &R, 01540 SparseMatrix *ORAP) 01541 { 01542 SparseMatrix *P = Transpose (R); 01543 SparseMatrix *AP = Mult (A, *P); 01544 delete P; 01545 SparseMatrix *_RAP = Mult (R, *AP, ORAP); 01546 delete AP; 01547 return _RAP; 01548 } 01549 01550 SparseMatrix *Mult_AtDA (SparseMatrix &A, Vector &D, 01551 SparseMatrix *OAtDA) 01552 { 01553 int i, At_nnz, *At_j; 01554 double *At_data; 01555 01556 SparseMatrix *At = Transpose (A); 01557 At_nnz = At -> NumNonZeroElems(); 01558 At_j = At -> GetJ(); 01559 At_data = At -> GetData(); 01560 for (i = 0; i < At_nnz; i++) 01561 At_data[i] *= D(At_j[i]); 01562 SparseMatrix *AtDA = Mult (*At, A, OAtDA); 01563 delete At; 01564 return AtDA; 01565 }