EpetraExt  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EpetraExt_PETScAIJMatrix.cpp
Go to the documentation of this file.
1 //@HEADER
2 // ***********************************************************************
3 //
4 // EpetraExt: Epetra Extended - Linear Algebra Services Package
5 // Copyright (2011) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 //@HEADER
41 
42 /*#############################################################################
43 # CVS File Information
44 # Current revision: $Revision$
45 # Last modified: $Date$
46 # Modified by: $Author$
47 #############################################################################*/
48 
49 #include "EpetraExt_ConfigDefs.h"
50 #ifdef HAVE_PETSC
51 
52 #include "Epetra_Import.h"
53 #include "Epetra_Export.h"
54 #include "Epetra_Vector.h"
55 #include "Epetra_MultiVector.h"
57 
58 //==============================================================================
60  : Amat_(Amat),
61  Epetra_Object("Epetra::PETScAIJMatrix"),
62  Values_(0),
63  Indices_(0),
64  MaxNumEntries_(-1),
65  ImportVector_(0),
66  NormInf_(-1.0),
67  NormOne_(-1.0),
68  Comm_(0),
69  DomainMap_(0),
70  ColMap_(0),
71  Importer_(0),
72  NumGlobalNonzeros_(0),
73  NumMyNonzeros_(0),
74  NumMyRows_(0),
75  NumGlobalRows_(0),
76  NumMyCols_(0),
77  PetscRowStart_(0),
78  PetscRowEnd_(0),
79  MatType_(" ")
80 {
81 #ifdef HAVE_MPI
82  MPI_Comm comm;
83  PetscObjectGetComm( (PetscObject)Amat, &comm);
84  Comm_ = new Epetra_MpiComm(comm);
85 #else
86  Comm_ = new Epetra_SerialComm();
87 #endif
88  int ierr;
89  char errMsg[80];
90  //MatGetType(Amat, const_cast<const char**>(&MatType_));
91  MatGetType(Amat, &MatType_);
92  if ( strcmp(MatType_,MATSEQAIJ) != 0 && strcmp(MatType_,MATMPIAIJ) != 0 ) {
93  sprintf(errMsg,"PETSc matrix must be either seqaij or mpiaij (but it is %s)",MatType_);
94  throw Comm_->ReportError(errMsg,-1);
95  }
96  petscMatrixType mt;
97  Mat_MPIAIJ* aij=0;
98  if (strcmp(MatType_,MATMPIAIJ) == 0) {
99  mt = PETSC_MPI_AIJ;
100  aij = (Mat_MPIAIJ*)Amat->data;
101  }
102  else if (strcmp(MatType_,MATSEQAIJ) == 0) {
103  mt = PETSC_SEQ_AIJ;
104  }
105  int numLocalRows, numLocalCols;
106  ierr = MatGetLocalSize(Amat,&numLocalRows,&numLocalCols);
107  if (ierr) {
108  sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetLocalSize() returned error code %d",__LINE__,ierr);
109  throw Comm_->ReportError(errMsg,-1);
110  }
111  NumMyRows_ = numLocalRows;
112  NumMyCols_ = numLocalCols; //numLocalCols is the total # of unique columns in the local matrix (the diagonal block)
113  //TODO what happens if some columns are empty?
114  if (mt == PETSC_MPI_AIJ)
115  NumMyCols_ += aij->B->cmap->n;
116  MatInfo info;
117  ierr = MatGetInfo(Amat,MAT_LOCAL,&info);
118  if (ierr) {
119  sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetInfo() returned error code %d",__LINE__,ierr);
120  throw Comm_->ReportError(errMsg,-1);
121  }
122  NumMyNonzeros_ = (int) info.nz_used; //PETSc stores nnz as double
123  Comm_->SumAll(&(info.nz_used), &NumGlobalNonzeros_, 1);
124 
125  //The PETSc documentation warns that this may not be robust.
126  //In particular, this will break if the ordering is not contiguous!
127  int rowStart, rowEnd;
128  ierr = MatGetOwnershipRange(Amat,&rowStart,&rowEnd);
129  if (ierr) {
130  sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetOwnershipRange() returned error code %d",__LINE__,ierr);
131  throw Comm_->ReportError(errMsg,-1);
132  }
133 
134  PetscRowStart_ = rowStart;
135  PetscRowEnd_ = rowEnd;
136 
137  int* MyGlobalElements = new int[rowEnd-rowStart];
138  for (int i=0; i<rowEnd-rowStart; i++)
139  MyGlobalElements[i] = rowStart+i;
140 
141  ierr = MatGetInfo(Amat,MAT_GLOBAL_SUM,&info);
142  if (ierr) {
143  sprintf(errMsg,"EpetraExt_PETScAIJMatrix.cpp, line %d, MatGetInfo() returned error code %d",__LINE__,ierr);
144  throw Comm_->ReportError(errMsg,-1);
145  }
146  int tmp;
147  ierr = MatGetSize(Amat,&NumGlobalRows_,&tmp);
148 
149  DomainMap_ = new Epetra_Map(NumGlobalRows_, NumMyRows_, MyGlobalElements, 0, *Comm_);
150 
151  // get the GIDs of the non-local columns
152  //FIXME what if the matrix is sequential?
153 
154  int * ColGIDs = new int[NumMyCols_];
155  for (int i=0; i<numLocalCols; i++) ColGIDs[i] = MyGlobalElements[i];
156  for (int i=numLocalCols; i<NumMyCols_; i++) ColGIDs[i] = aij->garray[i-numLocalCols];
157 
158  ColMap_ = new Epetra_Map(-1, NumMyCols_, ColGIDs, 0, *Comm_);
159 
160  Importer_ = new Epetra_Import(*ColMap_, *DomainMap_);
161 
162  delete [] MyGlobalElements;
163  delete [] ColGIDs;
164 } //Epetra_PETScAIJMatrix(Mat Amat)
165 
166 //==============================================================================
167 
169  if (ImportVector_!=0) delete ImportVector_;
170  delete Importer_;
171  delete ColMap_;
172  delete DomainMap_;
173  delete Comm_;
174 
175  if (Values_!=0) {delete [] Values_; Values_=0;}
176  if (Indices_!=0) {delete [] Indices_; Indices_=0;}
177 } //Epetra_PETScAIJMatrix dtor
178 
179 //==========================================================================
180 
181 //extern "C" {
182  PetscErrorCode MatCreateColmap_MPIAIJ_Private(Mat);
183 //}
184 
185 int Epetra_PETScAIJMatrix::ExtractMyRowCopy(int Row, int Length, int & NumEntries, double * Values,
186  int * Indices) const
187 {
188  int nz;
189  PetscInt *gcols, *lcols, ierr;
190  PetscScalar *vals;
191  bool alloc=false;
192 
193  // PETSc assumes the row number is global, whereas Trilinos assumes it's local.
194  int globalRow = PetscRowStart_ + Row;
195  assert(globalRow < PetscRowEnd_);
196  ierr=MatGetRow(Amat_, globalRow, &nz, (const PetscInt**) &gcols, (const PetscScalar **) &vals);CHKERRQ(ierr);
197 
198  // I ripped this bit of code from PETSc's MatSetValues_MPIAIJ() in mpiaij.c. The PETSc getrow returns everything in
199  // global numbering, so we must convert to local numbering.
200  if (strcmp(MatType_,MATMPIAIJ) == 0) {
201  Mat_MPIAIJ *aij = (Mat_MPIAIJ*)Amat_->data;
202  lcols = (PetscInt *) malloc(nz * sizeof(int));
203  alloc=true;
204  if (!aij->colmap) {
205  ierr = MatCreateColmap_MPIAIJ_Private(Amat_);CHKERRQ(ierr);
206  }
207  /*
208  A PETSc parallel aij matrix uses two matrices to represent the local rows.
209  The first matrix, A, is square and contains all local columns.
210  The second matrix, B, is rectangular and contains all non-local columns.
211 
212  Matrix A:
213  Local column ID's are mapped to global column id's by adding cmap.rstart.
214  Given the global ID of a local column, the local ID is found by
215  subtracting cmap.rstart.
216 
217  Matrix B:
218  Non-local column ID's are mapped to global column id's by the local-to-
219  global map garray. Given the global ID of a local column, the local ID is
220  found by the global-to-local map colmap. colmap is either an array or
221  hash table, the latter being the case when PETSC_USE_CTABLE is defined.
222  */
223  int offset = Amat_->cmap->n-1; //offset for non-local column indices
224 
225  for (int i=0; i<nz; i++) {
226  if (gcols[i] >= Amat_->cmap->rstart && gcols[i] < Amat_->cmap->rend) {
227  lcols[i] = gcols[i] - Amat_->cmap->rstart;
228  } else {
229 # ifdef PETSC_USE_CTABLE
230  ierr = PetscTableFind(aij->colmap,gcols[i]+1,lcols+i);CHKERRQ(ierr);
231  lcols[i] = lcols[i] + offset;
232 # else
233  lcols[i] = aij->colmap[gcols[i]] + offset;
234 # endif
235  }
236 
237  } //for i=0; i<nz; i++)
238  }
239  else lcols = gcols;
240 
241  NumEntries = nz;
242  if (NumEntries > Length) return(-1);
243  for (int i=0; i<NumEntries; i++) {
244  Indices[i] = lcols[i];
245  Values[i] = vals[i];
246  }
247  if (alloc) free(lcols);
248  MatRestoreRow(Amat_,globalRow,&nz,(const PetscInt**) &gcols, (const PetscScalar **) &vals);
249  return(0);
250 } //ExtractMyRowCopy()
251 
252 //==========================================================================
253 
254 int Epetra_PETScAIJMatrix::NumMyRowEntries(int Row, int & NumEntries) const
255 {
256  // NOTE: MatRestoreRow was previously zeroing out NumEntries.
257  // Do not pass NumEntries to it.
258  int globalRow = PetscRowStart_ + Row;
259  MatGetRow(Amat_, globalRow, &NumEntries, PETSC_NULL, PETSC_NULL);
260  MatRestoreRow(Amat_,globalRow,PETSC_NULL, PETSC_NULL, PETSC_NULL);
261  return(0);
262 }
263 
264 //==============================================================================
265 
267 {
268  //TODO optimization: only get this diagonal once
269  Vec petscDiag;
270  double *vals=0;
271  int length;
272 
273  int ierr=VecCreate(Comm_->Comm(),&petscDiag);CHKERRQ(ierr);
274  VecSetSizes(petscDiag,NumMyRows_,NumGlobalRows_);
275 # ifdef HAVE_MPI
276  ierr = VecSetType(petscDiag,VECMPI);CHKERRQ(ierr);
277 # else //TODO untested!!
278  VecSetType(petscDiag,VECSEQ);
279 # endif
280 
281  MatGetDiagonal(Amat_, petscDiag);
282  VecGetArray(petscDiag,&vals);
283  VecGetLocalSize(petscDiag,&length);
284  for (int i=0; i<length; i++) Diagonal[i] = vals[i];
285  VecRestoreArray(petscDiag,&vals);
286  VecDestroy(&petscDiag);
287  return(0);
288 }
289 
290 //=============================================================================
291 
292 int Epetra_PETScAIJMatrix::Multiply(bool TransA,
293  const Epetra_MultiVector& X,
294  Epetra_MultiVector& Y) const
295 {
296  (void)TransA;
297  int NumVectors = X.NumVectors();
298  if (NumVectors!=Y.NumVectors()) EPETRA_CHK_ERR(-1); // X and Y must have same number of vectors
299 
300  double ** xptrs;
301  double ** yptrs;
302  X.ExtractView(&xptrs);
303  Y.ExtractView(&yptrs);
304  if (RowMatrixImporter()!=0) {
305  if (ImportVector_!=0) {
306  if (ImportVector_->NumVectors()!=NumVectors) { delete ImportVector_; ImportVector_= 0;}
307  }
308  if (ImportVector_==0) ImportVector_ = new Epetra_MultiVector(RowMatrixColMap(),NumVectors);
309  ImportVector_->Import(X, *RowMatrixImporter(), Insert);
310  ImportVector_->ExtractView(&xptrs);
311  }
312 
313  double *vals=0;
314  int length;
315  Vec petscX, petscY;
316  int ierr;
317  for (int i=0; i<NumVectors; i++) {
318 # ifdef HAVE_MPI
319  ierr=VecCreateMPIWithArray(Comm_->Comm(),1,X.MyLength(),X.GlobalLength(),xptrs[i],&petscX); CHKERRQ(ierr);
320  ierr=VecCreateMPIWithArray(Comm_->Comm(),1, Y.MyLength(),Y.GlobalLength(),yptrs[i],&petscY); CHKERRQ(ierr);
321 # else //FIXME untested
322  ierr=VecCreateSeqWithArray(Comm_->Comm(),1, X.MyLength(),X.GlobalLength(),xptrs[i],&petscX); CHKERRQ(ierr);
323  ierr=VecCreateSeqWithArray(Comm_->Comm(),1, Y.MyLength(),Y.GlobalLength(),yptrs[i],&petscY); CHKERRQ(ierr);
324 # endif
325 
326  ierr = MatMult(Amat_,petscX,petscY);CHKERRQ(ierr);
327 
328  ierr = VecGetArray(petscY,&vals);CHKERRQ(ierr);
329  ierr = VecGetLocalSize(petscY,&length);CHKERRQ(ierr);
330  for (int j=0; j<length; j++) yptrs[i][j] = vals[j];
331  ierr = VecRestoreArray(petscY,&vals);CHKERRQ(ierr);
332  }
333 
334  VecDestroy(&petscX); VecDestroy(&petscY);
335 
336  double flops = NumGlobalNonzeros();
337  flops *= 2.0;
338  flops *= (double) NumVectors;
339  UpdateFlops(flops);
340  return(0);
341 } //Multiply()
342 
343 //=============================================================================
344 
345 int Epetra_PETScAIJMatrix::Solve(bool Upper, bool Trans, bool UnitDiagonal,
346  const Epetra_MultiVector& X,
347  Epetra_MultiVector& Y) const
348 {
349  (void)Upper;
350  (void)Trans;
351  (void)UnitDiagonal;
352  (void)X;
353  (void)Y;
354  return(-1); // Not implemented
355 }
356 
357 //=============================================================================
358 // Utility routine to get the specified row and put it into Values_ and Indices_ arrays
360  int NumEntries;
361 
362  if (MaxNumEntries_==-1) {
363  for (int i=0; i < NumMyRows_; i++) {
364  NumMyRowEntries(i, NumEntries);
365  if (NumEntries>MaxNumEntries_) MaxNumEntries_ = NumEntries;
366  }
367  }
368  return(MaxNumEntries_);
369 }
370 
371 //=============================================================================
372 // Utility routine to get the specified row and put it into Values_ and Indices_ arrays
373 int Epetra_PETScAIJMatrix::GetRow(int Row) const {
374  int NumEntries;
375  int MaxNumEntries = Epetra_PETScAIJMatrix::MaxNumEntries();
376 
377  if (MaxNumEntries>0) {
378  if (Values_==0) Values_ = new double[MaxNumEntries];
379  if (Indices_==0) Indices_ = new int[MaxNumEntries];
380  }
381  Epetra_PETScAIJMatrix::ExtractMyRowCopy(Row, MaxNumEntries, NumEntries, Values_, Indices_);
382 
383  return(NumEntries);
384 }
385 
386 //=============================================================================
388 //
389 // Put inverse of the sum of absolute values of the ith row of A in x[i].
390 //
391 
392  if (!OperatorRangeMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2); // x must have the same distribution as the range of A
393 
394  int ierr = 0;
395  int i, j;
396  for (i=0; i < NumMyRows_; i++) {
397  int NumEntries = GetRow(i); // Copies ith row of matrix into Values_ and Indices_
398  double scale = 0.0;
399  for (j=0; j < NumEntries; j++) scale += fabs(Values_[j]);
400  if (scale<Epetra_MinDouble) {
401  if (scale==0.0) ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
402  else if (ierr!=1) ierr = 2;
403  x[i] = Epetra_MaxDouble;
404  }
405  else
406  x[i] = 1.0/scale;
407  }
408  UpdateFlops(NumGlobalNonzeros());
409  EPETRA_CHK_ERR(ierr);
410  return(0);
411 }
412 
413 //=============================================================================
415 //
416 // Put inverse of the sum of absolute values of the jth column of A in x[j].
417 //
418 
419  if (!Filled()) EPETRA_CHK_ERR(-1); // Matrix must be filled.
420  if (!OperatorDomainMap().SameAs(x.Map())) EPETRA_CHK_ERR(-2); // x must have the same distribution as the domain of A
421 
422 
423  Epetra_Vector * xp = 0;
424  Epetra_Vector * x_tmp = 0;
425 
426 
427  // If we have a non-trivial importer, we must export elements that are permuted or belong to other processors
428  if (RowMatrixImporter()!=0) {
429  x_tmp = new Epetra_Vector(RowMatrixColMap()); // Create import vector if needed
430  xp = x_tmp;
431  }
432  int ierr = 0;
433  int i, j;
434 
435  for (i=0; i < NumMyCols_; i++) (*xp)[i] = 0.0;
436 
437  for (i=0; i < NumMyRows_; i++) {
438  int NumEntries = GetRow(i);// Copies ith row of matrix into Values_ and Indices_
439  for (j=0; j < NumEntries; j++) (*xp)[Indices_[j]] += fabs(Values_[j]);
440  }
441 
442  if (RowMatrixImporter()!=0){
443  x.Export(*x_tmp, *RowMatrixImporter(), Add); // Fill x with Values from import vector
444  delete x_tmp;
445  xp = &x;
446  }
447  // Invert values, don't allow them to get too large
448  for (i=0; i < NumMyRows_; i++) {
449  double scale = (*xp)[i];
450  if (scale<Epetra_MinDouble) {
451  if (scale==0.0) ierr = 1; // Set error to 1 to signal that zero rowsum found (supercedes ierr = 2)
452  else if (ierr!=1) ierr = 2;
453  (*xp)[i] = Epetra_MaxDouble;
454  }
455  else
456  (*xp)[i] = 1.0/scale;
457  }
458  UpdateFlops(NumGlobalNonzeros());
459  EPETRA_CHK_ERR(ierr);
460  return(0);
461 }
462 
463 //=============================================================================
465 //
466 // This function scales the ith row of A by x[i].
467 //
468  double *xptr;
469  X.ExtractView(&xptr);
470  Vec petscX;
471 # ifdef HAVE_MPI
472  int ierr=VecCreateMPIWithArray(Comm_->Comm(),1, X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
473 # else //FIXME untested
474  int ierr=VecCreateSeqWithArray(Comm_->Comm(),1, X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
475 # endif
476 
477  MatDiagonalScale(Amat_, petscX, PETSC_NULL);
478 
479  ierr=VecDestroy(&petscX); CHKERRQ(ierr);
480  return(0);
481 } //LeftScale()
482 
483 //=============================================================================
485 //
486 // This function scales the jth row of A by x[j].
487 //
488  double *xptr;
489  X.ExtractView(&xptr);
490  Vec petscX;
491 # ifdef HAVE_MPI
492  int ierr=VecCreateMPIWithArray(Comm_->Comm(),1,X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
493 # else //FIXME untested
494  int ierr=VecCreateSeqWithArray(Comm_->Comm(),1,X.MyLength(),X.GlobalLength(),xptr,&petscX); CHKERRQ(ierr);
495 # endif
496 
497  MatDiagonalScale(Amat_, PETSC_NULL, petscX);
498 
499  ierr=VecDestroy(&petscX); CHKERRQ(ierr);
500  return(0);
501 } //RightScale()
502 
503 //=============================================================================
504 
505 double Epetra_PETScAIJMatrix::NormInf() const {
506  if (NormInf_>-1.0) return(NormInf_);
507 
508  MatNorm(Amat_, NORM_INFINITY,&NormInf_);
509  UpdateFlops(NumGlobalNonzeros());
510 
511  return(NormInf_);
512 }
513 
514 //=============================================================================
515 
516 double Epetra_PETScAIJMatrix::NormOne() const {
517  if (NormOne_>-1.0) return(NormOne_);
518  if (!Filled()) EPETRA_CHK_ERR(-1); // Matrix must be filled.
519 
520  MatNorm(Amat_, NORM_1,&NormOne_);
521  UpdateFlops(NumGlobalNonzeros());
522 
523  return(NormOne_);
524 }
525 
526 //=============================================================================
527 
528 void Epetra_PETScAIJMatrix::Print(std::ostream& os) const {
529  return;
530 }
531 
532 #endif /*HAVE_PETSC*/
int ExtractDiagonalCopy(Epetra_Vector &Diagonal) const
Returns a copy of the main diagonal in a user-provided vector.
int NumMyRowEntries(int MyRow, int &NumEntries) const
Return the current number of values stored for the specified local row.
Epetra_PETScAIJMatrix(Mat Amat)
Epetra_PETScAIJMatrix constructor.
int ExtractMyRowCopy(int MyRow, int Length, int &NumEntries, double *Values, int *Indices) const
Returns a copy of the specified local row in user-provided arrays.
int InvRowSums(Epetra_Vector &x) const
Computes the sum of absolute values of the rows of the Epetra_PETScAIJMatrix, results returned in x...
int RightScale(const Epetra_Vector &x)
Scales the Epetra_PETScAIJMatrix on the right with a Epetra_Vector x.
virtual ~Epetra_PETScAIJMatrix()
Epetra_PETScAIJMatrix Destructor.
double NormOne() const
Returns the one norm of the global matrix.
int LeftScale(const Epetra_Vector &x)
Scales the Epetra_PETScAIJMatrix on the left with a Epetra_Vector x.
virtual void Print(std::ostream &os) const
Print method.
int InvColSums(Epetra_Vector &x) const
Computes the sum of absolute values of the columns of the Epetra_PETScAIJMatrix, results returned in ...
int Solve(bool Upper, bool Trans, bool UnitDiagonal, const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Returns the result of a Epetra_PETScAIJMatrix multiplied by a Epetra_MultiVector X in Y...
int MaxNumEntries() const
Returns the maximum of NumMyRowEntries() over all rows.
int Multiply(bool TransA, const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Returns the result of a Epetra_PETScAIJMatrix multiplied by a Epetra_MultiVector X in Y...
int ExtractView(double **V) const
double NormInf() const
Returns the infinity norm of the global matrix.