Xpetra_MatrixMatrix.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Xpetra: A linear algebra interface package
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 // Tobias Wiesner (tawiesn@sandia.gov)
43 //
44 // ***********************************************************************
45 //
46 // @HEADER
47 
48 #ifndef PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
49 #define PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
50 
51 #include "Xpetra_ConfigDefs.hpp"
52 
53 #include "Xpetra_Matrix.hpp"
54 #include "Xpetra_CrsMatrixWrap.hpp"
55 
56 #include "Xpetra_Map.hpp"
57 #include "Xpetra_StridedMap.hpp"
59 #include "Xpetra_MapExtractor.hpp"
60 #include "Xpetra_MatrixFactory.hpp"
62 
63 #ifdef HAVE_XPETRA_EPETRA
65 #endif
66 
67 #ifdef HAVE_XPETRA_EPETRAEXT
68 #include <EpetraExt_MatrixMatrix.h>
69 #include <EpetraExt_RowMatrixOut.h>
70 #include <Epetra_RowMatrixTransposer.h>
71 #endif // HAVE_XPETRA_EPETRAEXT
72 
73 #ifdef HAVE_XPETRA_TPETRA
74 #include <TpetraExt_MatrixMatrix.hpp>
75 #include <MatrixMarket_Tpetra.hpp>
77 #include <Xpetra_TpetraVector.hpp>
79 #endif // HAVE_XPETRA_TPETRA
80 
81 namespace Xpetra {
82 
89 template <class Scalar,
90 class LocalOrdinal = int,
91 class GlobalOrdinal = LocalOrdinal,
93 class Helpers {
94 
95 private:
96 #include "Xpetra_UseShortNames.hpp"
97 
98 public:
99 
100 #ifdef HAVE_XPETRA_EPETRA
103  // Get the underlying Epetra Mtx
105  if (crsOp == Teuchos::null)
106  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
108  const RCP<const Xpetra::EpetraCrsMatrix> &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::EpetraCrsMatrix>(tmp_CrsMtx);
109  if (tmp_ECrsMtx == Teuchos::null)
110  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed"));
111  A = tmp_ECrsMtx->getEpetra_CrsMatrix();
112  return A;
113  } //Op2EpetraCrs
114 
117  // Get the underlying Epetra Mtx
119  if (crsOp == Teuchos::null)
120  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
122  const RCP<const Xpetra::EpetraCrsMatrix> &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::EpetraCrsMatrix>(tmp_CrsMtx);
123  if (tmp_ECrsMtx == Teuchos::null)
124  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed"));
125  A = tmp_ECrsMtx->getEpetra_CrsMatrixNonConst();
126  return A;
127  } //Op2NonConstEpetraCrs
128 
129  static const Epetra_CrsMatrix & Op2EpetraCrs(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & Op) {
131  // Get the underlying Epetra Mtx
132  try {
135  const RCP<const Xpetra::EpetraCrsMatrix> &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::EpetraCrsMatrix>(tmp_CrsMtx);
136  if (tmp_ECrsMtx == Teuchos::null)
137  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed"));
138  A = tmp_ECrsMtx->getEpetra_CrsMatrix();
139  return *A;
140  } catch(...) {
141  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
142  }
143  } //Op2EpetraCrs
144 
147  // Get the underlying Epetra Mtx
148  try {
151  const RCP<const Xpetra::EpetraCrsMatrixT<GlobalOrdinal> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::EpetraCrsMatrixT<GlobalOrdinal> >(tmp_CrsMtx);
152  if (tmp_ECrsMtx == Teuchos::null)
153  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed"));
154  A = Teuchos::rcp_const_cast<Epetra_CrsMatrix>(tmp_ECrsMtx->getEpetra_CrsMatrix());
155  return *A;
156  } catch(...) {
157  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
158  }
159  } //Op2NonConstEpetraCrs
160 #endif // HAVE_XPETRA_EPETRA
161 
162 #ifdef HAVE_XPETRA_TPETRA
165  // Get the underlying Tpetra Mtx
167  if (crsOp == Teuchos::null)
168  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
171  if (tmp_ECrsMtx == Teuchos::null)
172  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed"));
173  A = tmp_ECrsMtx->getTpetra_CrsMatrix();
174  return A;
175  } //Op2TpetraCrs
176 
179  // Get the underlying Tpetra Mtx
181  if (crsOp == Teuchos::null)
182  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
185  if (tmp_ECrsMtx == Teuchos::null)
186  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed"));
187  A = tmp_ECrsMtx->getTpetra_CrsMatrixNonConst();
188  return A;
189  } //Op2NonConstTpetraCrs
190 
191  static const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & Op2TpetraCrs(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & Op) {
193  // Get the underlying Tpetra Mtx
194  try{
198  if (tmp_TCrsMtx == Teuchos::null)
199  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed"));
200  A = tmp_TCrsMtx->getTpetra_CrsMatrix();
201  return *A;
202  } catch (...) {
203  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
204  }
205  } //Op2TpetraCrs
206 
207  static Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & Op2NonConstTpetraCrs(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & Op) {
209  // Get the underlying Tpetra Mtx
210  try{
214  if (tmp_TCrsMtx == Teuchos::null)
215  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed"));
216  A = Teuchos::rcp_const_cast<Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(tmp_TCrsMtx->getTpetra_CrsMatrix());
217  return *A;
218  } catch (...) {
219  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
220  }
221  } //Op2NonConstTpetraCrs
222 
223 #endif // HAVE_XPETRA_TPETRA
224 
225 };
226 
227 template <class Scalar,
228 class LocalOrdinal = int,
229 class GlobalOrdinal = LocalOrdinal,
232 
233 private:
234 #undef XPETRA_MATRIXMATRIX_SHORT
235 #include "Xpetra_UseShortNames.hpp"
236 
237 public:
238 
263  static void Multiply(
265  bool transposeA,
267  bool transposeB,
269  bool call_FillComplete_on_result = true,
270  bool doOptimizeStorage = true,
271  const std::string & label = std::string()) {
272 
273  if(transposeA == false && C.getRowMap()->isSameAs(*A.getRowMap()) == false) {
274  std::string msg = "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as row map of A";
276  }
277  else if(transposeA == true && C.getRowMap()->isSameAs(*A.getDomainMap()) == false) {
278  std::string msg = "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as domain map of A";
280  }
281 
282 
283  if (!A.isFillComplete())
284  throw(Xpetra::Exceptions::RuntimeError("A is not fill-completed"));
285  if (!B.isFillComplete())
286  throw(Xpetra::Exceptions::RuntimeError("B is not fill-completed"));
287 
288  bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
289 
290  if (C.getRowMap()->lib() == Xpetra::UseEpetra) {
291 # ifndef HAVE_XPETRA_EPETRAEXT
292  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply requires EpetraExt to be compiled."));
293 #else
297 
298  int i = EpetraExt::MatrixMatrix::Multiply(epA,transposeA,epB,transposeB,epC,haveMultiplyDoFillComplete);
299  if (haveMultiplyDoFillComplete) {
300  // Due to Epetra wrapper intricacies, we need to explicitly call
301  // fillComplete on Xpetra matrix here. Specifically, EpetraCrsMatrix
302  // only keeps an internal variable to check whether we are in resumed
303  // state or not, but never touches the underlying Epetra object. As
304  // such, we need to explicitly update the state of Xpetra matrix to
305  // that of Epetra one afterwords
306  C.fillComplete();
307  }
308 
309  if (i != 0) {
310  std::ostringstream buf;
311  buf << i;
312  std::string msg = "EpetraExt::MatrixMatrix::Multiply return value of " + buf.str();
313  throw(Exceptions::RuntimeError(msg));
314  }
315 
316 #endif
317  } else if (C.getRowMap()->lib() == Xpetra::UseTpetra) {
318 #ifdef HAVE_XPETRA_TPETRA
319  const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & tpA = Xpetra::Helpers<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Op2TpetraCrs(A);
320  const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & tpB = Xpetra::Helpers<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Op2TpetraCrs(B);
321  Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & tpC = Xpetra::Helpers<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Op2NonConstTpetraCrs(C);
322 
323  //18Feb2013 JJH I'm reenabling the code that allows the matrix matrix multiply to do the fillComplete.
324  //Previously, Tpetra's matrix matrix multiply did not support fillComplete.
325  Tpetra::MatrixMatrix::Multiply(tpA,transposeA,tpB,transposeB,tpC,haveMultiplyDoFillComplete,label);
326 #else
327  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra."));
328 #endif
329  }
330 
331  if(call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
333  params->set("Optimize Storage",doOptimizeStorage);
334  C.fillComplete((transposeB) ? B.getRangeMap() : B.getDomainMap(),
335  (transposeA) ? A.getDomainMap() : A.getRangeMap(),
336  params);
337  }
338 
339  // transfer striding information
342  C.CreateView("stridedMaps", rcpA, transposeA, rcpB, transposeB); // TODO use references instead of RCPs
343  } // end Multiply
344 
368  const Matrix& B, bool transposeB,
369  RCP<Matrix> C_in,
371  bool doFillComplete = true,
372  bool doOptimizeStorage = true,
373  const std::string & label = std::string()) {
374 
375  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
376  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
377 
378  // Default case: Xpetra Multiply
379  RCP<Matrix> C = C_in;
380 
381  if (C == Teuchos::null) {
382  double nnzPerRow = Teuchos::as<double>(0);
383 
384  if (A.getDomainMap()->lib() == Xpetra::UseTpetra) {
385  // For now, follow what ML and Epetra do.
386  GO numRowsA = A.getGlobalNumRows();
387  GO numRowsB = B.getGlobalNumRows();
388  nnzPerRow = sqrt(Teuchos::as<double>(A.getGlobalNumEntries())/numRowsA) +
389  sqrt(Teuchos::as<double>(B.getGlobalNumEntries())/numRowsB) - 1;
390  nnzPerRow *= nnzPerRow;
391  double totalNnz = nnzPerRow * A.getGlobalNumRows() * 0.75 + 100;
392  double minNnz = Teuchos::as<double>(1.2 * A.getGlobalNumEntries());
393  if (totalNnz < minNnz)
394  totalNnz = minNnz;
395  nnzPerRow = totalNnz / A.getGlobalNumRows();
396 
397  fos << "Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
398  }
399 
400  if (transposeA) C = MatrixFactory::Build(A.getDomainMap(), Teuchos::as<LO>(nnzPerRow));
401  else C = MatrixFactory::Build(A.getRowMap(), Teuchos::as<LO>(nnzPerRow));
402 
403  } else {
404  C->resumeFill(); // why this is not done inside of Tpetra MxM?
405  fos << "Reuse C pattern" << std::endl;
406  }
407 
408  Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage,label); // call Multiply routine from above
409 
410  return C;
411  }
412 
424  bool transposeA,
425  const Matrix & B,
426  bool transposeB,
428  bool callFillCompleteOnResult = true,
429  bool doOptimizeStorage = true,
430  const std::string & label = std::string()){
431  return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage,label);
432  }
433 
434 #ifdef HAVE_XPETRA_EPETRAEXT
435  // Michael Gee's MLMultiply
436  static RCP<Epetra_CrsMatrix> MLTwoMatrixMultiply(const Epetra_CrsMatrix& epA,
437  const Epetra_CrsMatrix& epB,
438  Teuchos::FancyOStream& fos) {
439  throw(Xpetra::Exceptions::RuntimeError("MLTwoMatrixMultiply only available for SC=double and GO=LO=int."));
440  return Teuchos::null;
441  }
442 #endif //ifdef HAVE_XPETRA_EPETRAEXT
443 
455  BlockedCrsMatrix& B, bool transposeB,
457  bool doFillComplete = true,
458  bool doOptimizeStorage = true) {
459  if (transposeA || transposeB)
460  throw Exceptions::RuntimeError("TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
461 
462  // Preconditions
463  if (!A.isFillComplete())
464  throw Exceptions::RuntimeError("A is not fill-completed");
465  if (!B.isFillComplete())
466  throw Exceptions::RuntimeError("B is not fill-completed");
467 
470 
471  RCP<BlockedCrsMatrix> C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
472 
473  for (size_t i = 0; i < A.Rows(); ++i) { // loop over all block rows of A
474  for (size_t j = 0; j < B.Cols(); ++j) { // loop over all block columns of B
475  RCP<Matrix> Cij;
476 
477  for (size_t l = 0; l < B.Rows(); ++l) { // loop for calculating entry C_{ij}
478  RCP<CrsMatrix> crmat1 = A.getMatrix(i,l);
479  RCP<CrsMatrix> crmat2 = B.getMatrix(l,j);
480 
481  if (crmat1.is_null() || crmat2.is_null()) {
482  continue;
483  }
484 
485  RCP<CrsMatrixWrap> crop1 = rcp(new CrsMatrixWrap(crmat1));
486  RCP<CrsMatrixWrap> crop2 = rcp(new CrsMatrixWrap(crmat2));
487 
488  RCP<Matrix> temp = Multiply (*crop1, false, *crop2, false, fos);
489 
490  if (Cij.is_null ())
491  Cij = temp;
492  else
494  }
495 
496  if (!Cij.is_null()) {
497  if (Cij->isFillComplete())
498  Cij->resumeFill();
499  Cij->fillComplete(B.getDomainMap(j), A.getRangeMap(i));
500 
501  RCP<CrsMatrixWrap> crsCij = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(Cij);
503  "MatrixFactory failed in generating a CrsMatrixWrap." );
504 
505  RCP<CrsMatrix> crsMatCij = crsCij->getCrsMatrix();
506  C->setMatrix(i, j, crsMatCij);
507 
508  } else {
509  C->setMatrix(i, j, Teuchos::null);
510  }
511  }
512  }
513 
514  if (doFillComplete)
515  C->fillComplete(); // call default fillComplete for BlockCrsMatrixWrap objects
516 
517  return C;
518  } // TwoMatrixMultiplyBlock
519 
532  static void TwoMatrixAdd(const Matrix& A, bool transposeA, SC alpha, Matrix& B, SC beta) {
533  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
534  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
535 
536  if (A.getRowMap()->lib() == Xpetra::UseEpetra) {
537  throw Exceptions::RuntimeError("TwoMatrixAdd for Epetra matrices needs <double,int,int> for Scalar, LocalOrdinal and GlobalOrdinal.");
538  } else if (A.getRowMap()->lib() == Xpetra::UseTpetra) {
539 #ifdef HAVE_XPETRA_TPETRA
540  const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& tpA = Xpetra::Helpers<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Op2TpetraCrs(A);
541  Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& tpB = Xpetra::Helpers<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Op2NonConstTpetraCrs(B);
542 
543  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
544 #else
545  throw Exceptions::RuntimeError("Xpetra must be compiled with Tpetra.");
546 #endif
547  }
548  } //MatrixMatrix::TwoMatrixAdd()
549 
550 
563  static void TwoMatrixAdd(const Matrix& A, bool transposeA, const SC& alpha,
564  const Matrix& B, bool transposeB, const SC& beta,
565  RCP<Matrix>& C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow = false) {
566  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
567  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
568 
569  if (C == Teuchos::null) {
570  if (!A.isFillComplete() || !B.isFillComplete())
571  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Global statistics are not available for estimates.");
572 
573  size_t maxNzInA = A.getGlobalMaxNumRowEntries();
574  size_t maxNzInB = B.getGlobalMaxNumRowEntries();
575  size_t numLocalRows = A.getNodeNumRows();
576 
577  if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
578  // first check if either A or B has at most 1 nonzero per row
579  // the case of both having at most 1 nz per row is handled by the ``else''
580  Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
581 
582  if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
583  for (size_t i = 0; i < numLocalRows; ++i)
584  exactNnzPerRow[i] = B.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInA;
585 
586  } else {
587  for (size_t i = 0; i < numLocalRows; ++i)
588  exactNnzPerRow[i] = A.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInB;
589  }
590 
591  fos << "MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
592  << ", using static profiling" << std::endl;
593  C = rcp(new CrsMatrixWrap(A.getRowMap(), exactNnzPerRow, Xpetra::StaticProfile));
594 
595  } else {
596  // general case
597  double nnzPerRowInA = Teuchos::as<double>(A.getGlobalNumEntries()) / A.getGlobalNumRows();
598  double nnzPerRowInB = Teuchos::as<double>(B.getGlobalNumEntries()) / B.getGlobalNumRows();
599  LO nnzToAllocate = Teuchos::as<LO>( (nnzPerRowInA + nnzPerRowInB) * 1.5) + Teuchos::as<LO>(1);
600 
602  //Use static profiling (more efficient) if the estimate is at least as big as the max
603  //possible nnz's in any single row of the result.
604  Xpetra::ProfileType pft = (maxPossible) > nnzToAllocate ? Xpetra::DynamicProfile : Xpetra::StaticProfile;
605 
606  fos << "nnzPerRowInA = " << nnzPerRowInA << ", nnzPerRowInB = " << nnzPerRowInB << std::endl;
607  fos << "MatrixMatrix::TwoMatrixAdd : space allocated per row = " << nnzToAllocate
608  << ", max possible nnz per row in sum = " << maxPossible
609  << ", using " << (pft == Xpetra::DynamicProfile ? "dynamic" : "static" ) << " profiling"
610  << std::endl;
611  C = rcp(new CrsMatrixWrap(A.getRowMap(), nnzToAllocate, pft));
612  }
613  if (transposeB)
614  fos << "MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
615  }
616 
617  if (C->getRowMap()->lib() == Xpetra::UseEpetra) {
618  throw Exceptions::RuntimeError("MatrixMatrix::Add for Epetra only available with Scalar = double, LO = GO = int.");
619  } else if (C->getRowMap()->lib() == Xpetra::UseTpetra) {
620 #ifdef HAVE_XPETRA_TPETRA
621  const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& tpA =
623  const Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& tpB =
627 
628  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, transposeB, beta, tpC);
629 #else
630  throw Exceptions::RuntimeError("Xpetra must be compile with Tpetra.");
631 #endif
632  }
633 
635  if (A.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(A));
636  if (B.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(B));
638 
639  } //MatrixMatrix::TwoMatrixAdd()
640 
641 
642 }; // class MatrixMatrix
643 
644 
645 // specialization MatrixMatrix for SC=double, LO=GO=int
646 template<>
647 class MatrixMatrix<double,int,int> {
648  typedef double SC;
649  typedef int LO;
650  typedef int GO;
655 
656 public:
657 
682  static void Multiply(
684  bool transposeA,
686  bool transposeB,
688  bool call_FillComplete_on_result = true,
689  bool doOptimizeStorage = true,
690  const std::string & label = std::string()) {
691  if(transposeA == false && C.getRowMap()->isSameAs(*A.getRowMap()) == false) {
692  std::string msg = "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as row map of A";
694  }
695  else if(transposeA == true && C.getRowMap()->isSameAs(*A.getDomainMap()) == false) {
696  std::string msg = "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as domain map of A";
698  }
699 
700 
701  if (!A.isFillComplete())
702  throw(Xpetra::Exceptions::RuntimeError("A is not fill-completed"));
703  if (!B.isFillComplete())
704  throw(Xpetra::Exceptions::RuntimeError("B is not fill-completed"));
705 
706  bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
707 
708  if (C.getRowMap()->lib() == Xpetra::UseEpetra) {
709 # ifndef HAVE_XPETRA_EPETRAEXT
710  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply requires EpetraExt to be compiled."));
711 #else
712  Epetra_CrsMatrix & epA = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstEpetraCrs(A);
713  Epetra_CrsMatrix & epB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstEpetraCrs(B);
714  Epetra_CrsMatrix & epC = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstEpetraCrs(C);
715 
716  int i = EpetraExt::MatrixMatrix::Multiply(epA,transposeA,epB,transposeB,epC,haveMultiplyDoFillComplete);
717  if (haveMultiplyDoFillComplete) {
718  // Due to Epetra wrapper intricacies, we need to explicitly call
719  // fillComplete on Xpetra matrix here. Specifically, EpetraCrsMatrix
720  // only keeps an internal variable to check whether we are in resumed
721  // state or not, but never touches the underlying Epetra object. As
722  // such, we need to explicitly update the state of Xpetra matrix to
723  // that of Epetra one afterwords
724  C.fillComplete();
725  }
726 
727  if (i != 0) {
728  std::ostringstream buf;
729  buf << i;
730  std::string msg = "EpetraExt::MatrixMatrix::Multiply return value of " + buf.str();
731  throw(Exceptions::RuntimeError(msg));
732  }
733 
734 #endif
735  } else if (C.getRowMap()->lib() == Xpetra::UseTpetra) {
736 #ifdef HAVE_XPETRA_TPETRA
737  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
738  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
739  Tpetra::CrsMatrix<SC,LO,GO,NO> & tpC = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(C);
740 
741  //18Feb2013 JJH I'm reenabling the code that allows the matrix matrix multiply to do the fillComplete.
742  //Previously, Tpetra's matrix matrix multiply did not support fillComplete.
743  Tpetra::MatrixMatrix::Multiply(tpA,transposeA,tpB,transposeB,tpC,haveMultiplyDoFillComplete,label);
744 #else
745  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra."));
746 #endif
747  }
748 
749  if(call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
751  params->set("Optimize Storage",doOptimizeStorage);
752  C.fillComplete((transposeB) ? B.getRangeMap() : B.getDomainMap(),
753  (transposeA) ? A.getDomainMap() : A.getRangeMap(),
754  params);
755  }
756 
757  // transfer striding information
758  RCP<Xpetra::Matrix<SC,LO,GO,NO> > rcpA = Teuchos::rcp_const_cast<Xpetra::Matrix<SC,LO,GO,NO> >(Teuchos::rcpFromRef(A));
759  RCP<Xpetra::Matrix<SC,LO,GO,NO> > rcpB = Teuchos::rcp_const_cast<Xpetra::Matrix<SC,LO,GO,NO> >(Teuchos::rcpFromRef(B));
760  C.CreateView("stridedMaps", rcpA, transposeA, rcpB, transposeB); // TODO use references instead of RCPs
761  } // end Multiply
762 
785  static RCP<Xpetra::Matrix<SC,LO,GO,NO> > Multiply(const Matrix& A, bool transposeA,
786  const Matrix& B, bool transposeB,
787  RCP<Matrix> C_in,
789  bool doFillComplete = true,
790  bool doOptimizeStorage = true,
791  const std::string & label = std::string()) {
792 
793  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
794  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
795 
796  // Optimization using ML Multiply when available and requested
797  // This feature is currently not supported. We would have to introduce the HAVE_XPETRA_ML_MMM flag
798 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT) && defined(HAVE_XPETRA_ML_MMM)
799  if (B.getDomainMap()->lib() == Xpetra::UseEpetra && !transposeA && !transposeB) {
802  RCP<Epetra_CrsMatrix> epC = MLTwoMatrixMultiply(*epA, *epB, fos);
803 
804  RCP<Matrix> C = Convert_Epetra_CrsMatrix_ToXpetra_CrsMatrixWrap<SC,LO,GO,NO> (epC);
805  if (doFillComplete) {
807  params->set("Optimize Storage", doOptimizeStorage);
808  C->fillComplete(B.getDomainMap(), A.getRangeMap(), params);
809  }
810 
811  // Fill strided maps information
812  // This is necessary since the ML matrix matrix multiplication routine has no handling for this
813  // TODO: move this call to MLMultiply...
814  C->CreateView("stridedMaps", rcpFromRef(A), transposeA, rcpFromRef(B), transposeB);
815 
816  return C;
817  }
818 #endif // EPETRA + EPETRAEXT + ML
819 
820  // Default case: Xpetra Multiply
821  RCP<Matrix> C = C_in;
822 
823  if (C == Teuchos::null) {
824  double nnzPerRow = Teuchos::as<double>(0);
825 
826  if (A.getDomainMap()->lib() == Xpetra::UseTpetra) {
827  // For now, follow what ML and Epetra do.
828  GO numRowsA = A.getGlobalNumRows();
829  GO numRowsB = B.getGlobalNumRows();
830  nnzPerRow = sqrt(Teuchos::as<double>(A.getGlobalNumEntries())/numRowsA) +
831  sqrt(Teuchos::as<double>(B.getGlobalNumEntries())/numRowsB) - 1;
832  nnzPerRow *= nnzPerRow;
833  double totalNnz = nnzPerRow * A.getGlobalNumRows() * 0.75 + 100;
834  double minNnz = Teuchos::as<double>(1.2 * A.getGlobalNumEntries());
835  if (totalNnz < minNnz)
836  totalNnz = minNnz;
837  nnzPerRow = totalNnz / A.getGlobalNumRows();
838 
839  fos << "Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
840  }
841 
842  if (transposeA) C = Xpetra::MatrixFactory<SC,LO,GO,NO>::Build(A.getDomainMap(), Teuchos::as<LO>(nnzPerRow));
843  else C = Xpetra::MatrixFactory<SC,LO,GO,NO>::Build(A.getRowMap(), Teuchos::as<LO>(nnzPerRow));
844 
845  } else {
846  C->resumeFill(); // why this is not done inside of Tpetra MxM?
847  fos << "Reuse C pattern" << std::endl;
848  }
849 
850  Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage,label); // call Multiply routine from above
851 
852  return C;
853  }
854 
865  static RCP<Xpetra::Matrix<SC,LO,GO,NO> > Multiply(const Matrix & A,
866  bool transposeA,
867  const Matrix & B,
868  bool transposeB,
870  bool callFillCompleteOnResult = true,
871  bool doOptimizeStorage = true,
872  const std::string & label = std::string()){
873  return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage,label);
874  }
875 
876 #ifdef HAVE_XPETRA_EPETRAEXT
877  // Michael Gee's MLMultiply
878  static RCP<Epetra_CrsMatrix> MLTwoMatrixMultiply(const Epetra_CrsMatrix& epA,
879  const Epetra_CrsMatrix& epB,
880  Teuchos::FancyOStream& fos) {
881 #if defined(HAVE_XPETRA_ML_MMM) // Note: this is currently not supported
882  ML_Comm* comm;
883  ML_Comm_Create(&comm);
884  fos << "****** USING ML's MATRIX MATRIX MULTIPLY ******" << std::endl;
885 #ifdef HAVE_MPI
886  // ML_Comm uses MPI_COMM_WORLD, so try to use the same communicator as epA.
887  const Epetra_MpiComm * Mcomm = dynamic_cast<const Epetra_MpiComm*>(&(epA.Comm()));
888  if (Mcomm)
889  ML_Comm_Set_UsrComm(comm,Mcomm->GetMpiComm());
890 # endif
891  //in order to use ML, there must be no indices missing from the matrix column maps.
892  EpetraExt::CrsMatrix_SolverMap Atransform;
893  EpetraExt::CrsMatrix_SolverMap Btransform;
894  const Epetra_CrsMatrix& A = Atransform(const_cast<Epetra_CrsMatrix&>(epA));
895  const Epetra_CrsMatrix& B = Btransform(const_cast<Epetra_CrsMatrix&>(epB));
896 
897  if (!A.Filled()) throw Exceptions::RuntimeError("A has to be FillCompleted");
898  if (!B.Filled()) throw Exceptions::RuntimeError("B has to be FillCompleted");
899 
900  // create ML operators from EpetraCrsMatrix
901  ML_Operator* ml_As = ML_Operator_Create(comm);
902  ML_Operator* ml_Bs = ML_Operator_Create(comm);
903  ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&A),ml_As); // Should we test if the lightweight wrapper is actually used or if WrapEpetraCrsMatrix fall backs to the heavy one?
904  ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&B),ml_Bs);
905  ML_Operator* ml_AtimesB = ML_Operator_Create(comm);
906  {
907  Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("ML_2matmult kernel"));
908  ML_2matmult(ml_As,ml_Bs,ml_AtimesB,ML_CSR_MATRIX); // do NOT use ML_EpetraCRS_MATRIX!!!
909  }
910  ML_Operator_Destroy(&ml_As);
911  ML_Operator_Destroy(&ml_Bs);
912 
913  // For ml_AtimesB we have to reconstruct the column map in global indexing,
914  // The following is going down to the salt-mines of ML ...
915  // note: we use integers, since ML only works for Epetra...
916  int N_local = ml_AtimesB->invec_leng;
917  ML_CommInfoOP* getrow_comm = ml_AtimesB->getrow->pre_comm;
918  if (!getrow_comm) throw(Exceptions::RuntimeError("ML_Operator does not have a CommInfo"));
919  ML_Comm* comm_AB = ml_AtimesB->comm; // get comm object
920  if (N_local != B.DomainMap().NumMyElements())
921  throw(Exceptions::RuntimeError("Mismatch in local row dimension between ML and Epetra"));
922  int N_rcvd = 0;
923  int N_send = 0;
924  int flag = 0;
925  for (int i = 0; i < getrow_comm->N_neighbors; i++) {
926  N_rcvd += (getrow_comm->neighbors)[i].N_rcv;
927  N_send += (getrow_comm->neighbors)[i].N_send;
928  if ( ((getrow_comm->neighbors)[i].N_rcv != 0) &&
929  ((getrow_comm->neighbors)[i].rcv_list != NULL) ) flag = 1;
930  }
931  // For some unknown reason, ML likes to have stuff one larger than
932  // neccessary...
933  std::vector<double> dtemp(N_local + N_rcvd + 1); // "double" vector for comm function
934  std::vector<int> cmap (N_local + N_rcvd + 1); // vector for gids
935  for (int i = 0; i < N_local; ++i) {
936  cmap[i] = B.DomainMap().GID(i);
937  dtemp[i] = (double) cmap[i];
938  }
939  ML_cheap_exchange_bdry(&dtemp[0],getrow_comm,N_local,N_send,comm_AB); // do communication
940  if (flag) { // process received data
941  int count = N_local;
942  const int neighbors = getrow_comm->N_neighbors;
943  for (int i = 0; i < neighbors; i++) {
944  const int nrcv = getrow_comm->neighbors[i].N_rcv;
945  for (int j = 0; j < nrcv; j++)
946  cmap[getrow_comm->neighbors[i].rcv_list[j]] = (int) dtemp[count++];
947  }
948  } else {
949  for (int i = 0; i < N_local+N_rcvd; ++i)
950  cmap[i] = (int)dtemp[i];
951  }
952  dtemp.clear(); // free double array
953 
954  // we can now determine a matching column map for the result
955  Epetra_Map gcmap(-1, N_local+N_rcvd, &cmap[0], B.ColMap().IndexBase(), A.Comm());
956 
957  int allocated = 0;
958  int rowlength;
959  double* val = NULL;
960  int* bindx = NULL;
961 
962  const int myrowlength = A.RowMap().NumMyElements();
963  const Epetra_Map& rowmap = A.RowMap();
964 
965  // Determine the maximum bandwith for the result matrix.
966  // replaces the old, very(!) memory-consuming guess:
967  // int guessnpr = A.MaxNumEntries()*B.MaxNumEntries();
968  int educatedguess = 0;
969  for (int i = 0; i < myrowlength; ++i) {
970  // get local row
971  ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
972  if (rowlength>educatedguess)
973  educatedguess = rowlength;
974  }
975 
976  // allocate our result matrix and fill it
977  RCP<Epetra_CrsMatrix> result = rcp(new Epetra_CrsMatrix(::Copy, A.RangeMap(), gcmap, educatedguess, false));
978 
979  std::vector<int> gcid(educatedguess);
980  for (int i = 0; i < myrowlength; ++i) {
981  const int grid = rowmap.GID(i);
982  // get local row
983  ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
984  if (!rowlength) continue;
985  if ((int)gcid.size() < rowlength) gcid.resize(rowlength);
986  for (int j = 0; j < rowlength; ++j) {
987  gcid[j] = gcmap.GID(bindx[j]);
988  if (gcid[j] < 0)
989  throw Exceptions::RuntimeError("Error: cannot find gcid!");
990  }
991  int err = result->InsertGlobalValues(grid, rowlength, val, &gcid[0]);
992  if (err != 0 && err != 1) {
993  std::ostringstream errStr;
994  errStr << "Epetra_CrsMatrix::InsertGlobalValues returned err=" << err;
995  throw Exceptions::RuntimeError(errStr.str());
996  }
997  }
998  // free memory
999  if (bindx) ML_free(bindx);
1000  if (val) ML_free(val);
1001  ML_Operator_Destroy(&ml_AtimesB);
1002  ML_Comm_Destroy(&comm);
1003 
1004  return result;
1005 #else // no MUELU_ML
1007  "No ML multiplication available. This feature is currently not supported by Xpetra.");
1008  return Teuchos::null;
1009 #endif
1010  }
1011 #endif //ifdef HAVE_XPETRA_EPETRAEXT
1012 
1024  Xpetra::BlockedCrsMatrix<SC,LO,GO,NO>& B, bool transposeB,
1025  Teuchos::FancyOStream& fos,
1026  bool doFillComplete = true,
1027  bool doOptimizeStorage = true) {
1028  if (transposeA || transposeB)
1029  throw Exceptions::RuntimeError("TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
1030 
1031  // Preconditions
1032  if (!A.isFillComplete())
1033  throw Exceptions::RuntimeError("A is not fill-completed");
1034  if (!B.isFillComplete())
1035  throw Exceptions::RuntimeError("B is not fill-completed");
1036 
1039 
1041  rcp(new Xpetra::BlockedCrsMatrix<SC,LO,GO,NO>(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1042 
1043  for (size_t i = 0; i < A.Rows(); ++i) { // loop over all block rows of A
1044  for (size_t j = 0; j < B.Cols(); ++j) { // loop over all block columns of B
1045  RCP<Matrix> Cij;
1046 
1047  for (size_t l = 0; l < B.Rows(); ++l) { // loop for calculating entry C_{ij}
1050 
1051  if (crmat1.is_null() || crmat2.is_null()) {
1052  continue;
1053  }
1054 
1057 
1058  RCP<Xpetra::Matrix<SC,LO,GO,NO> > temp = Multiply (*crop1, false, *crop2, false, fos);
1059 
1060  if (Cij.is_null ())
1061  Cij = temp;
1062  else
1063  Xpetra::MatrixMatrix<SC,LO,GO,NO>::TwoMatrixAdd (*temp, false, 1.0, *Cij, 1.0);
1064  }
1065 
1066  if (!Cij.is_null()) {
1067  if (Cij->isFillComplete())
1068  Cij->resumeFill();
1069  Cij->fillComplete(B.getDomainMap(j), A.getRangeMap(i));
1070 
1071  RCP<Xpetra::CrsMatrixWrap<SC,LO,GO,NO> > crsCij = Teuchos::rcp_dynamic_cast<Xpetra::CrsMatrixWrap<SC,LO,GO,NO> >(Cij);
1073  "MatrixFactory failed in generating a CrsMatrixWrap." );
1074 
1075  RCP<Xpetra::CrsMatrix<SC,LO,GO,NO> > crsMatCij = crsCij->getCrsMatrix();
1076  C->setMatrix(i, j, crsMatCij);
1077 
1078  } else {
1079  C->setMatrix(i, j, Teuchos::null);
1080  }
1081  }
1082  }
1083 
1084  if (doFillComplete)
1085  C->fillComplete(); // call default fillComplete for BlockCrsMatrixWrap objects
1086 
1087  return C;
1088  } // TwoMatrixMultiplyBlock
1089 
1102  static void TwoMatrixAdd(const Xpetra::Matrix<SC,LO,GO,NO>& A, bool transposeA, SC alpha, Xpetra::Matrix<SC,LO,GO,NO>& B, SC beta) {
1103  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
1104  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
1105 
1106  if (A.getRowMap()->lib() == Xpetra::UseEpetra) {
1107 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1108  const Epetra_CrsMatrix& epA = Xpetra::Helpers<SC,LO,GO,NO>::Op2EpetraCrs(A);
1109  Epetra_CrsMatrix& epB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstEpetraCrs(B);
1110 
1111  //FIXME is there a bug if beta=0?
1112  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, beta);
1113 
1114  if (rv != 0)
1115  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value " + Teuchos::toString(rv));
1116  std::ostringstream buf;
1117 #else
1118  throw Exceptions::RuntimeError("Xpetra must be compiled with EpetraExt.");
1119 #endif
1120  } else if (A.getRowMap()->lib() == Xpetra::UseTpetra) {
1121 #ifdef HAVE_XPETRA_TPETRA
1122  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
1123  Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(B);
1124 
1125  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
1126 #else
1127  throw Exceptions::RuntimeError("Xpetra must be compiled with Tpetra.");
1128 #endif
1129  }
1130  } //MatrixMatrix::TwoMatrixAdd()
1131 
1132 
1145  static void TwoMatrixAdd(const Xpetra::Matrix<SC,LO,GO,NO>& A, bool transposeA, const SC& alpha,
1146  const Xpetra::Matrix<SC,LO,GO,NO>& B, bool transposeB, const SC& beta,
1147  RCP<Xpetra::Matrix<SC,LO,GO,NO> >& C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow = false) {
1148  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
1149  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
1150 
1151  if (C == Teuchos::null) {
1152  if (!A.isFillComplete() || !B.isFillComplete())
1153  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Global statistics are not available for estimates.");
1154 
1155  size_t maxNzInA = A.getGlobalMaxNumRowEntries();
1156  size_t maxNzInB = B.getGlobalMaxNumRowEntries();
1157  size_t numLocalRows = A.getNodeNumRows();
1158 
1159  if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
1160  // first check if either A or B has at most 1 nonzero per row
1161  // the case of both having at most 1 nz per row is handled by the ``else''
1162  Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
1163 
1164  if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
1165  for (size_t i = 0; i < numLocalRows; ++i)
1166  exactNnzPerRow[i] = B.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInA;
1167 
1168  } else {
1169  for (size_t i = 0; i < numLocalRows; ++i)
1170  exactNnzPerRow[i] = A.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInB;
1171  }
1172 
1173  fos << "MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
1174  << ", using static profiling" << std::endl;
1176 
1177  } else {
1178  // general case
1179  double nnzPerRowInA = Teuchos::as<double>(A.getGlobalNumEntries()) / A.getGlobalNumRows();
1180  double nnzPerRowInB = Teuchos::as<double>(B.getGlobalNumEntries()) / B.getGlobalNumRows();
1181  LO nnzToAllocate = Teuchos::as<LO>( (nnzPerRowInA + nnzPerRowInB) * 1.5) + Teuchos::as<LO>(1);
1182 
1183  LO maxPossible = A.getGlobalMaxNumRowEntries() + B.getGlobalMaxNumRowEntries();
1184  //Use static profiling (more efficient) if the estimate is at least as big as the max
1185  //possible nnz's in any single row of the result.
1186  Xpetra::ProfileType pft = (maxPossible) > nnzToAllocate ? Xpetra::DynamicProfile : Xpetra::StaticProfile;
1187 
1188  fos << "nnzPerRowInA = " << nnzPerRowInA << ", nnzPerRowInB = " << nnzPerRowInB << std::endl;
1189  fos << "MatrixMatrix::TwoMatrixAdd : space allocated per row = " << nnzToAllocate
1190  << ", max possible nnz per row in sum = " << maxPossible
1191  << ", using " << (pft == Xpetra::DynamicProfile ? "dynamic" : "static" ) << " profiling"
1192  << std::endl;
1193  C = rcp(new Xpetra::CrsMatrixWrap<SC,LO,GO,NO>(A.getRowMap(), nnzToAllocate, pft));
1194  }
1195  if (transposeB)
1196  fos << "MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
1197  }
1198 
1199  if (C->getRowMap()->lib() == Xpetra::UseEpetra) {
1200 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1201  const Epetra_CrsMatrix& epA = Xpetra::Helpers<SC,LO,GO,NO>::Op2EpetraCrs(A);
1202  const Epetra_CrsMatrix& epB = Xpetra::Helpers<SC,LO,GO,NO>::Op2EpetraCrs(B);
1204  Epetra_CrsMatrix* ref2epC = &*epC; //to avoid a compiler error...
1205 
1206  //FIXME is there a bug if beta=0?
1207  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, transposeB, beta, ref2epC);
1208 
1209  if (rv != 0)
1210  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value of " + Teuchos::toString(rv));
1211 #else
1212  throw Exceptions::RuntimeError("MueLu must be compile with EpetraExt.");
1213 #endif
1214  } else if (C->getRowMap()->lib() == Xpetra::UseTpetra) {
1215 #ifdef HAVE_XPETRA_TPETRA
1216  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA =
1218  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB =
1222 
1223  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, transposeB, beta, tpC);
1224 #else
1225  throw Exceptions::RuntimeError("Xpetra must be compile with Tpetra.");
1226 #endif
1227  }
1228 
1230  if (A.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(A));
1231  if (B.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(B));
1233 
1234  } //MatrixMatrix::TwoMatrixAdd()
1235 };
1236 
1237 } // end namespace Xpetra
1238 
1239 #define XPETRA_MATRIXMATRIX_SHORT
1240 
1241 #endif /* PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_ */
virtual size_t getNodeNumRows() const =0
Returns the number of matrix rows owned on the calling node.
RCP< const MapExtractor > getRangeMapExtractor()
Returns map extractor class for range map.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
static RCP< Xpetra::BlockedCrsMatrix< SC, LO, GO, NO > > TwoMatrixMultiplyBlock(Xpetra::BlockedCrsMatrix< SC, LO, GO, NO > &A, bool transposeA, Xpetra::BlockedCrsMatrix< SC, LO, GO, NO > &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply "in-place".
RCP< CrsMatrix > getCrsMatrix() const
Xpetra::MultiVector< double, int, int, NO > MultiVector
virtual global_size_t getGlobalNumRows() const =0
Returns the number of global rows in this matrix.
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string())
Helper function to do matrix-matrix multiply.
bool isFillComplete() const
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
GlobalOrdinal GO
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
static const Epetra_CrsMatrix & Op2EpetraCrs(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op)
RCP< const Map > getRangeMap() const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Xpetra utility class containing transformation routines between Xpetra::Matrix and Epetra/Tpetra obje...
Xpetra namespace
KokkosClassic::DefaultNode::DefaultNodeType NO
Teuchos::RCP< CrsMatrix > getMatrix(size_t r, size_t c) const
return block (r,c)
static void Multiply(const Xpetra::Matrix< SC, LO, GO, NO > &A, bool transposeA, const Xpetra::Matrix< SC, LO, GO, NO > &B, bool transposeB, Xpetra::Matrix< SC, LO, GO, NO > &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string())
static Tpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > & Op2NonConstTpetraCrs(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op)
Exception throws to report errors in the internal logical of the program.
LocalOrdinal LO
virtual size_t getGlobalMaxNumRowEntries() const =0
Returns the maximum number of entries across all rows/columns on all nodes.
Xpetra::Matrix< double, int, int, NO > Matrix
static void TwoMatrixAdd(const Xpetra::Matrix< SC, LO, GO, NO > &A, bool transposeA, SC alpha, Xpetra::Matrix< SC, LO, GO, NO > &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
static void Multiply(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, bool transposeA, const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &B, bool transposeB, Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string())
static RCP< Tpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op2NonConstTpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
static Epetra_CrsMatrix & Op2NonConstEpetraCrs(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op)
static RCP< Xpetra::Matrix< SC, LO, GO, NO > > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string())
Helper function to do matrix-matrix multiply.
static RCP< Time > getNewTimer(const std::string &name)
Exception indicating invalid cast attempted.
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(BlockedCrsMatrix &A, bool transposeA, BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply "in-place".
virtual void fillComplete(const RCP< const Map > &domainMap, const RCP< const Map > &rangeMap, const RCP< ParameterList > &params=null)=0
Signal that data entry is complete, specifying domain and range maps.
static RCP< Xpetra::Matrix< SC, LO, GO, NO > > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string())
Helper function to do matrix-matrix multiply.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
bool IsView(const viewLabel_t viewLabel) const
static void TwoMatrixAdd(const Xpetra::Matrix< SC, LO, GO, NO > &A, bool transposeA, const SC &alpha, const Xpetra::Matrix< SC, LO, GO, NO > &B, bool transposeB, const SC &beta, RCP< Xpetra::Matrix< SC, LO, GO, NO > > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
RCP< const MapExtractor > getDomainMapExtractor()
Returns map extractor for domain map.
virtual bool isFillComplete() const =0
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
virtual size_t Cols() const
number of column blocks
void CreateView(viewLabel_t viewLabel, const RCP< const Map > &rowMap, const RCP< const Map > &colMap)
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
RCP< Epetra_CrsMatrix > getEpetra_CrsMatrixNonConst() const
Get the underlying Epetra matrix.
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
Returns the current number of entries on this node in the specified local row.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
static RCP< const Epetra_CrsMatrix > Op2EpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
RCP< const Epetra_CrsMatrix > getEpetra_CrsMatrix() const
Get the underlying Epetra matrix.
Exception throws to report incompatible objects (like maps).
RCP< const Map > getDomainMap() const
Returns the Map associated with the full domain of this operator. This will be null until fillComplet...
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string())
Helper function to do matrix-matrix multiply.
static RCP< Epetra_CrsMatrix > Op2NonConstEpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
Copy
virtual global_size_t getGlobalNumEntries() const =0
Returns the global number of entries in this matrix.
Concrete implementation of Xpetra::Matrix.
virtual Teuchos::RCP< const Map > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y...
virtual size_t Rows() const
number of row blocks
static RCP< Matrix > Build(const RCP< const Map > &rowMap, size_t maxNumEntriesPerRow, Xpetra::ProfileType pftype=Xpetra::DynamicProfile)
Constructor specifying the number of non-zeros for all rows.
static RCP< const Tpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op2TpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
virtual const RCP< const Map > & getRowMap() const
Returns the Map that describes the row distribution in this matrix.
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
virtual Teuchos::RCP< const Map > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
static const Tpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > & Op2TpetraCrs(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op)
Xpetra-specific matrix class.
std::string toString(const T &t)
bool is_null() const