Tpetra Matrix/Vector Services  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
Tpetra_CrsGraph_def.hpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2008) Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 // @HEADER
00041 
00042 #ifndef TPETRA_CRSGRAPH_DEF_HPP
00043 #define TPETRA_CRSGRAPH_DEF_HPP
00044 
00045 #include <Tpetra_Distributor.hpp>
00046 #include <Teuchos_Assert.hpp>
00047 #include <Teuchos_NullIteratorTraits.hpp>
00048 #include <Teuchos_as.hpp>
00049 #include <algorithm>
00050 #include <string>
00051 #include <utility>
00052 #include <Teuchos_SerialDenseMatrix.hpp>
00053 
00054 #ifdef DOXYGEN_USE_ONLY
00055   #include "Tpetra_CrsGraph_decl.hpp"
00056 #endif
00057 
00058 namespace Tpetra {
00059 
00062   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00063   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00064   CrsGraph (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &rowMap,
00065             size_t maxNumEntriesPerRow,
00066             ProfileType pftype,
00067             const RCP<ParameterList>& params)
00068   : DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>(rowMap)
00069   , rowMap_(rowMap)
00070   , nodeNumEntries_(0)
00071   , nodeNumAllocated_(OrdinalTraits<size_t>::invalid())
00072   , pftype_(pftype)
00073   , numAllocForAllRows_(maxNumEntriesPerRow)
00074   , indicesAreAllocated_(false)
00075   , indicesAreLocal_(false)
00076   , indicesAreGlobal_(false)
00077   , fillComplete_(false)
00078   , indicesAreSorted_ (true)
00079   , noRedundancies_ (true)
00080   , haveLocalConstants_ (false)
00081   , haveGlobalConstants_ (false)
00082   , sortGhostsAssociatedWithEachProcessor_(true)
00083   {
00084     typedef Teuchos::OrdinalTraits<size_t> OTST;
00085     staticAssertions();
00086     TEUCHOS_TEST_FOR_EXCEPTION(maxNumEntriesPerRow == OTST::invalid(),
00087       std::invalid_argument, "The allocation hint must be a valid size_t value, "
00088       "which in this case means it must not be Teuchos::OrdinalTraits<size_t>::"
00089       "invalid().");
00090     resumeFill(params);
00091     checkInternalState();
00092   }
00093 
00096   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00097   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00098   CrsGraph (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &rowMap,
00099             const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &colMap,
00100             size_t maxNumEntriesPerRow,
00101             ProfileType pftype,
00102             const RCP<ParameterList>& params)
00103   : DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>(rowMap)
00104   , rowMap_(rowMap)
00105   , colMap_(colMap)
00106   , nodeNumEntries_(0)
00107   , nodeNumAllocated_(OrdinalTraits<size_t>::invalid())
00108   , pftype_(pftype)
00109   , numAllocForAllRows_(maxNumEntriesPerRow)
00110   , indicesAreAllocated_(false)
00111   , indicesAreLocal_(false)
00112   , indicesAreGlobal_(false)
00113   , fillComplete_(false)
00114   , indicesAreSorted_(true)
00115   , noRedundancies_(true)
00116   , haveLocalConstants_ (false)
00117   , haveGlobalConstants_ (false)
00118   , sortGhostsAssociatedWithEachProcessor_(true)
00119   {
00120     typedef Teuchos::OrdinalTraits<size_t> OTST;
00121     staticAssertions();
00122     TEUCHOS_TEST_FOR_EXCEPTION(maxNumEntriesPerRow == OTST::invalid(),
00123       std::invalid_argument, "The allocation hint must be a valid size_t value, "
00124       "which in this case means it must not be Teuchos::OrdinalTraits<size_t>::"
00125       "invalid().");
00126     resumeFill(params);
00127     checkInternalState();
00128   }
00129 
00132   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00133   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00134   CrsGraph (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &rowMap,
00135             const ArrayRCP<const size_t> &NumEntriesPerRowToAlloc,
00136             ProfileType pftype,
00137             const RCP<ParameterList>& params)
00138   : DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>(rowMap)
00139   , rowMap_(rowMap)
00140   , nodeNumEntries_(0)
00141   , nodeNumAllocated_(OrdinalTraits<size_t>::invalid())
00142   , pftype_(pftype)
00143   , numAllocPerRow_(NumEntriesPerRowToAlloc)
00144   , numAllocForAllRows_(0)
00145   , indicesAreAllocated_(false)
00146   , indicesAreLocal_(false)
00147   , indicesAreGlobal_(false)
00148   , fillComplete_(false)
00149   , indicesAreSorted_(true)
00150   , noRedundancies_(true)
00151   , haveLocalConstants_ (false)
00152   , haveGlobalConstants_ (false)
00153   , sortGhostsAssociatedWithEachProcessor_(true)
00154   {
00155     typedef Teuchos::OrdinalTraits<size_t> OTST;
00156     const char tfecfFuncName[] = "CrsGraph(rowMap,NumEntriesPerRowToAlloc)";
00157     staticAssertions();
00158     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC((size_t)NumEntriesPerRowToAlloc.size() != getNodeNumRows(), std::invalid_argument,
00159         ": NumEntriesPerRowToAlloc must have as many entries as specified by rowMap for this node.");
00160     for (size_t r=0; r < getNodeNumRows(); ++r) {
00161       const size_t curRowCount = NumEntriesPerRowToAlloc[r];
00162       TEUCHOS_TEST_FOR_EXCEPTION(curRowCount == OTST::invalid(),
00163         std::invalid_argument, "NumEntriesPerRowToAlloc[" << r << "] specifies "
00164         "an invalid number of entries (Teuchos::OrdinalTraits<size_t>::"
00165         "invalid()).");
00166     }
00167     resumeFill(params);
00168     checkInternalState();
00169   }
00170 
00171 
00174   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00175   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00176   CrsGraph (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &rowMap,
00177             const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &colMap,
00178             const ArrayRCP<const size_t> &NumEntriesPerRowToAlloc,
00179             ProfileType pftype,
00180             const RCP<ParameterList>& params)
00181   : DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>(rowMap)
00182   , rowMap_(rowMap)
00183   , colMap_(colMap)
00184   , nodeNumEntries_(0)
00185   , nodeNumAllocated_(OrdinalTraits<size_t>::invalid())
00186   , pftype_(pftype)
00187   , numAllocPerRow_(NumEntriesPerRowToAlloc)
00188   , numAllocForAllRows_(0)
00189   , indicesAreAllocated_(false)
00190   , indicesAreLocal_(false)
00191   , indicesAreGlobal_(false)
00192   , fillComplete_(false)
00193   , indicesAreSorted_(true)
00194   , noRedundancies_(true)
00195   , haveLocalConstants_ (false)
00196   , haveGlobalConstants_ (false)
00197   , sortGhostsAssociatedWithEachProcessor_(true)
00198   {
00199     typedef Teuchos::OrdinalTraits<size_t> OTST;
00200     const char tfecfFuncName[] = "CrsGraph(rowMap,colMap,NumEntriesPerRowToAlloc)";
00201     staticAssertions();
00202     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC((size_t)NumEntriesPerRowToAlloc.size() != getNodeNumRows(), std::invalid_argument,
00203         ": NumEntriesPerRowToAlloc must have as many entries as specified by rowMap for this node.");
00204     for (size_t r=0; r < getNodeNumRows(); ++r) {
00205       const size_t curRowCount = NumEntriesPerRowToAlloc[r];
00206       TEUCHOS_TEST_FOR_EXCEPTION(curRowCount == OTST::invalid(),
00207         std::invalid_argument, "NumEntriesPerRowToAlloc[" << r << "] specifies "
00208         "an invalid number of entries (Teuchos::OrdinalTraits<size_t>::"
00209         "invalid()).");
00210     }
00211     resumeFill(params);
00212     checkInternalState();
00213   }
00214 
00215 
00218   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00219   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00220   CrsGraph (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &rowMap,
00221             const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > &colMap,
00222             const ArrayRCP<size_t> & rowPointers,
00223             const ArrayRCP<LocalOrdinal> & columnIndices,
00224             const RCP<ParameterList>& params)
00225   : DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>(rowMap)
00226   , rowMap_(rowMap)
00227   , colMap_(colMap)
00228   , nodeNumEntries_(0)
00229   , nodeNumAllocated_(OrdinalTraits<size_t>::invalid())
00230   , pftype_(StaticProfile)
00231   , numAllocForAllRows_(0)
00232   , indicesAreAllocated_(true)
00233   , indicesAreLocal_(true)
00234   , indicesAreGlobal_(false)
00235   , fillComplete_(false)
00236   , indicesAreSorted_(true)
00237   , noRedundancies_(true)
00238   , haveLocalConstants_ (false)
00239   , haveGlobalConstants_ (false)
00240   , sortGhostsAssociatedWithEachProcessor_(true)
00241   {
00242     staticAssertions();
00243     globalNumEntries_ = globalNumDiags_ = globalMaxNumRowEntries_ = OrdinalTraits<global_size_t>::invalid();
00244     setAllIndices(rowPointers,columnIndices);
00245     checkInternalState();
00246   }
00247 
00250   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00251   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::~CrsGraph()
00252   {}
00253 
00254   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00255   RCP<const ParameterList>
00256   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00257   getValidParameters () const
00258   {
00259     RCP<ParameterList> params = parameterList ("Tpetra::CrsGraph");
00260 
00261     // Make a sublist for the Import.
00262     RCP<ParameterList> importSublist = parameterList ("Import");
00263 
00264     // FIXME (mfh 02 Apr 2012) We should really have the Import and
00265     // Export objects fill in these lists.  However, we don't want to
00266     // create an Import or Export unless we need them.  For now, we
00267     // know that the Import and Export just pass the list directly to
00268     // their Distributor, so we can create a Distributor here
00269     // (Distributor's constructor is a lightweight operation) and have
00270     // it fill in the list.
00271 
00272     // Fill in Distributor default parameters by creating a
00273     // Distributor and asking it to do the work.
00274     Distributor distributor (rowMap_->getComm(), importSublist);
00275     params->set ("Import", *importSublist, "How the Import performs communication.");
00276 
00277     // Make a sublist for the Export.  For now, it's a clone of the
00278     // Import sublist.  It's not a shallow copy, though, since we
00279     // might like the Import to do communication differently than the
00280     // Export.
00281     params->set ("Export", *importSublist, "How the Export performs communication.");
00282 
00283     return params;
00284   }
00285 
00286   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00287   void
00288   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00289   setParameterList (const RCP<ParameterList>& params)
00290   {
00291     RCP<const ParameterList> validParams = getValidParameters ();
00292     params->validateParametersAndSetDefaults (*validParams);
00293     this->setMyParamList (params);
00294   }
00295 
00296   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00297   global_size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getGlobalNumRows() const
00298   {
00299     return rowMap_->getGlobalNumElements();
00300   }
00301 
00302   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00303   global_size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getGlobalNumCols() const
00304   {
00305     const char tfecfFuncName[] = "getGlobalNumCols()";
00306     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00307       isFillComplete() == false, std::runtime_error,
00308       ": requires domain map, which requires that fillComplete() has been "
00309       "called.");
00310     return getDomainMap()->getGlobalNumElements();
00311   }
00312 
00313   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00314   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeNumRows() const
00315   {
00316     return rowMap_->getNodeNumElements();
00317   }
00318 
00319   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00320   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeNumCols() const
00321   {
00322     const char tfecfFuncName[] = "getNodeNumCols()";
00323     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00324       hasColMap() == false, std::runtime_error,
00325       ": requires column map.  This requires either that a custom column Map "
00326       "was given to the constructor, or that fillComplete() has been called.");
00327     return colMap_->getNodeNumElements();
00328   }
00329 
00330   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00331   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeNumDiags() const
00332   {
00333     return nodeNumDiags_;
00334   }
00335 
00336   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00337   global_size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getGlobalNumDiags() const
00338   {
00339     return globalNumDiags_;
00340   }
00341 
00342   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00343   RCP<Node>
00344   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNode() const
00345   {
00346     return rowMap_->getNode();
00347   }
00348 
00349   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00350   RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00351   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getRowMap() const
00352   {
00353     return rowMap_;
00354   }
00355 
00356   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00357   RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00358   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getColMap() const
00359   {
00360     return colMap_;
00361   }
00362 
00363   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00364   RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00365   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getDomainMap() const
00366   {
00367     return domainMap_;
00368   }
00369 
00370   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00371   RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
00372   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getRangeMap() const
00373   {
00374     return rangeMap_;
00375   }
00376 
00377   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00378   RCP<const Import<LocalOrdinal,GlobalOrdinal,Node> >
00379   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getImporter() const
00380   {
00381     return importer_;
00382   }
00383 
00384   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00385   RCP<const Export<LocalOrdinal,GlobalOrdinal,Node> >
00386   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getExporter() const
00387   {
00388     return exporter_;
00389   }
00390 
00391   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00392   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::hasColMap() const
00393   {
00394     return (colMap_ != null);
00395   }
00396 
00397   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00398   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isStorageOptimized() const
00399   {
00400     bool isOpt = indicesAreAllocated_ && (numRowEntries_ == null) && (getNodeNumRows() > 0);
00401 #ifdef HAVE_TPETRA_DEBUG
00402     const char tfecfFuncName[] = "isStorageOptimized()";
00403     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( (isOpt == true) && (getProfileType() == DynamicProfile), std::logic_error,
00404         ": Violated stated post-conditions. Please contact Tpetra team.");
00405 #endif
00406     return isOpt;
00407   }
00408 
00409   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00410   ProfileType CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getProfileType() const
00411   {
00412     return pftype_;
00413   }
00414 
00415   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00416   global_size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getGlobalNumEntries() const
00417   {
00418     return globalNumEntries_;
00419   }
00420 
00421   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00422   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeNumEntries() const
00423   {
00424     return nodeNumEntries_;
00425   }
00426 
00427   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00428   global_size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getGlobalMaxNumRowEntries() const
00429   {
00430     return globalMaxNumRowEntries_;
00431   }
00432 
00433   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00434   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeMaxNumRowEntries() const
00435   {
00436     return nodeMaxNumRowEntries_;
00437   }
00438 
00439   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00440   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isFillComplete() const
00441   {
00442     return fillComplete_;
00443   }
00444 
00445   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00446   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isFillActive() const
00447   {
00448     return !fillComplete_;
00449   }
00450 
00451   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00452   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isUpperTriangular() const
00453   {
00454     return upperTriangular_;
00455   }
00456 
00457   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00458   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isLowerTriangular() const
00459   {
00460     return lowerTriangular_;
00461   }
00462 
00463   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00464   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isLocallyIndexed() const
00465   {
00466     return indicesAreLocal_;
00467   }
00468 
00469   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00470   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isGloballyIndexed() const
00471   {
00472     return indicesAreGlobal_;
00473   }
00474 
00475   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00476   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeAllocationSize() const
00477   {
00478     return nodeNumAllocated_;
00479   }
00480 
00481   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00482   RCP<const Comm<int> >
00483   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getComm() const
00484   {
00485     return rowMap_->getComm();
00486   }
00487 
00488   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00489   GlobalOrdinal CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getIndexBase() const
00490   {
00491     return rowMap_->getIndexBase();
00492   }
00493 
00494   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00495   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::indicesAreAllocated() const
00496   {
00497     return indicesAreAllocated_;
00498   }
00499 
00500 
00503   //                                                                         //
00504   //                    Internal utility methods                             //
00505   //                                                                         //
00508 
00509 
00512   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00513   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isSorted() const
00514   {
00515     return indicesAreSorted_;
00516   }
00517 
00518 
00521   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00522   bool CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::isMerged() const
00523   {
00524     return noRedundancies_;
00525   }
00526 
00529   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00530   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::setLocallyModified ()
00531   {
00532     // FIXME (mfh 07 May 2013) How do we know that the change
00533     // introduced a redundancy, or even that it invalidated the sorted
00534     // order of indices?  CrsGraph has always made this conservative
00535     // guess.  It could be a bit costly to check at insertion time,
00536     // though.
00537     indicesAreSorted_ = false;
00538     noRedundancies_ = false;
00539 
00540     // We've modified the graph, so we'll have to recompute local
00541     // constants like the number of diagonal entries on this process.
00542     haveLocalConstants_ = false;
00543   }
00544 
00547   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00548   void
00549   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00550   allocateIndices (ELocalGlobal lg)
00551   {
00552     // This is a protected function, only callable by us.  If it was
00553     // called incorrectly, it is our fault.  That's why the tests
00554     // below throw std::logic_error instead of std::invalid_argument.
00555     const char tfecfFuncName[] = "allocateIndices: ";
00556     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00557       isLocallyIndexed () && lg == GlobalIndices, std::logic_error,
00558       "The graph is locally indexed, but Tpetra code is calling this method "
00559       "with lg=GlobalIndices.  Please report this bug to the Tpetra developers.");
00560     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00561       isGloballyIndexed () && lg == LocalIndices, std::logic_error,
00562       "The graph is globally indexed, but Tpetra code is calling this method "
00563       "with lg=LocalIndices.  Please report this bug to the Tpetra developers.");
00564     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00565       indicesAreAllocated (), std::logic_error, "The graph's indices are "
00566       "already allocated, but Tpetra code is calling allocateIndices() again.  "
00567       "Please report this bug to the Tpetra developers.");
00568 
00569     const size_t numRows = getNodeNumRows();
00570     indicesAreLocal_  = (lg == LocalIndices);
00571     indicesAreGlobal_ = (lg == GlobalIndices);
00572     nodeNumAllocated_ = 0;
00573     if (numAllocPerRow_ == null && getNodeNumRows() > 0) {
00574       // this wastes memory, temporarily, but it simplifies the code
00575       // and interfaces to follow
00576       ArrayRCP<size_t> tmpnumallocperrow = arcp<size_t>(numRows);
00577       std::fill(tmpnumallocperrow.begin(), tmpnumallocperrow.end(), numAllocForAllRows_);
00578       numAllocPerRow_ = tmpnumallocperrow;
00579     }
00580     //
00581     if (getProfileType() == StaticProfile) {
00582       //
00583       //  STATIC ALLOCATION PROFILE
00584       //
00585       // Have the local sparse kernels object allocate row offsets for
00586       // us, with first-touch allocation if applicable.  This is not
00587       // as important for global indices, because we never use global
00588       // indices in sparse kernels, but we might as well use the code
00589       // that we have for both the local and global indices cases.
00590       // Furthermore, first-touch allocation ensures that we don't
00591       // take up too much memory in any one NUMA affinity region.
00592       rowPtrs_ = sparse_ops_type::allocRowPtrs( getRowMap()->getNode(), numAllocPerRow_() );
00593       if (lg == LocalIndices) {
00594         lclInds1D_ = sparse_ops_type::template allocStorage<LocalOrdinal>( getRowMap()->getNode(), rowPtrs_() );
00595       }
00596       else {
00597         gblInds1D_ = sparse_ops_type::template allocStorage<GlobalOrdinal>( getRowMap()->getNode(), rowPtrs_() );
00598       }
00599       nodeNumAllocated_ = rowPtrs_[numRows];
00600     }
00601     else {
00602       //
00603       //  DYNAMIC ALLOCATION PROFILE
00604       //
00605       typename ArrayRCP<const size_t>::iterator numalloc = numAllocPerRow_.begin();
00606       size_t howmany = numAllocForAllRows_;
00607       if (lg == LocalIndices) {
00608         lclInds2D_ = arcp< Array<LocalOrdinal> >(numRows);
00609         nodeNumAllocated_ = 0;
00610         for (size_t i=0; i < numRows; ++i) {
00611           if (numAllocPerRow_ != null) howmany = *numalloc++;
00612           nodeNumAllocated_ += howmany;
00613           if (howmany > 0) lclInds2D_[i].resize(howmany);
00614         }
00615       }
00616       else { // allocate global indices
00617         gblInds2D_ = arcp< Array<GlobalOrdinal> >(numRows);
00618         nodeNumAllocated_ = 0;
00619         for (size_t i=0; i < numRows; ++i) {
00620           if (numAllocPerRow_ != null) howmany = *numalloc++;
00621           nodeNumAllocated_ += howmany;
00622           if (howmany > 0) gblInds2D_[i].resize(howmany);
00623         }
00624       }
00625     }
00626     if (numRows > 0) {
00627       numRowEntries_ = arcp<size_t>(numRows);
00628       std::fill( numRowEntries_.begin(), numRowEntries_.end(), 0 );
00629     }
00630     // done with these
00631     numAllocForAllRows_ = 0;
00632     numAllocPerRow_     = null;
00633     indicesAreAllocated_ = true;
00634     checkInternalState();
00635   }
00636 
00637 
00640   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00641   template <class T>
00642   ArrayRCP<T> CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::allocateValues1D() const
00643   {
00644     const char tfecfFuncName[] = "allocateValues()";
00645     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00646         indicesAreAllocated() == false,
00647         std::runtime_error, ": graph indices must be allocated before values."
00648     );
00649     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00650         getProfileType() != StaticProfile,
00651         std::runtime_error, ": graph indices must be allocated in a static profile."
00652     );
00653     ArrayRCP<T> values1D;
00654     values1D = sparse_ops_type::template allocStorage<T>( getRowMap()->getNode(), rowPtrs_() );
00655     return values1D;
00656   }
00657 
00658 
00661   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00662   template <class T>
00663   ArrayRCP<Array<T> >
00664   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::allocateValues2D() const
00665   {
00666     const char tfecfFuncName[] = "allocateValues2D()";
00667     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00668         indicesAreAllocated() == false,
00669         std::runtime_error, ": graph indices must be allocated before values."
00670     );
00671     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00672         getProfileType() != DynamicProfile,
00673         std::runtime_error, ": graph indices must be allocated in a dynamic profile."
00674     );
00675     ArrayRCP<Array<T> > values2D;
00676     values2D = arcp<Array<T> > (getNodeNumRows ());
00677     if (lclInds2D_ != null) {
00678       const size_t numRows = lclInds2D_.size ();
00679       for (size_t r = 0; r < numRows; ++r) {
00680         values2D[r].resize (lclInds2D_[r].size ());
00681       }
00682     }
00683     else if (gblInds2D_ != null) {
00684       const size_t numRows = gblInds2D_.size ();
00685       for (size_t r = 0; r < numRows; ++r) {
00686         values2D[r].resize (gblInds2D_[r].size ());
00687       }
00688     }
00689     return values2D;
00690   }
00691 
00692 
00693 //   /////////////////////////////////////////////////////////////////////////////
00694 //   /////////////////////////////////////////////////////////////////////////////
00695 //   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00696 //   template <ELocalGlobal lg, class T>
00697 //   RowInfo
00698 //   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00699 //   updateAllocAndValues (RowInfo rowinfo,
00700 //                         size_t newAllocSize,
00701 //                         Array<T>& rowVals)
00702 //   {
00703 // #ifdef HAVE_TPETRA_DEBUG
00704 //     TEUCHOS_TEST_FOR_EXCEPT( ! rowMap_->isNodeLocalElement(rowinfo.localRow) );
00705 //     TEUCHOS_TEST_FOR_EXCEPT( newAllocSize < rowinfo.allocSize );
00706 //     TEUCHOS_TEST_FOR_EXCEPT( (lg == LocalIndices && ! isLocallyIndexed()) ||
00707 //                              (lg == GlobalIndices && ! isGloballyIndexed()) );
00708 //     TEUCHOS_TEST_FOR_EXCEPT( newAllocSize == 0 );
00709 //     TEUCHOS_TEST_FOR_EXCEPT( ! indicesAreAllocated() );
00710 // #endif
00711 //     // ArrayRCP::resize automatically copies over values on reallocation.
00712 //     if (lg == LocalIndices) {
00713 //       lclInds2D_[rowinfo.localRow].resize (newAllocSize);
00714 //     }
00715 //     else { // lg == GlobalIndices
00716 //       gblInds2D_[rowinfo.localRow].resize (newAllocSize);
00717 //     }
00718 //     rowVals.resize (newAllocSize);
00719 //     nodeNumAllocated_ += (newAllocSize - rowinfo.allocSize);
00720 //     rowinfo.allocSize = newAllocSize;
00721 //     return rowinfo;
00722 //   }
00723 
00724 
00727   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00728   ArrayView<const LocalOrdinal>
00729   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00730   getLocalView (RowInfo rowinfo) const
00731   {
00732     ArrayView<const LocalOrdinal> view;
00733     if (rowinfo.allocSize > 0) {
00734       if (lclInds1D_ != null) {
00735         view = lclInds1D_ (rowinfo.offset1D, rowinfo.allocSize);
00736       }
00737       else if (! lclInds2D_[rowinfo.localRow].empty ()) {
00738         view = lclInds2D_[rowinfo.localRow] ();
00739       }
00740     }
00741     return view;
00742   }
00743 
00744 
00747   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00748   ArrayView<LocalOrdinal>
00749   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00750   getLocalViewNonConst (RowInfo rowinfo)
00751   {
00752     ArrayView<LocalOrdinal> view;
00753     if (rowinfo.allocSize > 0) {
00754       if (lclInds1D_ != null) {
00755         view = lclInds1D_ (rowinfo.offset1D, rowinfo.allocSize);
00756       }
00757       else if (! lclInds2D_[rowinfo.localRow].empty()) {
00758         view = lclInds2D_[rowinfo.localRow] ();
00759       }
00760     }
00761     return view;
00762   }
00763 
00764 
00767   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00768   ArrayView<const GlobalOrdinal>
00769   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00770   getGlobalView (RowInfo rowinfo) const
00771   {
00772     ArrayView<const GlobalOrdinal> view;
00773     if (rowinfo.allocSize > 0) {
00774       if (gblInds1D_ != null) {
00775         view = gblInds1D_ (rowinfo.offset1D, rowinfo.allocSize);
00776       }
00777       else if (! gblInds2D_[rowinfo.localRow].empty()) {
00778         view = gblInds2D_[rowinfo.localRow] ();
00779       }
00780     }
00781     return view;
00782   }
00783 
00784 
00787   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00788   ArrayView<GlobalOrdinal>
00789   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00790   getGlobalViewNonConst (RowInfo rowinfo)
00791   {
00792     ArrayView<GlobalOrdinal> view;
00793     if (rowinfo.allocSize > 0) {
00794       if (gblInds1D_ != null) {
00795         view = gblInds1D_ (rowinfo.offset1D, rowinfo.allocSize);
00796       }
00797       else if (!gblInds2D_[rowinfo.localRow].empty()) {
00798         view = gblInds2D_[rowinfo.localRow] ();
00799       }
00800     }
00801     return view;
00802   }
00803 
00804 
00807   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00808   RowInfo CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getRowInfo(size_t myRow) const
00809   {
00810 #ifdef HAVE_TPETRA_DEBUG
00811     const char tfecfFuncName[] = "getRowInfo";
00812     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00813         rowMap_->isNodeLocalElement (myRow) == false,
00814         std::logic_error,
00815         ": The given (local) row index myRow = " << myRow
00816         << " does not belong to the graph's row Map.  "
00817         "This probably indicates a bug in Tpetra::CrsGraph or Tpetra::CrsMatrix.  "
00818         "Please report this to the Tpetra developers.");
00819     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
00820       hasRowInfo() == false, std::logic_error,
00821       ": Late catch! Graph does not have row info anymore.  "
00822       "Error should have been caught earlier.  Please contact Tpetra team.");
00823 #endif // HAVE_TPETRA_DEBUG
00824     const size_t STINV = Teuchos::OrdinalTraits<size_t>::invalid ();
00825     RowInfo ret;
00826     ret.localRow = myRow;
00827     if (nodeNumAllocated_ != 0 && nodeNumAllocated_ != STINV) {
00828       // graph data structures have the info that we need
00829       //
00830       // if static graph, offsets tell us the allocation size
00831       if (getProfileType() == StaticProfile) {
00832         ret.offset1D  = rowPtrs_[myRow];
00833         ret.allocSize = rowPtrs_[myRow+1] - rowPtrs_[myRow];
00834         if (numRowEntries_ == null) {
00835           ret.numEntries = ret.allocSize;
00836         }
00837         else {
00838           ret.numEntries = numRowEntries_[myRow];
00839         }
00840       }
00841       else {
00842         ret.offset1D = STINV;
00843         if (isLocallyIndexed ()) {
00844           ret.allocSize = lclInds2D_[myRow].size();
00845         }
00846         else {
00847           ret.allocSize = gblInds2D_[myRow].size();
00848         }
00849         ret.numEntries = numRowEntries_[myRow];
00850       }
00851     }
00852     else if (nodeNumAllocated_ == 0) {
00853       // have performed allocation, but the graph has no allocation or entries
00854       ret.allocSize = 0;
00855       ret.numEntries = 0;
00856       ret.offset1D = STINV;
00857     }
00858     else if (indicesAreAllocated () == false) {
00859       // haven't performed allocation yet; probably won't hit this code
00860       if (numAllocPerRow_ == null) {
00861         ret.allocSize = numAllocForAllRows_;
00862       }
00863       else {
00864         ret.allocSize = numAllocPerRow_[myRow];
00865       }
00866       ret.numEntries = 0;
00867       ret.offset1D = STINV;
00868     }
00869     else {
00870       // don't know how we ended up here...
00871       TEUCHOS_TEST_FOR_EXCEPT(true);
00872     }
00873     return ret;
00874   }
00875 
00876 
00879   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00880   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::staticAssertions() const
00881   {
00882     // Assumption: sizeof(GlobalOrdinal) >= sizeof(LocalOrdinal):
00883     //     This is so that we can store local indices in the memory
00884     //     formerly occupied by global indices.
00885     //
00886     // Assumption: max(GlobalOrdinal) >= max(LocalOrdinal) and
00887     //   max(size_t) >= max(LocalOrdinal)
00888     //     This is so that we can represent any LocalOrdinal as a
00889     //     size_t, and any LocalOrdinal as a GlobalOrdinal
00890     Teuchos::CompileTimeAssert<sizeof(GlobalOrdinal) < sizeof(LocalOrdinal)> cta_size1; (void)cta_size1;
00891     Teuchos::CompileTimeAssert<sizeof(global_size_t) < sizeof(size_t)      > cta_size2; (void)cta_size2;
00892     // can't call max() with CompileTimeAssert, because it isn't a constant expression; will need to make this a runtime check
00893     std::string msg = typeName(*this) + ": Object cannot be allocated with stated template arguments: size assumptions are not valid.";
00894     TEUCHOS_TEST_FOR_EXCEPTION( (size_t)OrdinalTraits<LocalOrdinal>::max() > OrdinalTraits<size_t>::max(),          std::runtime_error, msg);
00895     TEUCHOS_TEST_FOR_EXCEPTION( (global_size_t)OrdinalTraits<LocalOrdinal>::max() > (global_size_t)OrdinalTraits<GlobalOrdinal>::max(),           std::runtime_error, msg);
00896     TEUCHOS_TEST_FOR_EXCEPTION( (size_t)OrdinalTraits<GlobalOrdinal>::max() > OrdinalTraits<global_size_t>::max(),  std::runtime_error, msg);
00897     TEUCHOS_TEST_FOR_EXCEPTION( OrdinalTraits<size_t>::max() > OrdinalTraits<global_size_t>::max(),                 std::runtime_error, msg);
00898   }
00899 
00900 
00903   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00904   template <ELocalGlobal lg>
00905   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::filterIndices(const SLocalGlobalNCViews &inds) const
00906   {
00907     const map_type& cmap = *colMap_;
00908     Teuchos::CompileTimeAssert<lg != GlobalIndices && lg != LocalIndices> cta_lg;
00909     (void)cta_lg;
00910     size_t numFiltered = 0;
00911 #ifdef HAVE_TPETRA_DEBUG
00912     size_t numFiltered_debug = 0;
00913 #endif
00914     if (lg == GlobalIndices) {
00915       ArrayView<GlobalOrdinal> ginds = inds.ginds;
00916       typename ArrayView<GlobalOrdinal>::iterator fend = ginds.begin();
00917       typename ArrayView<GlobalOrdinal>::iterator cptr = ginds.begin();
00918       while (cptr != ginds.end()) {
00919         if (cmap.isNodeGlobalElement(*cptr)) {
00920           *fend++ = *cptr;
00921 #ifdef HAVE_TPETRA_DEBUG
00922           ++numFiltered_debug;
00923 #endif
00924         }
00925         ++cptr;
00926       }
00927       numFiltered = fend - ginds.begin();
00928     }
00929     else if (lg == LocalIndices) {
00930       ArrayView<LocalOrdinal> linds = inds.linds;
00931       typename ArrayView<LocalOrdinal>::iterator fend = linds.begin();
00932       typename ArrayView<LocalOrdinal>::iterator cptr = linds.begin();
00933       while (cptr != linds.end()) {
00934         if (cmap.isNodeLocalElement(*cptr)) {
00935           *fend++ = *cptr;
00936 #ifdef HAVE_TPETRA_DEBUG
00937           ++numFiltered_debug;
00938 #endif
00939         }
00940         ++cptr;
00941       }
00942       numFiltered = fend - linds.begin();
00943     }
00944 #ifdef HAVE_TPETRA_DEBUG
00945     TEUCHOS_TEST_FOR_EXCEPT( numFiltered != numFiltered_debug );
00946 #endif
00947     return numFiltered;
00948   }
00949 
00950 
00951 //   /////////////////////////////////////////////////////////////////////////////
00952 //   /////////////////////////////////////////////////////////////////////////////
00953 //   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00954 //   template <class T>
00955 //   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00956 //   filterGlobalIndicesAndValues (const ArrayView<GlobalOrdinal>& ginds,
00957 //                                 const ArrayView<T>& vals) const
00958 //   {
00959 //     const Map<LocalOrdinal,GlobalOrdinal,Node>& cmap = *colMap_;
00960 //     size_t numFiltered = 0;
00961 //     typename ArrayView<T>::iterator fvalsend = vals.begin();
00962 //     typename ArrayView<T>::iterator valscptr = vals.begin();
00963 // #ifdef HAVE_TPETRA_DEBUG
00964 //     size_t numFiltered_debug = 0;
00965 // #endif
00966 //     typename ArrayView<GlobalOrdinal>::iterator fend = ginds.begin();
00967 //     typename ArrayView<GlobalOrdinal>::iterator cptr = ginds.begin();
00968 //     while (cptr != ginds.end()) {
00969 //       if (cmap.isNodeGlobalElement (*cptr)) {
00970 //         *fend++ = *cptr;
00971 //         *fvalsend++ = *valscptr;
00972 // #ifdef HAVE_TPETRA_DEBUG
00973 //         ++numFiltered_debug;
00974 // #endif
00975 //       }
00976 //       ++cptr;
00977 //       ++valscptr;
00978 //     }
00979 //     numFiltered = fend - ginds.begin();
00980 // #ifdef HAVE_TPETRA_DEBUG
00981 //     TEUCHOS_TEST_FOR_EXCEPT( numFiltered != numFiltered_debug );
00982 //     TEUCHOS_TEST_FOR_EXCEPT( valscptr != vals.end() );
00983 //     const size_t numFilteredActual =
00984 //       Teuchos::as<size_t> (fvalsend - vals.begin ());
00985 //     TEUCHOS_TEST_FOR_EXCEPT( numFiltered != numFilteredActual );
00986 // #endif
00987 //     return numFiltered;
00988 //   }
00989 
00990 
00991 //   /////////////////////////////////////////////////////////////////////////////
00992 //   /////////////////////////////////////////////////////////////////////////////
00993 //   template <class LocalOrdinal, class GlobalOrdinal, class Node>
00994 //   template <class T>
00995 //   size_t
00996 //   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
00997 //   filterLocalIndicesAndValues (const ArrayView<LocalOrdinal>& linds,
00998 //                                const ArrayView<T>& vals) const
00999 //   {
01000 //     const Map<LocalOrdinal,GlobalOrdinal,Node>& cmap = *colMap_;
01001 //     size_t numFiltered = 0;
01002 //     typename ArrayView<T>::iterator fvalsend = vals.begin();
01003 //     typename ArrayView<T>::iterator valscptr = vals.begin();
01004 // #ifdef HAVE_TPETRA_DEBUG
01005 //     size_t numFiltered_debug = 0;
01006 // #endif
01007 //     typename ArrayView<LocalOrdinal>::iterator fend = linds.begin();
01008 //     typename ArrayView<LocalOrdinal>::iterator cptr = linds.begin();
01009 //     while (cptr != linds.end()) {
01010 //       if (cmap.isNodeLocalElement (*cptr)) {
01011 //         *fend++ = *cptr;
01012 //         *fvalsend++ = *valscptr;
01013 // #ifdef HAVE_TPETRA_DEBUG
01014 //         ++numFiltered_debug;
01015 // #endif
01016 //       }
01017 //       ++cptr;
01018 //       ++valscptr;
01019 //     }
01020 //     numFiltered = fend - linds.begin();
01021 // #ifdef HAVE_TPETRA_DEBUG
01022 //     TEUCHOS_TEST_FOR_EXCEPT( numFiltered != numFiltered_debug );
01023 //     TEUCHOS_TEST_FOR_EXCEPT( valscptr != vals.end() );
01024 //     const size_t numFilteredActual =
01025 //       Teuchos::as<size_t> (fvalsend - vals.begin ());
01026 //     TEUCHOS_TEST_FOR_EXCEPT( numFiltered != numFilteredActual );
01027 // #endif
01028 //     return numFiltered;
01029 //   }
01030 
01031 
01034   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01035   size_t
01036   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01037   insertIndices (const RowInfo& rowinfo,
01038                  const SLocalGlobalViews &newInds,
01039                  const ELocalGlobal lg,
01040                  const ELocalGlobal I)
01041   {
01042 #ifdef HAVE_TPETRA_DEBUG
01043     TEUCHOS_TEST_FOR_EXCEPTION(
01044       lg != GlobalIndices && lg != LocalIndices, std::invalid_argument,
01045       "Tpetra::CrsGraph::insertIndices: lg must be either GlobalIndices or "
01046       "LocalIndices.");
01047 #endif // HAVE_TPETRA_DEBUG
01048     size_t numNewInds = 0;
01049     if (lg == GlobalIndices) { // input indices are global
01050       ArrayView<const GlobalOrdinal> new_ginds = newInds.ginds;
01051       numNewInds = new_ginds.size();
01052       if (I == GlobalIndices) { // store global indices
01053         ArrayView<GlobalOrdinal> gind_view = getGlobalViewNonConst(rowinfo);
01054         std::copy(new_ginds.begin(), new_ginds.end(), gind_view.begin()+rowinfo.numEntries);
01055       }
01056       else if (I == LocalIndices) { // store local indices
01057         ArrayView<LocalOrdinal> lind_view = getLocalViewNonConst(rowinfo);
01058         typename ArrayView<const GlobalOrdinal>::iterator         in = new_ginds.begin();
01059         const typename ArrayView<const GlobalOrdinal>::iterator stop = new_ginds.end();
01060         typename ArrayView<LocalOrdinal>::iterator out = lind_view.begin()+rowinfo.numEntries;
01061         while (in != stop) {
01062           *out++ = colMap_->getLocalElement (*in++);
01063         }
01064       }
01065     }
01066     else if (lg == LocalIndices) { // input indices are local
01067       ArrayView<const LocalOrdinal> new_linds = newInds.linds;
01068       numNewInds = new_linds.size();
01069       if (I == LocalIndices) { // store local indices
01070         ArrayView<LocalOrdinal> lind_view = getLocalViewNonConst(rowinfo);
01071         std::copy(new_linds.begin(), new_linds.end(), lind_view.begin()+rowinfo.numEntries);
01072       }
01073       else if (I == GlobalIndices) {
01074         TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Tpetra::CrsGraph::"
01075           "insertIndices: the case where the input indices are local and the "
01076           "indices to write are global (lg=LocalIndices, I=GlobalIndices) is "
01077           "not implemented, because it does not make sense." << std::endl <<
01078           "If you have correct local column indices, that means the graph has "
01079           "a column Map.  In that case, you should be storing local indices.");
01080       }
01081     }
01082     numRowEntries_[rowinfo.localRow] += numNewInds;
01083     nodeNumEntries_ += numNewInds;
01084     setLocallyModified ();
01085     return numNewInds;
01086   }
01087 
01090   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01091   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01092   insertGlobalIndicesImpl (const LocalOrdinal myRow,
01093                            const ArrayView<const GlobalOrdinal> &indices)
01094   {
01095     const char* tfecfFuncName ("insertGlobalIndicesImpl");
01096 
01097     RowInfo rowInfo = getRowInfo(myRow);
01098     const size_t numNewInds = indices.size();
01099     const size_t newNumEntries = rowInfo.numEntries + numNewInds;
01100     if (newNumEntries > rowInfo.allocSize) {
01101       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01102         getProfileType() == StaticProfile, std::runtime_error,
01103         ": new indices exceed statically allocated graph structure.");
01104 
01105       // update allocation, doubling size to reduce number of reallocations
01106       size_t newAllocSize = 2*rowInfo.allocSize;
01107       if (newAllocSize < newNumEntries)
01108         newAllocSize = newNumEntries;
01109       gblInds2D_[myRow].resize(newAllocSize);
01110       nodeNumAllocated_ += (newAllocSize - rowInfo.allocSize);
01111     }
01112 
01113     // Copy new indices at end of global index array
01114     if (gblInds1D_ != null)
01115       std::copy(indices.begin(), indices.end(),
01116                 gblInds1D_.begin()+rowInfo.offset1D+rowInfo.numEntries);
01117     else
01118       std::copy(indices.begin(), indices.end(),
01119                 gblInds2D_[myRow].begin()+rowInfo.numEntries);
01120     numRowEntries_[myRow] += numNewInds;
01121     nodeNumEntries_ += numNewInds;
01122     setLocallyModified ();
01123 
01124 #ifdef HAVE_TPETRA_DEBUG
01125     {
01126       const size_t chkNewNumEntries = getNumEntriesInLocalRow (myRow);
01127       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01128         chkNewNumEntries != newNumEntries, std::logic_error,
01129         ": Internal logic error. Please contact Tpetra team.");
01130     }
01131 #endif
01132   }
01133 
01136   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01137   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01138   insertLocalIndicesImpl (const LocalOrdinal myRow,
01139                           const ArrayView<const LocalOrdinal> &indices)
01140   {
01141     const char* tfecfFuncName ("insertLocallIndicesImpl");
01142 
01143     RowInfo rowInfo = getRowInfo(myRow);
01144     const size_t numNewInds = indices.size();
01145     const size_t newNumEntries = rowInfo.numEntries + numNewInds;
01146     if (newNumEntries > rowInfo.allocSize) {
01147       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01148         getProfileType() == StaticProfile, std::runtime_error,
01149         ": new indices exceed statically allocated graph structure.");
01150 
01151       // update allocation, doubling size to reduce number of reallocations
01152       size_t newAllocSize = 2*rowInfo.allocSize;
01153       if (newAllocSize < newNumEntries)
01154         newAllocSize = newNumEntries;
01155       lclInds2D_[myRow].resize(newAllocSize);
01156       nodeNumAllocated_ += (newAllocSize - rowInfo.allocSize);
01157     }
01158 
01159     // Insert new indices at end of lclInds array
01160     if (lclInds1D_ != null)
01161       std::copy(indices.begin(), indices.end(),
01162                 lclInds1D_.begin()+rowInfo.offset1D+rowInfo.numEntries);
01163     else
01164       std::copy(indices.begin(), indices.end(),
01165                 lclInds2D_[myRow].begin()+rowInfo.numEntries);
01166     numRowEntries_[myRow] += numNewInds;
01167     nodeNumEntries_ += numNewInds;
01168     setLocallyModified ();
01169 #ifdef HAVE_TPETRA_DEBUG
01170     {
01171       const size_t chkNewNumEntries = getNumEntriesInLocalRow (myRow);
01172       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01173         chkNewNumEntries != newNumEntries, std::logic_error,
01174         ": Internal logic error. Please contact Tpetra team.");
01175     }
01176 #endif
01177   }
01178 
01179   // /////////////////////////////////////////////////////////////////////////////
01180   // /////////////////////////////////////////////////////////////////////////////
01181   // template <class LocalOrdinal, class GlobalOrdinal, class Node>
01182   // template <class Scalar>
01183   // void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01184   // insertIndicesAndValues (const RowInfo& rowInfo,
01185   //                         const SLocalGlobalViews& newInds,
01186   //                         const ArrayView<Scalar>& oldRowVals,
01187   //                         const ArrayView<const Scalar>& newRowVals,
01188   //                         const ELocalGlobal lg,
01189   //                         const ELocalGlobal I)
01190   // {
01191   //   const size_t numNewInds = insertIndices (rowInfo, newInds, lg, I);
01192   //   typename ArrayView<const Scalar>::const_iterator newRowValsBegin =
01193   //     newRowVals.begin ();
01194   //   std::copy (newRowValsBegin, newRowValsBegin + numNewInds,
01195   //              oldRowVals.begin () + rowInfo.numEntries);
01196   // }
01197 
01198   // /////////////////////////////////////////////////////////////////////////////
01199   // /////////////////////////////////////////////////////////////////////////////
01200   // template <class LocalOrdinal, class GlobalOrdinal, class Node>
01201   // template <class Scalar, class BinaryFunction>
01202   // void
01203   // CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01204   // transformLocalValues (RowInfo rowInfo,
01205   //                       const Teuchos::ArrayView<Scalar>& rowVals,
01206   //                       const Teuchos::ArrayView<const LocalOrdinal>& inds,
01207   //                       const Teuchos::ArrayView<const Scalar>& newVals,
01208   //                       BinaryFunction f) const
01209   // {
01210   //   const size_t STINV = Teuchos::OrdinalTraits<size_t>::invalid();
01211   //   const size_t numElts = Teuchos::as<size_t> (inds.size ());
01212   //   size_t hint = 0; // Guess for the current index k into rowVals
01213 
01214   //   // Get a view of the column indices in the row.  This amortizes
01215   //   // the cost of getting the view over all the entries of inds.
01216   //   ArrayView<const LocalOrdinal> colInds = getLocalView (rowInfo);
01217 
01218   //   for (size_t j = 0; j < numElts; ++j) {
01219   //     const size_t k = findLocalIndex (rowInfo, inds[j], colInds, hint);
01220   //     if (k != STINV) {
01221   //       rowVals[k] = f( rowVals[k], newVals[j] );
01222   //       hint = k+1;
01223   //     }
01224   //   }
01225   // }
01226 
01227 
01228   // /////////////////////////////////////////////////////////////////////////////
01229   // /////////////////////////////////////////////////////////////////////////////
01230   // template <class LocalOrdinal, class GlobalOrdinal, class Node>
01231   // template <class Scalar, class BinaryFunction>
01232   // void
01233   // CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01234   // transformGlobalValues (RowInfo rowInfo,
01235   //                        const Teuchos::ArrayView<Scalar>& rowVals,
01236   //                        const Teuchos::ArrayView<const GlobalOrdinal>& inds,
01237   //                        const Teuchos::ArrayView<const Scalar>& newVals,
01238   //                        BinaryFunction f) const
01239   // {
01240   //   const size_t STINV = Teuchos::OrdinalTraits<size_t>::invalid();
01241   //   const size_t numElts = Teuchos::as<size_t> (inds.size ());
01242   //   size_t hint = 0; // hint is a guess as to wheter the index is
01243 
01244   //   for (size_t j = 0; j < numElts; ++j) {
01245   //     const size_t k = findGlobalIndex (rowInfo, inds[j], hint);
01246   //     if (k != STINV) {
01247   //       rowVals[k] = f( rowVals[k], newVals[j] );
01248   //       hint = k+1;
01249   //     }
01250   //   }
01251   // }
01252 
01253   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01254   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01255   sortRowIndices (RowInfo rowinfo)
01256   {
01257     if (rowinfo.numEntries > 0) {
01258       Teuchos::ArrayView<LocalOrdinal> inds_view =
01259         this->getLocalViewNonConst (rowinfo);
01260       std::sort (inds_view.begin (), inds_view.begin () + rowinfo.numEntries);
01261     }
01262   }
01263 
01264   // in the future, perhaps this could use std::sort with a boost::zip_iterator
01265   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01266   template <class Scalar>
01267   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01268   sortRowIndicesAndValues (const RowInfo rowinfo,
01269                            const Teuchos::ArrayView<Scalar>& values)
01270   {
01271     if (rowinfo.numEntries > 0) {
01272       Teuchos::ArrayView<LocalOrdinal> indsView =
01273         this->getLocalViewNonConst (rowinfo);
01274       sort2 (indsView.begin (), indsView.begin () + rowinfo.numEntries,
01275              values.begin ());
01276     }
01277   }
01278 
01279   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01280   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01281   mergeRowIndices (RowInfo rowinfo)
01282   {
01283     using Teuchos::ArrayView;
01284     const char tfecfFuncName[] = "mergeRowIndices: ";
01285     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01286       isStorageOptimized (), std::logic_error, "The graph is already storage "
01287       "optimized, so we shouldn't be merging any indices.  "
01288       "Please report this bug to the Tpetra developers.");
01289 
01290     ArrayView<LocalOrdinal> inds_view = getLocalViewNonConst(rowinfo);
01291     typename ArrayView<LocalOrdinal>::iterator beg, end, newend;
01292     beg = inds_view.begin();
01293     end = inds_view.begin() + rowinfo.numEntries;
01294     newend = std::unique(beg,end);
01295     const size_t mergedEntries = newend - beg;
01296 #ifdef HAVE_TPETRA_DEBUG
01297     // merge should not have eliminated any entries; if so, the
01298     // assignment below will destroy the packed structure
01299     TEUCHOS_TEST_FOR_EXCEPT( isStorageOptimized() && mergedEntries != rowinfo.numEntries );
01300 #endif
01301     numRowEntries_[rowinfo.localRow] = mergedEntries;
01302     nodeNumEntries_ -= (rowinfo.numEntries - mergedEntries);
01303   }
01304 
01305   // in the future, this could use std::unique with a boost::zip_iterator
01306   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01307   template<class Scalar>
01308   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01309   mergeRowIndicesAndValues (RowInfo rowinfo, const ArrayView<Scalar>& rowValues)
01310   {
01311     const char tfecfFuncName[] = "mergeRowIndicesAndValues";
01312     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01313       isStorageOptimized(), std::logic_error, ": It is invalid to call this "
01314       "method if the graph's storage has already been optimized." << std::endl
01315       << "Please report this bug to the Tpetra developers.");
01316 
01317     typedef typename ArrayView<Scalar>::iterator Iter;
01318     Iter rowValueIter = rowValues.begin ();
01319     ArrayView<LocalOrdinal> inds_view = getLocalViewNonConst (rowinfo);
01320     typename ArrayView<LocalOrdinal>::iterator beg, end, newend;
01321 
01322     // beg,end define a half-exclusive interval over which to iterate.
01323     beg = inds_view.begin();
01324     end = inds_view.begin() + rowinfo.numEntries;
01325     newend = beg;
01326     if (beg != end) {
01327       typename ArrayView<LocalOrdinal>::iterator cur = beg + 1;
01328       Iter vcur = rowValueIter + 1;
01329       Iter vend = rowValueIter;
01330       cur = beg+1;
01331       while (cur != end) {
01332         if (*cur != *newend) {
01333           // new entry; save it
01334           ++newend;
01335           ++vend;
01336           (*newend) = (*cur);
01337           (*vend) = (*vcur);
01338         }
01339         else {
01340           // old entry; merge it
01341           //(*vend) = f (*vend, *vcur);
01342           (*vend) += *vcur;
01343         }
01344         ++cur;
01345         ++vcur;
01346       }
01347       ++newend; // one past the last entry, per typical [beg,end) semantics
01348     }
01349     const size_t mergedEntries = newend - beg;
01350 #ifdef HAVE_TPETRA_DEBUG
01351     // merge should not have eliminated any entries; if so, the
01352     // assignment below will destroy the packed structure
01353     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01354       isStorageOptimized() && mergedEntries != rowinfo.numEntries,
01355       std::logic_error,
01356       ": Merge was incorrect; it eliminated entries from the graph.  "
01357       << std::endl << "Please report this bug to the Tpetra developers.");
01358 #endif // HAVE_TPETRA_DEBUG
01359     numRowEntries_[rowinfo.localRow] = mergedEntries;
01360     nodeNumEntries_ -= (rowinfo.numEntries - mergedEntries);
01361   }
01362 
01363 
01366   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01367   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01368   setDomainRangeMaps (const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& domainMap,
01369                       const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >& rangeMap)
01370   {
01371     // simple pointer comparison for equality
01372     if (domainMap_ != domainMap) {
01373       domainMap_ = domainMap;
01374       importer_ = null;
01375     }
01376     if (rangeMap_ != rangeMap) {
01377       rangeMap_  = rangeMap;
01378       exporter_ = null;
01379     }
01380   }
01381 
01382 
01385   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01386   size_t
01387   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01388   findLocalIndex (RowInfo rowinfo, LocalOrdinal ind, size_t hint) const
01389   {
01390     ArrayView<const LocalOrdinal> colInds = getLocalView (rowinfo);
01391     return this->findLocalIndex (rowinfo, ind, colInds, hint);
01392   }
01393 
01394 
01397   template <class LocalOrdinal,
01398             class GlobalOrdinal,
01399             class Node>
01400   size_t
01401   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01402   findLocalIndex (RowInfo rowinfo,
01403                   LocalOrdinal ind,
01404                   ArrayView<const LocalOrdinal> colInds,
01405                   size_t hint) const
01406   {
01407     typedef typename ArrayView<const LocalOrdinal>::iterator IT;
01408 
01409     // If the hint was correct, then the hint is the offset to return.
01410     if (hint < rowinfo.numEntries && colInds[hint] == ind) {
01411       return hint;
01412     }
01413 
01414     // The hint was wrong, so we must search for the given column
01415     // index in the column indices for the given row.  How we do the
01416     // search depends on whether the graph's column indices are
01417     // sorted.
01418     IT beg = colInds.begin ();
01419     IT end = beg + rowinfo.numEntries;
01420     IT ptr = beg + rowinfo.numEntries; // "null"
01421     bool found = true;
01422 
01423     if (isSorted ()) {
01424       // binary search
01425       std::pair<IT,IT> p = std::equal_range (beg, end, ind);
01426       if (p.first == p.second) {
01427         found = false;
01428       }
01429       else {
01430         ptr = p.first;
01431       }
01432     }
01433     else {
01434       // direct search
01435       ptr = std::find (beg, end, ind);
01436       if (ptr == end) {
01437         found = false;
01438       }
01439     }
01440 
01441     if (found) {
01442       return Teuchos::as<size_t> (ptr - beg);
01443     }
01444     else {
01445       return Teuchos::OrdinalTraits<size_t>::invalid ();
01446     }
01447   }
01448 
01449 
01452   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01453   size_t
01454   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01455   findGlobalIndex (RowInfo rowinfo, GlobalOrdinal ind, size_t hint) const
01456   {
01457     using Teuchos::ArrayView;
01458     typedef typename ArrayView<const GlobalOrdinal>::iterator IT;
01459 
01460     // Don't let an invalid global column index through.
01461     if (ind == Teuchos::OrdinalTraits<GlobalOrdinal>::invalid ()) {
01462       return Teuchos::OrdinalTraits<size_t>::invalid ();
01463     }
01464 
01465     ArrayView<const GlobalOrdinal> indices = getGlobalView (rowinfo);
01466 
01467     // We don't actually require that the hint be a valid index.
01468     // If it is not in range, we just ignore it.
01469     if (hint < rowinfo.numEntries && indices[hint] == ind) {
01470       return hint;
01471     }
01472 
01473     IT beg = indices.begin ();
01474     IT end = indices.begin () + rowinfo.numEntries; // not indices.end()
01475     if (isSorted ()) { // use binary search
01476       const std::pair<IT,IT> p = std::equal_range (beg, end, ind);
01477       if (p.first == p.second) { // range of matching entries is empty
01478         return Teuchos::OrdinalTraits<size_t>::invalid ();
01479       } else {
01480         return p.first - beg;
01481       }
01482     }
01483     else { // not sorted; must use linear search
01484       const IT loc = std::find (beg, end, ind);
01485       if (loc == end) {
01486         return Teuchos::OrdinalTraits<size_t>::invalid ();
01487       } else {
01488         return loc - beg;
01489       }
01490     }
01491   }
01492 
01493 
01496   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01497   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::clearGlobalConstants()
01498   {
01499     globalNumEntries_       = OrdinalTraits<global_size_t>::invalid();
01500     globalNumDiags_         = OrdinalTraits<global_size_t>::invalid();
01501     globalMaxNumRowEntries_ = OrdinalTraits<global_size_t>::invalid();
01502     haveGlobalConstants_    = false;
01503   }
01504 
01505 
01508   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01509   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01510   checkInternalState () const
01511   {
01512 #ifdef HAVE_TPETRA_DEBUG
01513     const global_size_t GSTI = OrdinalTraits<global_size_t>::invalid();
01514     const size_t         STI = OrdinalTraits<size_t>::invalid();
01515     std::string err = typeName(*this) + "::checkInternalState(): Likely internal logic error. Please contact Tpetra team.";
01516     // check the internal state of this data structure
01517     // this is called by numerous state-changing methods, in a debug build, to ensure that the object
01518     // always remains in a valid state
01519     // the graph should have been allocated with a row map
01520     TEUCHOS_TEST_FOR_EXCEPTION( rowMap_ == null,                     std::logic_error, err );
01521     // am either complete or active
01522     TEUCHOS_TEST_FOR_EXCEPTION( isFillActive() == isFillComplete(),  std::logic_error, err );
01523     // if active, i have no local graph
01524     TEUCHOS_TEST_FOR_EXCEPTION( isFillActive() && lclGraph_ != null, std::logic_error, err );
01525     // if the graph has been fill completed, then all maps should be present
01526     TEUCHOS_TEST_FOR_EXCEPTION( isFillComplete() == true && (colMap_ == null || rangeMap_ == null || domainMap_ == null), std::logic_error, err );
01527     // if storage has been optimized, then indices should have been allocated (even if trivially so)
01528     TEUCHOS_TEST_FOR_EXCEPTION( isStorageOptimized() == true && indicesAreAllocated() == false, std::logic_error, err );
01529     // if storage has been optimized, then number of allocated is now the number of entries
01530     TEUCHOS_TEST_FOR_EXCEPTION( isStorageOptimized() == true && getNodeAllocationSize() != getNodeNumEntries(), std::logic_error, err );
01531     // if graph doesn't have the global constants, then they should all be marked as invalid
01532     TEUCHOS_TEST_FOR_EXCEPTION( haveGlobalConstants_ == false && ( globalNumEntries_ != GSTI || globalNumDiags_ != GSTI || globalMaxNumRowEntries_ != GSTI ), std::logic_error, err );
01533     // if the graph has global cosntants, then they should be valid.
01534     TEUCHOS_TEST_FOR_EXCEPTION( haveGlobalConstants_ == true && ( globalNumEntries_ == GSTI || globalNumDiags_ == GSTI || globalMaxNumRowEntries_ == GSTI ), std::logic_error, err );
01535     TEUCHOS_TEST_FOR_EXCEPTION( haveGlobalConstants_ == true && ( globalNumEntries_ < nodeNumEntries_ || globalNumDiags_ < nodeNumDiags_ || globalMaxNumRowEntries_ < nodeMaxNumRowEntries_ ),
01536                         std::logic_error, err );
01537     // if indices are allocated, then the allocation specifications should have been released
01538     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreAllocated() == true  && (numAllocForAllRows_ != 0 || numAllocPerRow_ != null),                        std::logic_error, err );
01539     // if indices are not allocated, then information dictating allocation quantities should be present
01540     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreAllocated() == false && (nodeNumAllocated_ != STI || nodeNumEntries_ != 0),                           std::logic_error, err );
01541     // if storage is optimized, then profile should be static
01542     TEUCHOS_TEST_FOR_EXCEPTION( isStorageOptimized() && pftype_ != StaticProfile,                                                               std::logic_error, err );
01543     // if rowPtrs_ exists, it is required to have N+1 rows, and rowPtrs_[N] == gblInds1D_.size()/lclInds1D_.size()
01544     TEUCHOS_TEST_FOR_EXCEPTION( isGloballyIndexed() && rowPtrs_ != null && ((size_t)rowPtrs_.size() != getNodeNumRows()+1 || rowPtrs_[getNodeNumRows()] != (size_t)gblInds1D_.size()), std::logic_error, err );
01545     TEUCHOS_TEST_FOR_EXCEPTION(  isLocallyIndexed() && rowPtrs_ != null && ((size_t)rowPtrs_.size() != getNodeNumRows()+1 || rowPtrs_[getNodeNumRows()] != (size_t)lclInds1D_.size()), std::logic_error, err );
01546     // if profile is dynamic and we have allocated, then 2D allocations should be present
01547     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == DynamicProfile && indicesAreAllocated() && getNodeNumRows() > 0 && lclInds2D_ == null && gblInds2D_ == null,
01548                                                                                                                                         std::logic_error, err );
01549     // if profile is dynamic, then numentries and 2D indices are needed and should be present
01550     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == DynamicProfile && indicesAreAllocated() && getNodeNumRows() > 0 && (numRowEntries_ == null || (lclInds2D_ == null && gblInds2D_ == null)),
01551                                                                                                                                         std::logic_error, err );
01552     // if profile is dynamic, then 1D allocations should not be present
01553     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == DynamicProfile && (lclInds1D_ != null || gblInds1D_ != null),                                std::logic_error, err );
01554     // if profile is dynamic, then row offsets should not be present
01555     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == DynamicProfile && rowPtrs_ != null,                                                          std::logic_error, err );
01556     // if profile is static and we have allocated non-trivially, then 1D allocations should be present
01557     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == StaticProfile && indicesAreAllocated() && getNodeAllocationSize() > 0 && lclInds1D_ == null && gblInds1D_ == null,
01558                                                                                                                                         std::logic_error, err );
01559     // if profile is static, then 2D allocations should not be present
01560     TEUCHOS_TEST_FOR_EXCEPTION( pftype_ == StaticProfile && (lclInds2D_ != null || gblInds2D_ != null),                                 std::logic_error, err );
01561     // if indices are not allocated, then none of the buffers should be.
01562     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreAllocated() == false && (rowPtrs_ != null || numRowEntries_ != null ||
01563                                                                  lclInds1D_ != null || lclInds2D_ != null ||
01564                                                                  gblInds1D_ != null || gblInds2D_ != null),                             std::logic_error, err );
01565     // indices may be local or global only if they are allocated (numAllocated is redundant; could simply be indicesAreLocal_ || indicesAreGlobal_)
01566     TEUCHOS_TEST_FOR_EXCEPTION( (indicesAreLocal_ == true || indicesAreGlobal_ == true) && indicesAreAllocated_ == false,               std::logic_error, err );
01567     // indices may be local or global, but not both
01568     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreLocal_ == true && indicesAreGlobal_ == true,                                                  std::logic_error, err );
01569     // if indices are local, then global allocations should not be present
01570     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreLocal_ == true && (gblInds1D_ != null || gblInds2D_ != null),                                 std::logic_error, err );
01571     // if indices are global, then local allocations should not be present
01572     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreGlobal_ == true && (lclInds1D_ != null || lclInds2D_ != null),                                std::logic_error, err );
01573     // if indices are local, then local allocations should be present
01574     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreLocal_ == true && getNodeAllocationSize() > 0 && lclInds1D_ == null && getNodeNumRows() > 0 && lclInds2D_ == null,
01575                                                                                                                           std::logic_error, err );
01576     // if indices are global, then global allocations should be present
01577     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreGlobal_ == true && getNodeAllocationSize() > 0 && gblInds1D_ == null && getNodeNumRows() > 0 && gblInds2D_ == null,
01578                                                                                                                           std::logic_error, err );
01579     // if indices are allocated, then we should have recorded how many were allocated
01580     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreAllocated() == true  && nodeNumAllocated_ == STI,                                       std::logic_error, err );
01581     // if indices are not allocated, then the allocation size should be marked invalid
01582     TEUCHOS_TEST_FOR_EXCEPTION( indicesAreAllocated() == false && nodeNumAllocated_ != STI,                                       std::logic_error, err );
01583     // check the actual allocations
01584     if (indicesAreAllocated()) {
01585       size_t actualNumAllocated = 0;
01586       if (pftype_ == DynamicProfile) {
01587         if (isGloballyIndexed() && gblInds2D_ != null) {
01588           for (size_t r = 0; r < getNodeNumRows(); ++r) {
01589             actualNumAllocated += gblInds2D_[r].size();
01590           }
01591         }
01592         else if (isLocallyIndexed() && lclInds2D_ != null) {
01593           for (size_t r = 0; r < getNodeNumRows(); ++r) {
01594             actualNumAllocated += lclInds2D_[r].size();
01595           }
01596         }
01597         TEUCHOS_TEST_FOR_EXCEPTION(actualNumAllocated != nodeNumAllocated_, std::logic_error, err );
01598       }
01599       else if (rowPtrs_ != null) { // pftype_ == StaticProfile
01600         actualNumAllocated = rowPtrs_[getNodeNumRows()];
01601         TEUCHOS_TEST_FOR_EXCEPTION(  isLocallyIndexed() == true && (size_t)lclInds1D_.size() != actualNumAllocated, std::logic_error, err );
01602         TEUCHOS_TEST_FOR_EXCEPTION( isGloballyIndexed() == true && (size_t)gblInds1D_.size() != actualNumAllocated, std::logic_error, err );
01603         TEUCHOS_TEST_FOR_EXCEPTION(actualNumAllocated != nodeNumAllocated_, std::logic_error, err );
01604       }
01605     }
01606 #endif
01607   }
01608 
01609 
01612   //                                                                         //
01613   //                  User-visible class methods                             //
01614   //                                                                         //
01617 
01618 
01621   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01622   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNumEntriesInGlobalRow(GlobalOrdinal globalRow) const
01623   {
01624     const LocalOrdinal lrow = rowMap_->getLocalElement(globalRow);
01625     size_t ret = OrdinalTraits<size_t>::invalid();
01626     if (hasRowInfo() && lrow != OrdinalTraits<LocalOrdinal>::invalid())
01627     {
01628       RowInfo rowinfo = getRowInfo(lrow);
01629       ret = rowinfo.numEntries;
01630     }
01631     return ret;
01632   }
01633 
01634 
01637   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01638   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNumEntriesInLocalRow(LocalOrdinal localRow) const
01639   {
01640     size_t ret = OrdinalTraits<size_t>::invalid();
01641     if (hasRowInfo() && rowMap_->isNodeLocalElement(localRow)) {
01642       RowInfo rowinfo = getRowInfo(localRow);
01643       ret = rowinfo.numEntries;
01644     }
01645     return ret;
01646   }
01647 
01648 
01651   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01652   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNumAllocatedEntriesInGlobalRow(GlobalOrdinal globalRow) const
01653   {
01654     const LocalOrdinal lrow = rowMap_->getLocalElement(globalRow);
01655     size_t ret = OrdinalTraits<size_t>::invalid();
01656     if (hasRowInfo() && lrow != OrdinalTraits<LocalOrdinal>::invalid())
01657     {
01658       RowInfo rowinfo = getRowInfo(lrow);
01659       ret = rowinfo.allocSize;
01660     }
01661     return ret;
01662   }
01663 
01664 
01667   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01668   size_t CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNumAllocatedEntriesInLocalRow(LocalOrdinal localRow) const
01669   {
01670     size_t ret = OrdinalTraits<size_t>::invalid();
01671     if (hasRowInfo() && rowMap_->isNodeLocalElement(localRow)) {
01672       RowInfo rowinfo = getRowInfo(localRow);
01673       ret = rowinfo.allocSize;
01674     }
01675     return ret;
01676   }
01677 
01678 
01681   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01682   ArrayRCP<const size_t> CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodeRowPtrs() const
01683   {
01684     return rowPtrs_;
01685   }
01686 
01687 
01690   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01691   ArrayRCP<const LocalOrdinal> CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::getNodePackedIndices() const
01692   {
01693     return lclInds1D_;
01694   }
01695 
01696 
01699   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01700   void
01701   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01702   getLocalRowCopy (LocalOrdinal localRow,
01703                    const ArrayView<LocalOrdinal>& indices,
01704                    size_t& numEntries) const
01705   {
01706     using Teuchos::ArrayView;
01707     typedef LocalOrdinal LO;
01708     typedef GlobalOrdinal GO;
01709 
01710     TEUCHOS_TEST_FOR_EXCEPTION(
01711       isGloballyIndexed () && ! hasColMap (), std::runtime_error,
01712       "Tpetra::CrsGraph::getLocalRowCopy: The graph is globally indexed and "
01713       "does not have a column Map yet.  That means we don't have local indices "
01714       "for columns yet, so it doesn't make sense to call this method.  If the "
01715       "graph doesn't have a column Map yet, you should call fillComplete on "
01716       "it first.");
01717     TEUCHOS_TEST_FOR_EXCEPTION(
01718       ! hasRowInfo(), std::runtime_error,
01719       "Tpetra::CrsGraph::getLocalRowCopy: graph row information was deleted "
01720       "at fillComplete().");
01721 
01722 
01723     if (! getRowMap ()->isNodeLocalElement (localRow)) {
01724       numEntries = 0;
01725       return;
01726     }
01727 
01728     const RowInfo rowinfo = getRowInfo (localRow);
01729     const size_t theNumEntries = rowinfo.numEntries;
01730 
01731     TEUCHOS_TEST_FOR_EXCEPTION(
01732       static_cast<size_t> (indices.size ()) < theNumEntries,
01733       std::runtime_error,
01734       "Tpetra::CrsGraph::getLocalRowCopy: The given row " << localRow << " has "
01735       << theNumEntries << " entries, but indices.size() = " << indices.size ()
01736       << ", which does not suffice to store the row's indices.");
01737 
01738     numEntries = theNumEntries;
01739 
01740     if (isLocallyIndexed ()) {
01741       ArrayView<const LO> lview = getLocalView (rowinfo);
01742       std::copy (lview.begin (), lview.begin () + numEntries, indices.begin ());
01743     }
01744     else if (isGloballyIndexed ()) {
01745       ArrayView<const GO> gview = getGlobalView (rowinfo);
01746       const map_type& colMap = * (this->getColMap ());
01747       for (size_t j = 0; j < numEntries; ++j) {
01748         indices[j] = colMap.getLocalElement (gview[j]);
01749       }
01750     }
01751     else {
01752       // If the graph on the calling process is neither locally nor
01753       // globally indexed, that means it owns no column indices.
01754       //
01755       // FIXME (mfh 21 Oct 2013) It's not entirely clear to me whether
01756       // we can reach this branch, given the checks above.  However,
01757       // if that is the case, it should still be correct to call this
01758       // function if the calling process owns no column indices.
01759       numEntries = 0;
01760     }
01761   }
01762 
01763 
01766   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01767   void
01768   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01769   getGlobalRowCopy (GlobalOrdinal globalRow,
01770                     const ArrayView<GlobalOrdinal>& indices,
01771                     size_t& NumIndices) const
01772   {
01773     // One of the following is true:
01774     //
01775     // 1. The calling process owns no column indices.
01776     // 2. The graph stores global column indices.
01777     // 3. The graph has a column Map that we can use to convert any
01778     //    stored local indices into global indices for output.
01779 
01780     const char tfecfFuncName[] = "getGlobalRowCopy";
01781     const LocalOrdinal localRow = rowMap_->getLocalElement (globalRow);
01782     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01783       localRow == Teuchos::OrdinalTraits<LocalOrdinal>::invalid(),
01784       std::runtime_error, ": globalRow (== " << globalRow << ") is not owned "
01785       "by (i.e., is not in the row Map on) the calling process with rank "
01786       << getComm ()->getRank () << ".");
01787     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01788       ! hasRowInfo (), std::runtime_error,
01789       ": graph row information was deleted at fillComplete().");
01790 
01791     const RowInfo rowinfo = getRowInfo (static_cast<size_t> (localRow));
01792     NumIndices = rowinfo.numEntries;
01793     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01794       static_cast<size_t> (indices.size ()) < NumIndices, std::runtime_error,
01795       ": specified storage (size == " << indices.size () << ") does not suffice "
01796       "to hold all entries in this row (NumIndices == " << NumIndices << ").");
01797 
01798     if (isLocallyIndexed ()) {
01799       ArrayView<const LocalOrdinal> lview = getLocalView (rowinfo);
01800       for (size_t j = 0; j < NumIndices; ++j) {
01801         indices[j] = colMap_->getGlobalElement (lview[j]);
01802       }
01803     }
01804     else if (isGloballyIndexed ()) {
01805       ArrayView<const GlobalOrdinal> gview = getGlobalView (rowinfo);
01806       std::copy (gview.begin (), gview.begin () + NumIndices, indices.begin ());
01807     }
01808   }
01809 
01810 
01813   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01814   void
01815   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01816   getLocalRowView (LocalOrdinal localRow, ArrayView<const LocalOrdinal> &indices) const
01817   {
01818     const char tfecfFuncName[] = "getLocalRowView";
01819     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01820       isGloballyIndexed(), std::runtime_error,
01821       ": The graph is globally indexed, so we cannot return a view with local "
01822       "column indices.  Use getLocalRowCopy() instead.");
01823     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01824       ! hasRowInfo (), std::runtime_error,
01825       ": graph row information was deleted at fillComplete().");
01826 
01827     indices = null;
01828     if (rowMap_->isNodeLocalElement (localRow)) {
01829       const RowInfo rowinfo = getRowInfo(localRow);
01830       if (rowinfo.numEntries > 0) {
01831         indices = getLocalView (rowinfo);
01832         indices = indices (0, rowinfo.numEntries);
01833       }
01834 #ifdef HAVE_TPETRA_DEBUG
01835       const size_t numEntriesInView = static_cast<size_t> (indices.size ());
01836       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01837         numEntriesInView != getNumEntriesInLocalRow (localRow),
01838         std::logic_error, ": The number of entries " << numEntriesInView
01839         << " in the view to return must be the same as getNumEntriesInLocalRow"
01840         "(localRow=" << localRow << ") = " << getNumEntriesInLocalRow (localRow)
01841         << ", but this is not the case.  "
01842         "Please report this bug to the Tpetra developers.");
01843 #endif // HAVE_TPETRA_DEBUG
01844     }
01845   }
01846 
01847 
01850   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01851   void
01852   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01853   getGlobalRowView (GlobalOrdinal globalRow,
01854                     ArrayView<const GlobalOrdinal>& indices) const
01855   {
01856     using Teuchos::as;
01857     const char tfecfFuncName[] = "getGlobalRowView";
01858     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01859       isLocallyIndexed (), std::runtime_error,
01860       ": The graph is locally indexed, so we cannot return a view with global "
01861       "column indices.  Use getGlobalRowCopy() instead.");
01862     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01863       ! hasRowInfo (), std::runtime_error,
01864       ": graph row information was deleted at fillComplete().");
01865 
01866     // We don't have to call isNodeGlobalElement() to test whether
01867     // globalRow belongs to the calling process.  That method requires
01868     // a global to local lookup anyway, and getLocalElement() returns
01869     // invalid() anyway if the global index wasn't found.
01870     const LocalOrdinal localRow = rowMap_->getLocalElement (globalRow);
01871     indices = null;
01872     if (localRow != Teuchos::OrdinalTraits<LocalOrdinal>::invalid ()) {
01873       const RowInfo rowInfo = getRowInfo (as<size_t> (localRow));
01874       if (rowInfo.numEntries > 0) {
01875         indices = (getGlobalView (rowInfo)) (0, rowInfo.numEntries);
01876       }
01877     }
01878 #ifdef HAVE_TPETRA_DEBUG
01879     using std::endl;
01880     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01881       as<size_t> (indices.size ()) != getNumEntriesInGlobalRow (globalRow),
01882       std::logic_error,
01883       ": Violated stated post-conditions:"
01884       << "  indices.size () = " << indices.size () << endl
01885       << "  as<size_t> (indices.size ()) = " << as<size_t> (indices.size ())
01886       << endl << "  getNumEntriesInGlobalRow (globalRow = " << globalRow
01887       << ") = " << getNumEntriesInGlobalRow (globalRow) << endl
01888       << "Please report this bug to the Tpetra developers.");
01889 #endif // HAVE_TPETRA_DEBUG
01890   }
01891 
01892 
01895   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01896   void
01897   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01898   insertLocalIndices (const LocalOrdinal localRow,
01899                       const ArrayView<const LocalOrdinal> &indices)
01900   {
01901     using Teuchos::ArrayView;
01902     const char tfecfFuncName[] = "insertLocalIndices";
01903 
01904     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01905       isFillActive() == false, std::runtime_error,
01906       ": requires that fill is active.");
01907     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01908       isGloballyIndexed() == true, std::runtime_error,
01909       ": graph indices are global; use insertGlobalIndices().");
01910     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01911       hasColMap() == false, std::runtime_error,
01912       ": cannot insert local indices without a column map.");
01913     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01914       rowMap_->isNodeLocalElement(localRow) == false, std::runtime_error,
01915       ": row does not belong to this node.");
01916     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01917       hasRowInfo() == false, std::runtime_error,
01918       ": graph row information was deleted at fillComplete().");
01919     if (! indicesAreAllocated ()) {
01920       allocateIndices (LocalIndices);
01921     }
01922 
01923 #ifdef HAVE_TPETRA_DEBUG
01924     // In a debug build, if the graph has a column Map, test whether
01925     // any of the given column indices are not in the column Map.
01926     // Keep track of the invalid column indices so we can tell the
01927     // user about them.
01928     if (hasColMap ()) {
01929       using Teuchos::Array;
01930       using Teuchos::toString;
01931       using std::endl;
01932       typedef LocalOrdinal LO;
01933       typedef typename ArrayView<const LO>::size_type size_type;
01934 
01935       const map_type& colMap = * (getColMap ());
01936       Array<LO> badColInds;
01937       bool allInColMap = true;
01938       for (size_type k = 0; k < indices.size (); ++k) {
01939         if (! colMap.isNodeLocalElement (indices[k])) {
01940           allInColMap = false;
01941           badColInds.push_back (indices[k]);
01942         }
01943       }
01944       if (! allInColMap) {
01945         std::ostringstream os;
01946         os << "Tpetra::CrsMatrix::insertLocalIndices: You attempted to insert "
01947           "entries in owned row " << localRow << ", at the following column "
01948           "indices: " << toString (indices) << "." << endl;
01949         os << "Of those, the following indices are not in the column Map on "
01950           "this process: " << toString (badColInds) << "." << endl << "Since "
01951           "the graph has a column Map already, it is invalid to insert entries "
01952           "at those locations.";
01953         TEUCHOS_TEST_FOR_EXCEPTION(! allInColMap, std::invalid_argument, os.str ());
01954       }
01955     }
01956 #endif // HAVE_TPETRA_DEBUG
01957 
01958     insertLocalIndicesImpl (localRow, indices);
01959 
01960 #ifdef HAVE_TPETRA_DEBUG
01961     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01962       indicesAreAllocated() == false || isLocallyIndexed() == false,
01963       std::logic_error,
01964       ": Violated stated post-conditions. Please contact Tpetra team.");
01965 #endif
01966   }
01967 
01968 
01971   template <class LocalOrdinal, class GlobalOrdinal, class Node>
01972   void
01973   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
01974   insertLocalIndicesFiltered (const LocalOrdinal localRow,
01975                               const ArrayView<const LocalOrdinal> &indices)
01976   {
01977     typedef LocalOrdinal LO;
01978     const char tfecfFuncName[] = "insertLocalIndicesFiltered";
01979 
01980     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01981       isFillActive() == false, std::runtime_error,
01982       ": requires that fill is active.");
01983     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01984       isGloballyIndexed() == true, std::runtime_error,
01985       ": graph indices are global; use insertGlobalIndices().");
01986     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01987       hasColMap() == false, std::runtime_error,
01988       ": cannot insert local indices without a column map.");
01989     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01990       rowMap_->isNodeLocalElement(localRow) == false, std::runtime_error,
01991       ": row does not belong to this node.");
01992     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
01993       hasRowInfo() == false, std::runtime_error,
01994       ": graph row information was deleted at fillComplete().");
01995     if (indicesAreAllocated() == false) {
01996       allocateIndices(LocalIndices);
01997     }
01998 
01999      // If we have a column map, use it to filter the entries.
02000     if (hasColMap ()) {
02001       Array<LO> filtered_indices(indices);
02002       SLocalGlobalViews inds_view;
02003       SLocalGlobalNCViews inds_ncview;
02004       inds_ncview.linds = filtered_indices();
02005       const size_t numFilteredEntries =
02006         filterIndices<LocalIndices>(inds_ncview);
02007       inds_view.linds = filtered_indices (0, numFilteredEntries);
02008       insertLocalIndicesImpl(localRow, inds_view.linds);
02009     }
02010     else {
02011       insertLocalIndicesImpl(localRow, indices);
02012     }
02013 #ifdef HAVE_TPETRA_DEBUG
02014     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02015       indicesAreAllocated() == false || isLocallyIndexed() == false,
02016       std::logic_error,
02017       ": Violated stated post-conditions. Please contact Tpetra team.");
02018 #endif
02019   }
02020 
02021 
02024   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02025   void
02026   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02027   insertGlobalIndices (const GlobalOrdinal grow,
02028                        const ArrayView<const GlobalOrdinal> &indices)
02029   {
02030     typedef LocalOrdinal LO;
02031     typedef GlobalOrdinal GO;
02032     typedef typename ArrayView<const GO>::size_type size_type;
02033     const char tfecfFuncName[] = "insertGlobalIndices";
02034 
02035     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02036       isLocallyIndexed() == true, std::runtime_error,
02037       ": graph indices are local; use insertLocalIndices().");
02038     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02039       hasRowInfo() == false, std::runtime_error,
02040       ": graph row information was deleted at fillComplete().");
02041     // This can't really be satisfied for now, because if we are
02042     // fillComplete(), then we are local.  In the future, this may
02043     // change.  However, the rule that modification require active
02044     // fill will not change.
02045     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02046       isFillActive() == false, std::runtime_error,
02047       ": You are not allowed to call this method if fill is not active.  "
02048       "If fillComplete has been called, you must first call resumeFill "
02049       "before you may insert indices.");
02050     if (! indicesAreAllocated ()) {
02051       allocateIndices (GlobalIndices);
02052     }
02053     const LO myRow = rowMap_->getLocalElement (grow);
02054     if (myRow != Teuchos::OrdinalTraits<LO>::invalid ()) {
02055 #ifdef HAVE_TPETRA_DEBUG
02056       if (hasColMap ()) {
02057         using std::endl;
02058         const map_type& colMap = * (getColMap ());
02059         // In a debug build, keep track of the nonowned ("bad") column
02060         // indices, so that we can display them in the exception
02061         // message.  In a release build, just ditch the loop early if
02062         // we encounter a nonowned column index.
02063         Array<GO> badColInds;
02064         bool allInColMap = true;
02065         for (size_type k = 0; k < indices.size (); ++k) {
02066           if (! colMap.isNodeGlobalElement (indices[k])) {
02067             allInColMap = false;
02068             badColInds.push_back (indices[k]);
02069           }
02070         }
02071         if (! allInColMap) {
02072           std::ostringstream os;
02073           os << "Tpetra::CrsGraph::insertGlobalIndices: You attempted to insert "
02074             "entries in owned row " << grow << ", at the following column "
02075             "indices: " << toString (indices) << "." << endl;
02076           os << "Of those, the following indices are not in the column Map on "
02077             "this process: " << toString (badColInds) << "." << endl << "Since "
02078             "the matrix has a column Map already, it is invalid to insert "
02079             "entries at those locations.";
02080           TEUCHOS_TEST_FOR_EXCEPTION(! allInColMap, std::invalid_argument, os.str ());
02081         }
02082       }
02083 #endif // HAVE_TPETRA_DEBUG
02084       insertGlobalIndicesImpl (myRow, indices);
02085     }
02086     else { // a nonlocal row
02087       const size_type numIndices = indices.size ();
02088       // This creates the Array if it doesn't exist yet.  std::map's
02089       // operator[] does a lookup each time, so it's better to pull
02090       // nonlocals_[grow] out of the loop.
02091       std::vector<GO>& nonlocalRow = nonlocals_[grow];
02092       for (size_type k = 0; k < numIndices; ++k) {
02093         nonlocalRow.push_back (indices[k]);
02094       }
02095     }
02096 #ifdef HAVE_TPETRA_DEBUG
02097     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02098       indicesAreAllocated() == false || isGloballyIndexed() == false,
02099       std::logic_error,
02100       ": Violated stated post-conditions. Please contact Tpetra team.");
02101 #endif
02102   }
02103 
02104 
02107   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02108   void
02109   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02110   insertGlobalIndicesFiltered (const GlobalOrdinal grow,
02111                                const ArrayView<const GlobalOrdinal> &indices)
02112   {
02113     typedef LocalOrdinal LO;
02114     typedef GlobalOrdinal GO;
02115     const char tfecfFuncName[] = "insertGlobalIndicesFiltered";
02116 
02117     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02118       isLocallyIndexed() == true, std::runtime_error,
02119       ": graph indices are local; use insertLocalIndices().");
02120     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02121       hasRowInfo() == false, std::runtime_error,
02122       ": graph row information was deleted at fillComplete().");
02123     // This can't really be satisfied for now, because if we are
02124     // fillComplete(), then we are local.  In the future, this may
02125     // change.  However, the rule that modification require active
02126     // fill will not change.
02127     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02128       isFillActive() == false, std::runtime_error,
02129       ": You are not allowed to call this method if fill is not active.  "
02130       "If fillComplete has been called, you must first call resumeFill "
02131       "before you may insert indices.");
02132     if (indicesAreAllocated() == false) {
02133       allocateIndices (GlobalIndices);
02134     }
02135     const LO myRow = rowMap_->getLocalElement (grow);
02136     if (myRow != Teuchos::OrdinalTraits<LO>::invalid ()) {
02137       // If we have a column map, use it to filter the entries.
02138       if (hasColMap ()) {
02139         Array<GO> filtered_indices(indices);
02140         SLocalGlobalViews inds_view;
02141         SLocalGlobalNCViews inds_ncview;
02142         inds_ncview.ginds = filtered_indices();
02143         const size_t numFilteredEntries =
02144           filterIndices<GlobalIndices> (inds_ncview);
02145         inds_view.ginds = filtered_indices (0, numFilteredEntries);
02146         insertGlobalIndicesImpl(myRow, inds_view.ginds);
02147       }
02148       else {
02149        insertGlobalIndicesImpl(myRow, indices);
02150       }
02151     }
02152     else { // a nonlocal row
02153       typedef typename ArrayView<const GO>::size_type size_type;
02154       const size_type numIndices = indices.size ();
02155       for (size_type k = 0; k < numIndices; ++k) {
02156         nonlocals_[grow].push_back (indices[k]);
02157       }
02158     }
02159 #ifdef HAVE_TPETRA_DEBUG
02160     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02161       indicesAreAllocated() == false || isGloballyIndexed() == false,
02162       std::logic_error,
02163       ": Violated stated post-conditions. Please contact Tpetra team.");
02164 #endif
02165   }
02166 
02169   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02170   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::removeLocalIndices(LocalOrdinal lrow)
02171   {
02172     const char tfecfFuncName[] = "removeLocalIndices()";
02173     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( isFillActive() == false,                    std::runtime_error, ": requires that fill is active.");
02174     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( isStorageOptimized() == true,               std::runtime_error, ": cannot remove indices after optimizeStorage() has been called.");
02175     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( isGloballyIndexed() == true,                std::runtime_error, ": graph indices are global.");
02176     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( rowMap_->isNodeLocalElement(lrow) == false, std::runtime_error, ": row does not belong to this node.");
02177     if (indicesAreAllocated() == false) {
02178       allocateIndices(LocalIndices);
02179     }
02180     //
02181     clearGlobalConstants();
02182     //
02183     if (numRowEntries_ != null) {
02184       nodeNumEntries_ -= numRowEntries_[lrow];
02185       numRowEntries_[lrow] = 0;
02186     }
02187 #ifdef HAVE_TPETRA_DEBUG
02188     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(getNumEntriesInLocalRow(lrow) != 0 || indicesAreAllocated() == false || isLocallyIndexed() == false, std::logic_error,
02189         ": Violated stated post-conditions. Please contact Tpetra team.");
02190 #endif
02191   }
02192 
02195   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02196   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::setAllIndices(const ArrayRCP<size_t> & rowPointers,const ArrayRCP<LocalOrdinal> & columnIndices)
02197   {
02198     const char tfecfFuncName[] = "setAllIndices()";
02199     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( hasColMap() == false, std::runtime_error, ": requires a ColMap.");
02200     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( (size_t)rowPointers.size() != getNodeNumRows()+1, std::runtime_error, ": requires rowPointers.size() == getNodeNumRows()+1");
02201     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( lclInds1D_ != Teuchos::null || gblInds1D_ != Teuchos::null, std::runtime_error, ": cannot have 1D data structures allocated.");
02202     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( lclInds2D_ != Teuchos::null || gblInds2D_ != Teuchos::null, std::runtime_error, ": cannot have 2D data structures allocated.");
02203 
02204     indicesAreAllocated_ = true;
02205     indicesAreLocal_     = true;
02206     pftype_              = StaticProfile; // if the profile wasn't static before, it sure is now.
02207     lclInds1D_           = columnIndices;
02208     rowPtrs_             = rowPointers;
02209     nodeNumEntries_ = nodeNumAllocated_ = rowPtrs_[getNodeNumRows()];
02210     numAllocForAllRows_  = 0;
02211     numAllocPerRow_      = null;
02212     checkInternalState();
02213   }
02214 
02217   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02218   void
02219   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02220   getNumEntriesPerLocalRowUpperBound (Teuchos::ArrayRCP<const size_t>& boundPerLocalRow,
02221                                       size_t& boundForAllLocalRows,
02222                                       bool& boundSameForAllLocalRows) const
02223   {
02224     // The three output arguments.  We assign them to the actual
02225     // output arguments at the end, in order to implement
02226     // transactional semantics.
02227     Teuchos::ArrayRCP<const size_t> numEntriesPerRow;
02228     size_t numEntriesForAll = 0;
02229     bool allRowsSame = true;
02230 
02231     const ptrdiff_t numRows = static_cast<ptrdiff_t> (this->getNodeNumRows ());
02232 
02233     if (! this->indicesAreAllocated ()) {
02234       if (! this->numAllocPerRow_.is_null ()) {
02235         numEntriesPerRow = this->numAllocPerRow_;
02236         allRowsSame = false; // conservatively; we don't check the array
02237       }
02238       else {
02239         numEntriesForAll = this->numAllocForAllRows_;
02240         allRowsSame = true;
02241       }
02242     }
02243     else if (! this->numRowEntries_.is_null ()) {
02244       numEntriesPerRow = numRowEntries_;
02245         allRowsSame = false; // conservatively; we don't check the array
02246     }
02247     else if (this->nodeNumAllocated_ == 0) {
02248       numEntriesForAll = 0;
02249       allRowsSame = true;
02250     }
02251     else {
02252       // left with the case that we have optimized storage. in this
02253       // case, we have to construct a list of row sizes.
02254       TEUCHOS_TEST_FOR_EXCEPTION(
02255         this->getProfileType () != StaticProfile, std::logic_error,
02256         "Tpetra::CrsGraph::getNumEntriesPerRowUpperBound: "
02257         "The graph is not StaticProfile, but storage appears to be optimized.  "
02258         "Please report this bug to the Tpetra developers.");
02259       TEUCHOS_TEST_FOR_EXCEPTION(
02260         numRows != 0 && this->rowPtrs_.size () == 0, std::logic_error,
02261         "Tpetra::CrsGraph::getNumEntriesPerRowUpperBound: "
02262         "The graph has " << numRows << " (> 0) row" << (numRows != 1 ? "s" : "")
02263         << " on the calling process, but the rowPtrs_ array has zero entries.  "
02264         "Please report this bug to the Tpetra developers.");
02265 
02266       Teuchos::ArrayRCP<size_t> numEnt;
02267       if (numRows != 0) {
02268         numEnt = Teuchos::arcp<size_t> (numRows);
02269       }
02270 
02271       // We have to iterate through the row offsets anyway, so we
02272       // might as well check whether all rows' bounds are the same.
02273       bool allRowsReallySame = false;
02274       for (ptrdiff_t i = 0; i < numRows; ++i) {
02275         numEnt[i] = this->rowPtrs_[i+1] - this->rowPtrs_[i];
02276         if (i != 0 && numEnt[i] != numEnt[i-1]) {
02277           allRowsReallySame = false;
02278         }
02279       }
02280       if (allRowsReallySame) {
02281         if (numRows == 0) {
02282           numEntriesForAll = 0;
02283         } else {
02284           numEntriesForAll = numEnt[1] - numEnt[0];
02285         }
02286         allRowsSame = true;
02287       }
02288       else {
02289         numEntriesPerRow = numEnt; // Teuchos::arcp_const_cast<const size_t> (numEnt);
02290         allRowsSame = false; // conservatively; we don't check the array
02291       }
02292     }
02293 
02294     TEUCHOS_TEST_FOR_EXCEPTION(
02295       numEntriesForAll != 0 && numEntriesPerRow.size () != 0, std::logic_error,
02296       "Tpetra::CrsGraph::getNumEntriesPerLocalRowUpperBound: "
02297       "numEntriesForAll and numEntriesPerRow are not consistent.  The former "
02298       "is " << numEntriesForAll << ", but the latter has nonzero size "
02299       << numEntriesPerRow.size () << ".  "
02300       "Please report this bug to the Tpetra developers.");
02301 
02302     boundPerLocalRow = numEntriesPerRow;
02303     boundForAllLocalRows = numEntriesForAll;
02304     boundSameForAllLocalRows = allRowsSame;
02305   }
02306 
02307   // TODO: in the future, globalAssemble() should use import/export functionality
02310   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02311   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::globalAssemble()
02312   {
02313     using Teuchos::Array;
02314     using Teuchos::as;
02315     using Teuchos::Comm;
02316     using Teuchos::gatherAll;
02317     using Teuchos::ireceive;
02318     using Teuchos::isend;
02319     using Teuchos::outArg;
02320     using Teuchos::REDUCE_MAX;
02321     using Teuchos::reduceAll;
02322     using Teuchos::toString;
02323     using Teuchos::waitAll;
02324     using std::endl;
02325     using std::make_pair;
02326     using std::pair;
02327     typedef GlobalOrdinal GO;
02328     typedef typename std::map<GO, std::vector<GO> >::const_iterator NLITER;
02329     typedef typename Array<GO>::size_type size_type;
02330 
02331     const char tfecfFuncName[] = "globalAssemble"; // for exception macro
02332     RCP<const Comm<int> > comm = getComm();
02333 
02334     const int numImages = comm->getSize();
02335     const int myImageID = comm->getRank();
02336 #ifdef HAVE_TPETRA_DEBUG
02337     Teuchos::barrier (*comm);
02338 #endif // HAVE_TPETRA_DEBUG
02339 
02340     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( ! isFillActive(), std::runtime_error,
02341       ": requires that fill is active.");
02342     // Determine if any nodes have global entries to share
02343     {
02344       size_t MyNonlocals = nonlocals_.size(), MaxGlobalNonlocals;
02345       reduceAll (*comm, REDUCE_MAX, MyNonlocals, outArg (MaxGlobalNonlocals));
02346       if (MaxGlobalNonlocals == 0) {
02347         return;  // no entries to share
02348       }
02349     }
02350 
02351     // compute a list of NLRs from nonlocals_ and use it to compute:
02352     //      IdsAndRows: a vector of (id,row) pairs
02353     //          NLR2Id: a map from NLR to the Id that owns it
02354     // globalNeighbors: a global graph of connectivity between images: globalNeighbors(i,j) indicates that j sends to i
02355     //         sendIDs: a list of all images I send to
02356     //         recvIDs: a list of all images I receive from (constructed later)
02357     Array<pair<int, GO> > IdsAndRows;
02358     std::map<GO, int> NLR2Id;
02359     Teuchos::SerialDenseMatrix<int, char> globalNeighbors;
02360     Array<int> sendIDs, recvIDs;
02361     {
02362       // nonlocals_ contains the entries we are holding for all non-local rows
02363       // we want a list of the rows for which we have data
02364       Array<GO> NLRs;
02365       std::set<GO> setOfRows;
02366       for (NLITER iter = nonlocals_.begin(); iter != nonlocals_.end(); ++iter) {
02367         setOfRows.insert(iter->first);
02368       }
02369       // copy the elements in the set into an Array
02370       NLRs.resize(setOfRows.size());
02371       std::copy(setOfRows.begin(), setOfRows.end(), NLRs.begin());
02372 
02373       // get a list of ImageIDs for the non-local rows (NLRs)
02374       Array<int> NLRIds(NLRs.size());
02375       {
02376         LookupStatus stat = rowMap_->getRemoteIndexList(NLRs(),NLRIds());
02377         int lclerror = ( stat == IDNotPresent ? 1 : 0 );
02378         int gblerror;
02379         reduceAll<int, int> (*comm, REDUCE_MAX, lclerror, outArg (gblerror));
02380         if (gblerror != 0) {
02381           const int myRank = comm->getRank ();
02382           std::ostringstream os;
02383           os << "On one or more processes in the communicator, "
02384              << "there were insertions into rows of the graph that do not "
02385              << "exist in the row Map on any process in the communicator."
02386              << endl << "This process " << myRank << " is "
02387              << (lclerror == 0 ? "not " : "") << "one of those offending "
02388              << "processes." << endl;
02389           if (lclerror != 0) {
02390             // If NLRIds[k] is -1, then NLRs[k] is a row index not in
02391             // the row Map.  Collect this list of invalid row indices
02392             // for display in the exception message.
02393             Array<GO> invalidNonlocalRows;
02394             for (size_type k = 0; k < NLRs.size (); ++k) {
02395               if (NLRIds[k] == -1) {
02396                 invalidNonlocalRows.push_back (NLRs[k]);
02397               }
02398             }
02399             const size_type numInvalid = invalidNonlocalRows.size ();
02400             os << "On this process, " << numInvalid << " nonlocal row"
02401                << (numInvalid != 1 ? "s " : " ") << " were inserted that are "
02402                << "not in the row Map on any process." << endl;
02403             // Don't print _too_ many nonlocal rows.
02404             if (numInvalid <= 100) {
02405               os << "Offending row indices: "
02406                  << toString (invalidNonlocalRows ()) << endl;
02407             }
02408           }
02409           TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02410             gblerror != 0, std::runtime_error,
02411             ": nonlocal entries correspond to invalid rows."
02412             << endl << os.str ());
02413         }
02414       }
02415 
02416       // build up a list of neighbors, as well as a map between NLRs and Ids
02417       // localNeighbors[i] != 0 iff I have data to send to image i
02418       // put NLRs,Ids into an array of pairs
02419       IdsAndRows.reserve(NLRs.size());
02420       Array<char> localNeighbors(numImages, 0);
02421       typename Array<GO>::const_iterator nlr;
02422       typename Array<int>::const_iterator id;
02423       for (nlr = NLRs.begin(), id = NLRIds.begin();
02424            nlr != NLRs.end(); ++nlr, ++id) {
02425         NLR2Id[*nlr] = *id;
02426         localNeighbors[*id] = 1;
02427         // IdsAndRows.push_back(make_pair<int,GlobalOrdinal>(*id,*nlr));
02428         IdsAndRows.push_back(make_pair(*id,*nlr));
02429       }
02430       for (int j=0; j<numImages; ++j) {
02431         if (localNeighbors[j]) {
02432           sendIDs.push_back(j);
02433         }
02434       }
02435       // sort IdsAndRows, by Ids first, then rows
02436       std::sort(IdsAndRows.begin(),IdsAndRows.end());
02437       // gather from other nodes to form the full graph
02438       globalNeighbors.shapeUninitialized(numImages,numImages);
02439       gatherAll (*getComm(), numImages, localNeighbors.getRawPtr(),
02440                  numImages * numImages, globalNeighbors.values());
02441       // globalNeighbors at this point contains (on all images) the
02442       // connectivity between the images.
02443       // globalNeighbors(i,j) != 0 means that j sends to i/that i receives from j
02444     }
02445 
02447     // FIGURE OUT WHO IS SENDING TO WHOM AND HOW MUCH
02448     // DO THIS IN THE PROCESS OF PACKING ALL OUTGOING DATA ACCORDING TO DESTINATION ID
02450 
02451     // loop over all columns to know from which images I can expect to receive something
02452     for (int j=0; j<numImages; ++j) {
02453       if (globalNeighbors(myImageID,j)) {
02454         recvIDs.push_back(j);
02455       }
02456     }
02457     const size_t numRecvs = recvIDs.size();
02458 
02459     // we know how many we're sending to already
02460     // form a contiguous list of all data to be sent
02461     // track the number of entries for each ID
02462     Array<pair<GO, GO> > IJSendBuffer;
02463     Array<size_t> sendSizes(sendIDs.size(), 0);
02464     size_t numSends = 0;
02465     for (typename Array<pair<int, GO> >::const_iterator IdAndRow = IdsAndRows.begin();
02466          IdAndRow != IdsAndRows.end(); ++IdAndRow) {
02467       int id = IdAndRow->first;
02468       GO row = IdAndRow->second;
02469       // have we advanced to a new send?
02470       if (sendIDs[numSends] != id) {
02471         numSends++;
02472         TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(sendIDs[numSends] != id,
02473           std::logic_error, ": internal logic error. Contact Tpetra team.");
02474       }
02475       // copy data for row into contiguous storage
02476       for (typename std::vector<GO>::const_iterator j = nonlocals_[row].begin(); j != nonlocals_[row].end(); ++j)
02477       {
02478         IJSendBuffer.push_back( pair<GlobalOrdinal,GlobalOrdinal>(row,*j) );
02479         sendSizes[numSends]++;
02480       }
02481     }
02482     if (IdsAndRows.size() > 0) {
02483       numSends++; // one last increment, to make it a count instead of an index
02484     }
02485     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(as<typename Array<int>::size_type>(numSends) != sendIDs.size(), std::logic_error, ": internal logic error. Contact Tpetra team.");
02486 
02487     // don't need this data anymore
02488     nonlocals_.clear();
02489 
02491     // TRANSMIT SIZE INFO BETWEEN SENDERS AND RECEIVERS
02493 
02494     // Array of pending nonblocking communication requests.  It's OK
02495     // to mix nonblocking send and receive requests in the same
02496     // waitAll() call.
02497     Array<RCP<Teuchos::CommRequest<int> > > requests;
02498 
02499     // perform non-blocking sends: send sizes to our recipients
02500     for (size_t s = 0; s < numSends ; ++s) {
02501       // We're using a nonowning RCP because all communication
02502       // will be local to this method and the scope of our data
02503       requests.push_back (isend<int, size_t> (*comm,
02504                                               rcp (&sendSizes[s], false),
02505                                               sendIDs[s]));
02506     }
02507     // perform non-blocking receives: receive sizes from our senders
02508     Array<size_t> recvSizes (numRecvs);
02509     for (size_t r = 0; r < numRecvs; ++r) {
02510       // We're using a nonowning RCP because all communication
02511       // will be local to this method and the scope of our data
02512       requests.push_back (ireceive (*comm, rcp (&recvSizes[r], false), recvIDs[r]));
02513     }
02514     // Wait on all the nonblocking sends and receives.
02515     if (! requests.empty()) {
02516       waitAll (*comm, requests());
02517     }
02518 #ifdef HAVE_TPETRA_DEBUG
02519     Teuchos::barrier (*comm);
02520 #endif // HAVE_TPETRA_DEBUG
02521 
02522     // This doesn't necessarily deallocate the array.
02523     requests.resize (0);
02524 
02526     // NOW SEND/RECEIVE ALL ROW DATA
02528     // from the size info, build the ArrayViews into IJSendBuffer
02529     Array<ArrayView<pair<GO,GO> > > sendBuffers(numSends,null);
02530     {
02531       size_t cur = 0;
02532       for (size_t s=0; s<numSends; ++s) {
02533         sendBuffers[s] = IJSendBuffer(cur,sendSizes[s]);
02534         cur += sendSizes[s];
02535       }
02536     }
02537     // perform non-blocking sends
02538     for (size_t s=0; s < numSends ; ++s)
02539     {
02540       // We're using a nonowning RCP because all communication
02541       // will be local to this method and the scope of our data
02542       ArrayRCP<pair<GO,GO> > tmpSendBuf =
02543         arcp (sendBuffers[s].getRawPtr(), 0, sendBuffers[s].size(), false);
02544       requests.push_back (isend<int, pair<GO,GO> > (*comm, tmpSendBuf, sendIDs[s]));
02545     }
02546     // calculate amount of storage needed for receives
02547     // setup pointers for the receives as well
02548     size_t totalRecvSize = std::accumulate (recvSizes.begin(), recvSizes.end(), 0);
02549     Array<pair<GO,GO> > IJRecvBuffer (totalRecvSize);
02550     // from the size info, build the ArrayViews into IJRecvBuffer
02551     Array<ArrayView<pair<GO,GO> > > recvBuffers (numRecvs, null);
02552     {
02553       size_t cur = 0;
02554       for (size_t r=0; r<numRecvs; ++r) {
02555         recvBuffers[r] = IJRecvBuffer(cur,recvSizes[r]);
02556         cur += recvSizes[r];
02557       }
02558     }
02559     // perform non-blocking recvs
02560     for (size_t r = 0; r < numRecvs; ++r) {
02561       // We're using a nonowning RCP because all communication
02562       // will be local to this method and the scope of our data
02563       ArrayRCP<pair<GO,GO> > tmpRecvBuf =
02564         arcp (recvBuffers[r].getRawPtr(), 0, recvBuffers[r].size(), false);
02565       requests.push_back (ireceive (*comm, tmpRecvBuf, recvIDs[r]));
02566     }
02567     // perform waits
02568     if (! requests.empty()) {
02569       waitAll (*comm, requests());
02570     }
02571 #ifdef HAVE_TPETRA_DEBUG
02572     Teuchos::barrier (*comm);
02573 #endif // HAVE_TPETRA_DEBUG
02574 
02576     // NOW PROCESS THE RECEIVED ROW DATA
02578     // TODO: instead of adding one entry at a time, add one row at a time.
02579     //       this requires resorting; they arrived sorted by sending node,
02580     //       so that entries could be non-contiguous if we received
02581     //       multiple entries for a particular row from different processors.
02582     //       it also requires restoring the data, which may make it not worth the trouble.
02583     for (typename Array<pair<GO,GO> >::const_iterator ij = IJRecvBuffer.begin();
02584          ij != IJRecvBuffer.end(); ++ij)
02585     {
02586       insertGlobalIndicesFiltered (ij->first, tuple<GO> (ij->second));
02587     }
02588     checkInternalState();
02589   }
02590 
02591 
02594   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02595   void
02596   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02597   resumeFill (const RCP<ParameterList> &params)
02598   {
02599     const char tfecfFuncName[] = "resumeFill";
02600     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(! hasRowInfo(), std::runtime_error,
02601       ": Sorry, you cannot resume fill of the CrsGraph, since the graph's row "
02602       "information was deleted in fillComplete().");
02603 
02604 #ifdef HAVE_TPETRA_DEBUG
02605     Teuchos::barrier( *rowMap_->getComm() );
02606 #endif // HAVE_TPETRA_DEBUG
02607     clearGlobalConstants();
02608     lclGraph_ = null;
02609     if (params != null) this->setParameterList (params);
02610     lowerTriangular_  = false;
02611     upperTriangular_  = false;
02612     // either still sorted/merged or initially sorted/merged
02613     indicesAreSorted_ = true;
02614     noRedundancies_ = true;
02615     fillComplete_ = false;
02616 #ifdef HAVE_TPETRA_DEBUG
02617     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02618       ! isFillActive() || isFillComplete(), std::logic_error,
02619       "::resumeFill(): At end of method, either fill is not active or fill is "
02620       "complete.  This violates stated post-conditions.  Please report this bug "
02621       "to the Tpetra developers.");
02622 #endif // HAVE_TPETRA_DEBUG
02623   }
02624 
02625 
02626   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02627   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02628   fillComplete (const Teuchos::RCP<Teuchos::ParameterList>& params)
02629   {
02630     // If the graph already has domain and range Maps, don't clobber
02631     // them.  If it doesn't, use the current row Map for both the
02632     // domain and range Maps.
02633     //
02634     // NOTE (mfh 28 Sep 2014): If the graph was constructed without a
02635     // column Map, and column indices are inserted which are not in
02636     // the row Map on any process, this will cause troubles.  However,
02637     // that is not a common case for most applications that we
02638     // encounter, and checking for it might require more
02639     // communication.
02640     Teuchos::RCP<const map_type> domMap = this->getDomainMap ();
02641     if (domMap.is_null ()) {
02642       domMap = this->getRowMap ();
02643     }
02644     Teuchos::RCP<const map_type> ranMap = this->getRangeMap ();
02645     if (ranMap.is_null ()) {
02646       ranMap = this->getRowMap ();
02647     }
02648     this->fillComplete (domMap, ranMap, params);
02649   }
02650 
02651 
02652   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02653   void
02654   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02655   fillComplete (const Teuchos::RCP<const map_type>& domainMap,
02656                 const Teuchos::RCP<const map_type>& rangeMap,
02657                 const Teuchos::RCP<Teuchos::ParameterList>& params)
02658   {
02659     const char tfecfFuncName[] = "fillComplete";
02660 
02661 #ifdef HAVE_TPETRA_DEBUG
02662     rowMap_->getComm ()->barrier ();
02663 #endif // HAVE_TPETRA_DEBUG
02664 
02665     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( ! isFillActive() || isFillComplete(),
02666       std::runtime_error, ": Graph fill state must be active (isFillActive() "
02667       "must be true) before calling fillComplete().");
02668 
02669     const int numProcs = getComm ()->getSize ();
02670 
02671     //
02672     // Read and set parameters
02673     //
02674 
02675     // Does the caller want to sort remote GIDs (within those owned by
02676     // the same process) in makeColMap()?
02677     if (! params.is_null ()) {
02678       if (params->isParameter ("sort column map ghost gids")) {
02679         sortGhostsAssociatedWithEachProcessor_ =
02680           params->get<bool> ("sort column map ghost gids",
02681                              sortGhostsAssociatedWithEachProcessor_);
02682       }
02683       else if (params->isParameter ("Sort column Map ghost GIDs")) {
02684         sortGhostsAssociatedWithEachProcessor_ =
02685           params->get<bool> ("Sort column Map ghost GIDs",
02686                              sortGhostsAssociatedWithEachProcessor_);
02687       }
02688     }
02689 
02690     // If true, the caller promises that no process did nonlocal
02691     // changes since the last call to fillComplete.
02692     bool assertNoNonlocalInserts = false;
02693     if (! params.is_null ()) {
02694       assertNoNonlocalInserts =
02695         params->get<bool> ("No Nonlocal Changes", assertNoNonlocalInserts);
02696     }
02697 
02698     //
02699     // Allocate indices, if they haven't already been allocated
02700     //
02701     if (! indicesAreAllocated ()) {
02702       if (hasColMap ()) {
02703         // We have a column Map, so use local indices.
02704         allocateIndices (LocalIndices);
02705       } else {
02706         // We don't have a column Map, so use global indices.
02707         allocateIndices (GlobalIndices);
02708       }
02709     }
02710 
02711     //
02712     // Do global assembly, if requested and if the communicator
02713     // contains more than one process.
02714     //
02715     const bool mayNeedGlobalAssemble = ! assertNoNonlocalInserts && numProcs > 1;
02716     if (mayNeedGlobalAssemble) {
02717       // This first checks if we need to do global assembly.
02718       // The check costs a single all-reduce.
02719       globalAssemble ();
02720     }
02721     else {
02722       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02723         numProcs > 1 && nonlocals_.size() > 0, std::runtime_error,
02724         ":" << std::endl << "The graph's communicator contains only one "
02725         "process, but there are nonlocal entries.  " << std::endl <<
02726         "This probably means that invalid entries were added to the graph.");
02727     }
02728 
02729     // Set domain and range Map.  This may clear the Import / Export
02730     // objects if the new Maps differ from any old ones.
02731     setDomainRangeMaps (domainMap, rangeMap);
02732 
02733     // If the graph does not already have a column Map (either from
02734     // the user constructor calling the version of the constructor
02735     // that takes a column Map, or from a previous fillComplete call),
02736     // then create it.
02737     if (! hasColMap ()) {
02738       makeColMap ();
02739     }
02740 
02741     // Make indices local, if they aren't already.
02742     // The method doesn't do any work if the indices are already local.
02743     makeIndicesLocal ();
02744 
02745     if (! isSorted ()) {
02746       // If this process has no indices, then CrsGraph considers it
02747       // already trivially sorted.  Thus, this method need not be
02748       // called on all processes in the row Map's communicator.
02749       sortAllIndices ();
02750     }
02751     if (! isMerged ()) {
02752       mergeAllIndices ();
02753     }
02754     makeImportExport(); // Make Import and Export objects, if necessary
02755     computeGlobalConstants ();
02756     fillLocalGraph (params);
02757     fillComplete_ = true;
02758 
02759 #ifdef HAVE_TPETRA_DEBUG
02760     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02761       isFillActive() == true || isFillComplete() == false, std::logic_error,
02762       ": Violated stated post-conditions. Please contact Tpetra team.");
02763 #endif
02764 
02765     checkInternalState ();
02766   }
02767 
02768 
02771   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02772   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::expertStaticFillComplete(const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > & domainMap,
02773                                                                                        const RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> > & rangeMap,
02774                                                                                        const RCP<const Import<LocalOrdinal,GlobalOrdinal,Node> > &importer,
02775                                                                                        const RCP<const Export<LocalOrdinal,GlobalOrdinal,Node> > &exporter,
02776                                                                                        const RCP<ParameterList> &params)
02777   {
02778 #ifdef HAVE_TPETRA_DEBUG
02779     rowMap_->getComm ()->barrier ();
02780 #endif // HAVE_TPETRA_DEBUG
02781     const char tfecfFuncName[] = "expertStaticFillComplete()";
02782     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( isFillComplete() == true || hasColMap() == false,
02783                                            std::runtime_error, ": fillComplete cannot have already been called and a ColMap is required.");
02784 
02785     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( getNodeNumRows() > 0 && rowPtrs_==Teuchos::null,
02786                                            std::runtime_error, ": a matrix will getNodeNumRows()>0 requires rowptr to be set.");
02787 
02788     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( domainMap == Teuchos::null || rangeMap == Teuchos::null,
02789                                            std::runtime_error, ": requires a non-null domainMap & rangeMap.");
02790 
02791     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( pftype_ !=StaticProfile,
02792                                            std::runtime_error, ": requires StaticProfile.");
02793 
02794     // Note: We don't need to do the following things which are normally done in fillComplete:
02795     // allocateIndices, globalAssemble, makeColMap, makeIndicesLocal, sortAllIndices, mergeAllIndices
02796 
02797     // Note: Need to do this so computeGlobalConstants & fillLocalGraph work
02798     nodeNumEntries_ = nodeNumAllocated_ = rowPtrs_[getNodeNumRows()];
02799 
02800     // Constants from allocateIndices
02801     numAllocForAllRows_  = 0;
02802     numAllocPerRow_      = null;
02803     indicesAreAllocated_ = true;
02804 
02805     // Constants from makeIndicesLocal
02806     indicesAreLocal_  = true;
02807     indicesAreGlobal_ = false;
02808 
02809     // set domain/range map: may clear the import/export objects
02810     setDomainRangeMaps(domainMap,rangeMap);
02811 
02812     // Presume the user sorted and merged the arrays first
02813     indicesAreSorted_ = true;
02814     noRedundancies_ = true;
02815 
02816     // makeImportExport won't create a new importer/exporter if I set one here first.
02817     importer_=Teuchos::null;
02818     exporter_=Teuchos::null;
02819     if(importer != Teuchos::null) {
02820       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(!importer->getSourceMap()->isSameAs(*getDomainMap()) || !importer->getTargetMap()->isSameAs(*getColMap()),
02821                                             std::invalid_argument,": importer does not match matrix maps.");
02822       importer_ = importer;
02823 
02824     }
02825     if(exporter != Teuchos::null) {
02826       TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(!exporter->getSourceMap()->isSameAs(*getRowMap()) || !exporter->getTargetMap()->isSameAs(*getRangeMap()),
02827                                             std::invalid_argument,": exporter does not match matrix maps.");
02828       exporter_ = exporter;
02829     }
02830     makeImportExport();
02831 
02832     // Compute the constants
02833     computeGlobalConstants();
02834 
02835     // Since we have a StaticProfile, fillLocalGraph will do the right thing...
02836     fillLocalGraph(params);
02837     fillComplete_ = true;
02838 
02839 #ifdef HAVE_TPETRA_DEBUG
02840     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC( isFillActive() == true || isFillComplete() == false, std::logic_error, ": Violated stated post-conditions. Please contact Tpetra team.");
02841 #endif
02842     checkInternalState();
02843   }
02844 
02845 
02846 
02849   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02850   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::fillLocalGraph(const RCP<ParameterList> &params)
02851   {
02852     using Teuchos::ArrayRCP;
02853     using Teuchos::null;
02854     using Teuchos::ParameterList;
02855     using Teuchos::parameterList;
02856     using Teuchos::RCP;
02857     using Teuchos::sublist;
02858 
02859     const size_t numRows = getNodeNumRows ();
02860     ArrayRCP<size_t> ptrs;
02861     ArrayRCP<LocalOrdinal> inds;
02862     bool requestOptimizedStorage = true;
02863     if (params != null && params->get ("Optimize Storage", true) == false) {
02864       requestOptimizedStorage = false;
02865     }
02866 
02867     RCP<Node> node = getRowMap ()->getNode ();
02868     if (getProfileType () == DynamicProfile) {
02869       // Storage is currently in 2-D ("array of arrays") format.
02870       // Pack into 1-D packed storage.
02871       ptrs = sparse_ops_type::allocRowPtrs (node, numRowEntries_ ());
02872       inds = sparse_ops_type::template allocStorage<LocalOrdinal> (node, ptrs ());
02873       for (size_t row = 0; row < numRows; ++row) {
02874         const size_t numentrs = numRowEntries_[row];
02875         std::copy (lclInds2D_[row].begin (),
02876                    lclInds2D_[row].begin () + numentrs,
02877                    inds + ptrs[row]);
02878       }
02879     }
02880     else if (getProfileType () == StaticProfile) {
02881       // We already have 1-D storage, but it might not yet be packed.
02882       if (nodeNumEntries_ != nodeNumAllocated_) { // need to pack storage
02883         ptrs = sparse_ops_type::allocRowPtrs (node, numRowEntries_ ());
02884         inds = sparse_ops_type::template allocStorage<LocalOrdinal> (node, ptrs ());
02885         for (size_t row = 0; row < numRows; ++row) {
02886           const size_t numentrs = numRowEntries_[row];
02887           std::copy (lclInds1D_ + rowPtrs_[row],
02888                      lclInds1D_ + rowPtrs_[row] + numentrs,
02889                      inds + ptrs[row]);
02890         }
02891       }
02892       else { // don't need to pack storage
02893         inds = lclInds1D_;
02894         ptrs = rowPtrs_;
02895       }
02896     }
02897     // can we ditch the old allocations for the packed one?
02898     if (requestOptimizedStorage) {
02899       lclInds2D_ = null;
02900       numRowEntries_ = null;
02901       // keep the new stuff
02902       lclInds1D_ = inds;
02903       rowPtrs_ = ptrs;
02904       nodeNumAllocated_ = nodeNumEntries_;
02905       pftype_ = StaticProfile;
02906     }
02907     // build the local graph, hand over the indices
02908     RCP<ParameterList> lclparams = params.is_null () ?
02909       parameterList () :
02910       sublist (params, "Local Graph");
02911     lclGraph_ =
02912       rcp (new local_graph_type (getRowMap ()->getNodeNumElements (),
02913                                  getColMap ()->getNodeNumElements (),
02914                                  getRowMap ()->getNode (), lclparams));
02915     lclGraph_->setStructure (ptrs, inds);
02916     ptrs = null;
02917     inds = null;
02918     // finalize local graph
02919     const Teuchos::EDiag diag = getNodeNumDiags () < getNodeNumRows () ?
02920       Teuchos::UNIT_DIAG : Teuchos::NON_UNIT_DIAG;
02921     Teuchos::EUplo uplo = Teuchos::UNDEF_TRI;
02922     if (isUpperTriangular ()) {
02923       uplo = Teuchos::UPPER_TRI;
02924     }
02925     else if (isLowerTriangular ()) {
02926       uplo = Teuchos::LOWER_TRI;
02927     }
02928     sparse_ops_type::finalizeGraph (uplo, diag, *lclGraph_, params);
02929   }
02930 
02931 
02932   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02933   void
02934   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02935   replaceColMap (const Teuchos::RCP<const map_type>& newColMap)
02936   {
02937     // NOTE: This safety check matches the code, but not the documentation of Crsgraph
02938     //
02939     // FIXME (mfh 18 Aug 2014) This will break if the calling process
02940     // has no entries, because in that case, it is neither locally nor
02941     // globally indexed.
02942     const char tfecfFuncName[] = "replaceColMap: ";
02943     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02944       isLocallyIndexed () || isGloballyIndexed (), std::runtime_error,
02945       "Requires matching maps and non-static graph.");
02946     colMap_ = newColMap;
02947   }
02948 
02949 
02950   template <class LocalOrdinal, class GlobalOrdinal, class Node>
02951   void
02952   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
02953   reindexColumns (const Teuchos::RCP<const map_type>& newColMap,
02954                   const Teuchos::RCP<const import_type>& newImport,
02955                   const bool sortIndicesInEachRow)
02956   {
02957     using Teuchos::REDUCE_MIN;
02958     using Teuchos::reduceAll;
02959     using Teuchos::RCP;
02960     typedef GlobalOrdinal GO;
02961     typedef LocalOrdinal LO;
02962     const char tfecfFuncName[] = "reindexColumns: ";
02963 
02964     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
02965       isFillComplete (), std::runtime_error, "The graph is fill complete "
02966       "(isFillComplete() returns true).  You must call resumeFill() before "
02967       "you may call this method.");
02968 
02969     // mfh 19 Aug 2014: This method does NOT redistribute data; it
02970     // doesn't claim to do the work of an Import or Export.  This
02971     // means that for all processes, the calling process MUST own all
02972     // column indices, in both the old column Map (if it exists) and
02973     // the new column Map.  We check this via an all-reduce.
02974     //
02975     // Some processes may be globally indexed, others may be locally
02976     // indexed, and others (that have no graph entries) may be
02977     // neither.  This method will NOT change the graph's current
02978     // state.  If it's locally indexed, it will stay that way, and
02979     // vice versa.  It would easy to add an option to convert indices
02980     // from global to local, so as to save a global-to-local
02981     // conversion pass.  However, we don't do this here.  The intended
02982     // typical use case is that the graph already has a column Map and
02983     // is locally indexed, and this is the case for which we optimize.
02984 
02985     const size_t lclNumRows = getNodeNumRows ();
02986 
02987     // Attempt to convert indices to the new column Map's version of
02988     // local.  This will fail if on the calling process, the graph has
02989     // indices that are not on that process in the new column Map.
02990     // After the local conversion attempt, we will do an all-reduce to
02991     // see if any processes failed.
02992 
02993     // If this is false, then either the graph contains a column index
02994     // which is invalid in the CURRENT column Map, or the graph is
02995     // locally indexed but currently has no column Map.  In either
02996     // case, there is no way to convert the current local indices into
02997     // global indices, so that we can convert them into the new column
02998     // Map's local indices.  It's possible for this to be true on some
02999     // processes but not others, due to replaceColMap.
03000     bool allCurColIndsValid = true;
03001     // On the calling process, are all valid current column indices
03002     // also in the new column Map on the calling process?  In other
03003     // words, does local reindexing suffice, or should the user have
03004     // done an Import or Export instead?
03005     bool localSuffices = true;
03006 
03007     // Final arrays for the local indices.  We will allocate exactly
03008     // one of these ONLY if the graph is locally indexed on the
03009     // calling process, and ONLY if the graph has one or more entries
03010     // (is not empty) on the calling process.  In that case, we
03011     // allocate the first (1-D storage) if the graph has a static
03012     // profile, else we allocate the second (2-D storage).
03013     Teuchos::ArrayRCP<LO> newLclInds1D;
03014     Teuchos::ArrayRCP<Teuchos::Array<LO> > newLclInds2D;
03015 
03016     // If indices aren't allocated, that means the calling process
03017     // owns no entries in the graph.  Thus, there is nothing to
03018     // convert, and it trivially succeeds locally.
03019     if (indicesAreAllocated ()) {
03020       if (isLocallyIndexed ()) {
03021         if (hasColMap ()) { // locally indexed, and currently has a column Map
03022           const map_type& oldColMap = * (getColMap ());
03023           if (pftype_ == StaticProfile) {
03024             // Allocate storage for the new local indices.
03025             RCP<Node> node = getRowMap ()->getNode ();
03026             newLclInds1D =
03027               sparse_ops_type::template allocStorage<LO> (node, rowPtrs_ ());
03028 
03029             // Attempt to convert the new indices locally.
03030             for (size_t lclRow = 0; lclRow < lclNumRows; ++lclRow) {
03031               const RowInfo rowInfo = getRowInfo (lclRow);
03032               const size_t beg = rowInfo.offset1D;
03033               const size_t end = beg + rowInfo.numEntries;
03034               for (size_t k = beg; k < end; ++k) {
03035                 const LO oldLclCol = lclInds1D_[k];
03036                 if (oldLclCol == Teuchos::OrdinalTraits<LO>::invalid ()) {
03037                   allCurColIndsValid = false;
03038                   break; // Stop at the first invalid index
03039                 }
03040                 const GO gblCol = oldColMap.getGlobalElement (oldLclCol);
03041 
03042                 // The above conversion MUST succeed.  Otherwise, the
03043                 // current local index is invalid, which means that
03044                 // the graph was constructed incorrectly.
03045                 if (gblCol == Teuchos::OrdinalTraits<GO>::invalid ()) {
03046                   allCurColIndsValid = false;
03047                   break; // Stop at the first invalid index
03048                 }
03049                 else {
03050                   const LO newLclCol = newColMap->getLocalElement (gblCol);
03051                   if (newLclCol == Teuchos::OrdinalTraits<LO>::invalid ()) {
03052                     localSuffices = false;
03053                     break; // Stop at the first invalid index
03054                   }
03055                   newLclInds1D[k] = newLclCol;
03056                 }
03057               } // for each entry in the current row
03058             } // for each locally owned row
03059           }
03060           else { // pftype_ == DynamicProfile
03061             // Allocate storage for the new local indices.  We only
03062             // allocate the outer array here; we will allocate the
03063             // inner arrays below.
03064             newLclInds2D = Teuchos::arcp<Teuchos::Array<LO> > (lclNumRows);
03065 
03066             // Attempt to convert the new indices locally.
03067             for (size_t lclRow = 0; lclRow < lclNumRows; ++lclRow) {
03068               const RowInfo rowInfo = getRowInfo (lclRow);
03069               newLclInds2D.resize (rowInfo.allocSize);
03070 
03071               Teuchos::ArrayView<const LO> oldLclRowView = getLocalView (rowInfo);
03072               Teuchos::ArrayView<LO> newLclRowView = (newLclInds2D[lclRow]) ();
03073 
03074               for (size_t k = 0; k < rowInfo.numEntries; ++k) {
03075                 const LO oldLclCol = oldLclRowView[k];
03076                 if (oldLclCol == Teuchos::OrdinalTraits<LO>::invalid ()) {
03077                   allCurColIndsValid = false;
03078                   break; // Stop at the first invalid index
03079                 }
03080                 const GO gblCol = oldColMap.getGlobalElement (oldLclCol);
03081 
03082                 // The above conversion MUST succeed.  Otherwise, the
03083                 // local index is invalid and the graph is wrong.
03084                 if (gblCol == Teuchos::OrdinalTraits<GO>::invalid ()) {
03085                   allCurColIndsValid = false;
03086                   break; // Stop at the first invalid index
03087                 }
03088                 else {
03089                   const LO newLclCol = newColMap->getLocalElement (gblCol);
03090                   if (newLclCol == Teuchos::OrdinalTraits<LO>::invalid ()) {
03091                     localSuffices = false;
03092                     break; // Stop at the first invalid index.
03093                   }
03094                   newLclRowView[k] = newLclCol;
03095                 }
03096               } // for each entry in the current row
03097             } // for each locally owned row
03098           } // pftype_
03099         }
03100         else { // locally indexed, but no column Map
03101           // This case is only possible if replaceColMap() was called
03102           // with a null argument on the calling process.  It's
03103           // possible, but it means that this method can't possibly
03104           // succeed, since we have no way of knowing how to convert
03105           // the current local indices to global indices.
03106           allCurColIndsValid = false;
03107         }
03108       }
03109       else { // globally indexed
03110         // If the graph is globally indexed, we don't need to save
03111         // local indices, but we _do_ need to know whether the current
03112         // global indices are valid in the new column Map.  We may
03113         // need to do a getRemoteIndexList call to find this out.
03114         //
03115         // In this case, it doesn't matter whether the graph currently
03116         // has a column Map.  We don't need the old column Map to
03117         // convert from global indices to the _new_ column Map's local
03118         // indices.  Furthermore, we can use the same code, whether
03119         // the graph is static or dynamic profile.
03120 
03121         // Test whether the current global indices are in the new
03122         // column Map on the calling process.
03123         for (size_t lclRow = 0; lclRow < lclNumRows; ++lclRow) {
03124           const RowInfo rowInfo = getRowInfo (lclRow);
03125           Teuchos::ArrayView<const GO> oldGblRowView = getGlobalView (rowInfo);
03126           for (size_t k = 0; k < rowInfo.numEntries; ++k) {
03127             const GO gblCol = oldGblRowView[k];
03128             if (! newColMap->isNodeGlobalElement (gblCol)) {
03129               localSuffices = false;
03130               break; // Stop at the first invalid index
03131             }
03132           } // for each entry in the current row
03133         } // for each locally owned row
03134       } // locally or globally indexed
03135     } // whether indices are allocated
03136 
03137     // Do an all-reduce to check both possible error conditions.
03138     int lclSuccess[2];
03139     lclSuccess[0] = allCurColIndsValid ? 1 : 0;
03140     lclSuccess[1] = localSuffices ? 1 : 0;
03141     int gblSuccess[2];
03142     gblSuccess[0] = 0;
03143     gblSuccess[1] = 0;
03144     RCP<const Teuchos::Comm<int> > comm =
03145       getRowMap ().is_null () ? Teuchos::null : getRowMap ()->getComm ();
03146     if (! comm.is_null ()) {
03147       reduceAll<int, int> (*comm, REDUCE_MIN, 2, lclSuccess, gblSuccess);
03148     }
03149 
03150     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03151       gblSuccess[0] == 0, std::runtime_error, "It is not possible to continue."
03152       "  The most likely reason is that the graph is locally indexed, but the "
03153       "column Map is missing (null) on some processes, due to a previous call "
03154       "to replaceColMap().");
03155 
03156     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03157       gblSuccess[1] == 0, std::runtime_error, "On some process, the graph "
03158       "contains column indices that are in the old column Map, but not in the "
03159       "new column Map (on that process).  This method does NOT redistribute "
03160       "data; it does not claim to do the work of an Import or Export operation."
03161       "  This means that for all processess, the calling process MUST own all "
03162       "column indices, in both the old column Map and the new column Map.  In "
03163       "this case, you will need to do an Import or Export operation to "
03164       "redistribute data.");
03165 
03166     // Commit the results.
03167     if (isLocallyIndexed ()) {
03168       if (pftype_ == StaticProfile) {
03169         lclInds1D_ = newLclInds1D;
03170       } else { // dynamic profile
03171         lclInds2D_ = newLclInds2D;
03172       }
03173       // We've reindexed, so we don't know if the indices are sorted.
03174       //
03175       // FIXME (mfh 17 Sep 2014) It could make sense to check this,
03176       // since we're already going through all the indices above.  We
03177       // could also sort each row in place; that way, we would only
03178       // have to make one pass over the rows.
03179       indicesAreSorted_ = false;
03180       if (sortIndicesInEachRow) {
03181         // NOTE (mfh 17 Sep 2014) The graph must be locally indexed in
03182         // order to call this method.
03183         //
03184         // FIXME (mfh 17 Sep 2014) This violates the strong exception
03185         // guarantee.  It would be better to sort the new index arrays
03186         // before committing them.
03187         sortAllIndices ();
03188       }
03189     }
03190     colMap_ = newColMap;
03191 
03192     if (newImport.is_null ()) {
03193       // FIXME (mfh 19 Aug 2014) Should use the above all-reduce to
03194       // check whether the input Import is null on any process.
03195       //
03196       // If the domain Map hasn't been set yet, we can't compute a new
03197       // Import object.  Leave it what it is; it should be null, but
03198       // it doesn't matter.  If the domain Map _has_ been set, then
03199       // compute a new Import object if necessary.
03200       if (! domainMap_.is_null ()) {
03201         if (! domainMap_->isSameAs (* newColMap)) {
03202           importer_ = Teuchos::rcp (new import_type (domainMap_, newColMap));
03203         } else {
03204           importer_ = Teuchos::null; // don't need an Import
03205         }
03206       }
03207     } else {
03208       // The caller gave us an Import object.  Assume that it's valid.
03209       importer_ = newImport;
03210     }
03211   }
03212 
03213 
03216   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03217   void
03218   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
03219   replaceDomainMapAndImporter (const Teuchos::RCP<const map_type>& newDomainMap,
03220                                const Teuchos::RCP<const import_type>& newImporter)
03221   {
03222     const char prefix[] = "Tpetra::CrsGraph::replaceDomainMapAndImporter: ";
03223     TEUCHOS_TEST_FOR_EXCEPTION(
03224       colMap_.is_null (), std::invalid_argument, prefix << "You may not call "
03225       "this method unless the graph already has a column Map.");
03226     TEUCHOS_TEST_FOR_EXCEPTION(
03227       newDomainMap.is_null (), std::invalid_argument,
03228       prefix << "The new domain Map must be nonnull.");
03229 
03230 #ifdef HAVE_TPETRA_DEBUG
03231     if (newImporter.is_null ()) {
03232       // It's not a good idea to put expensive operations in a macro
03233       // clause, even if they are side effect - free, because macros
03234       // don't promise that they won't evaluate their arguments more
03235       // than once.  It's polite for them to do so, but not required.
03236       const bool colSameAsDom = colMap_->isSameAs (*newDomainMap);
03237       TEUCHOS_TEST_FOR_EXCEPTION(
03238         colSameAsDom, std::invalid_argument, "If the new Import is null, "
03239         "then the new domain Map must be the same as the current column Map.");
03240     }
03241     else {
03242       const bool colSameAsTgt =
03243         colMap_->isSameAs (* (newImporter->getTargetMap ()));
03244       const bool newDomSameAsSrc =
03245         newDomainMap->isSameAs (* (newImporter->getSourceMap ()));
03246       TEUCHOS_TEST_FOR_EXCEPTION(
03247         ! colSameAsTgt || ! newDomSameAsSrc, std::invalid_argument, "If the "
03248         "new Import is nonnull, then the current column Map must be the same "
03249         "as the new Import's target Map, and the new domain Map must be the "
03250         "same as the new Import's source Map.");
03251     }
03252 #endif // HAVE_TPETRA_DEBUG
03253 
03254     domainMap_ = newDomainMap;
03255     importer_ = Teuchos::rcp_const_cast<import_type> (newImporter);
03256   }
03257 
03258 
03261   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03262   const Teuchos::RCP<
03263     const typename CrsGraph<
03264       LocalOrdinal, GlobalOrdinal, Node>::local_graph_type>
03265   CrsGraph<LocalOrdinal, GlobalOrdinal, Node>::
03266   getLocalGraph () const
03267   {
03268     return lclGraph_;
03269   }
03270 
03271 
03274   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03275   const Teuchos::RCP<
03276     typename CrsGraph<
03277       LocalOrdinal, GlobalOrdinal, Node>::local_graph_type>
03278   CrsGraph<LocalOrdinal, GlobalOrdinal, Node>::
03279   getLocalGraphNonConst ()
03280   {
03281     return lclGraph_;
03282   }
03283 
03284 
03287   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03288   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::computeGlobalConstants()
03289   {
03290     using Teuchos::as;
03291     using Teuchos::outArg;
03292     using Teuchos::reduceAll;
03293     typedef LocalOrdinal LO;
03294     typedef GlobalOrdinal GO;
03295     typedef global_size_t GST;
03296 
03297 #ifdef HAVE_TPETRA_DEBUG
03298     TEUCHOS_TEST_FOR_EXCEPTION(! hasColMap(), std::logic_error, "Tpetra::"
03299       "CrsGraph::computeGlobalConstants: At this point, the graph should have "
03300       "a column Map, but it does not.  Please report this bug to the Tpetra "
03301       "developers.");
03302 #endif // HAVE_TPETRA_DEBUG
03303 
03304     // If necessary, (re)compute the local constants: nodeNumDiags_,
03305     // lowerTriangular_, upperTriangular_, and nodeMaxNumRowEntries_.
03306     if (! haveLocalConstants_) {
03307       // We have actually already computed nodeNumEntries_.
03308       // nodeNumEntries_ gets updated by methods that insert or remove
03309       // indices (including setAllIndices and
03310       // expertStaticFillComplete).  Before fillComplete, its count
03311       // may include duplicate column indices in the same row.
03312       // However, mergeRowIndices and mergeRowIndicesAndValues both
03313       // subtract off merged indices in each row from the total count.
03314       // Thus, nodeNumEntries_ _should_ be accurate at this point,
03315       // meaning that we don't have to re-count it here.
03316 
03317       // Reset local properties
03318       upperTriangular_ = true;
03319       lowerTriangular_ = true;
03320       nodeMaxNumRowEntries_ = 0;
03321       nodeNumDiags_         = 0;
03322 
03323       // At this point, we know that we have both a row Map and a column Map.
03324       const Map<LO,GO,Node>& rowMap = *rowMap_;
03325       const Map<LO,GO,Node>& colMap = *colMap_;
03326 
03327       // Go through all the entries of the graph.  Count the number of
03328       // diagonal elements we encounter, and figure out whether the
03329       // graph is lower or upper triangular.  Diagonal elements are
03330       // determined using global indices, with respect to the whole
03331       // graph.  However, lower or upper triangularity is a local
03332       // property, and is determined using local indices.
03333       //
03334       // At this point, indices have already been sorted in each row.
03335       // That makes finding out whether the graph is lower / upper
03336       // triangular easier.
03337       if (indicesAreAllocated () && nodeNumAllocated_ > 0) {
03338         const size_t numLocalRows = getNodeNumRows ();
03339         for (size_t localRow = 0; localRow < numLocalRows; ++localRow) {
03340           const GO globalRow = rowMap.getGlobalElement (localRow);
03341           // Find the local (column) index for the diagonal element.
03342           const LO rlcid = colMap.getLocalElement (globalRow);
03343           RowInfo rowInfo = getRowInfo (localRow);
03344           ArrayView<const LO> rview = getLocalView (rowInfo);
03345           typename ArrayView<const LO>::iterator beg, end, cur;
03346           beg = rview.begin();
03347           end = beg + rowInfo.numEntries;
03348           if (beg != end) {
03349             for (cur = beg; cur != end; ++cur) {
03350               // is this the diagonal?
03351               if (rlcid == *cur) ++nodeNumDiags_;
03352             }
03353             // Local column indices are sorted in each row.  That means
03354             // the smallest column index in this row (on this process)
03355             // is *beg, and the largest column index in this row (on
03356             // this process) is *(end - 1).  We know that end - 1 is
03357             // valid because beg != end.
03358             const size_t smallestCol = as<size_t> (*beg);
03359             const size_t largestCol = as<size_t> (*(end - 1));
03360 
03361             if (smallestCol < localRow) {
03362               upperTriangular_ = false;
03363             }
03364             if (localRow < largestCol) {
03365               lowerTriangular_ = false;
03366             }
03367           }
03368           // Update the max number of entries over all rows.
03369           nodeMaxNumRowEntries_ = std::max (nodeMaxNumRowEntries_, rowInfo.numEntries);
03370         }
03371       }
03372       haveLocalConstants_ = true;
03373     } // if my process doesn't have local constants
03374 
03375     // Compute global constants from local constants.  Processes that
03376     // already have local constants still participate in the
03377     // all-reduces, using their previously computed values.
03378     if (haveGlobalConstants_ == false) {
03379       // Promote all the nodeNum* and nodeMaxNum* quantities from
03380       // size_t to global_size_t, when doing the all-reduces for
03381       // globalNum* / globalMaxNum* results.
03382       //
03383       // FIXME (mfh 07 May 2013) Unfortunately, we either have to do
03384       // this in two all-reduces (one for the sum and the other for
03385       // the max), or use a custom MPI_Op that combines the sum and
03386       // the max.  The latter might even be slower than two
03387       // all-reduces on modern network hardware.  It would also be a
03388       // good idea to use nonblocking all-reduces (MPI 3), so that we
03389       // don't have to wait around for the first one to finish before
03390       // starting the second one.
03391       GST lcl[2], gbl[2];
03392       lcl[0] = as<GST> (nodeNumEntries_);
03393       lcl[1] = as<GST> (nodeNumDiags_);
03394       reduceAll<int,GST> (*getComm (), Teuchos::REDUCE_SUM,
03395                           2, lcl, gbl);
03396       globalNumEntries_ = gbl[0];
03397       globalNumDiags_   = gbl[1];
03398       reduceAll<int,GST> (*getComm (), Teuchos::REDUCE_MAX,
03399                           as<GST> (nodeMaxNumRowEntries_),
03400                           outArg (globalMaxNumRowEntries_));
03401       haveGlobalConstants_ = true;
03402     }
03403   }
03404 
03405 
03408   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03409   void
03410   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::makeIndicesLocal ()
03411   {
03412     typedef LocalOrdinal LO;
03413     typedef GlobalOrdinal GO;
03414 #ifdef HAVE_TPETRA_DEBUG
03415     const char tfecfFuncName[] = "makeIndicesLocal";
03416 #endif // HAVE_TPETRA_DEBUG
03417 
03418     // Transform indices to local index space
03419     const size_t nlrs = getNodeNumRows ();
03420     if (isGloballyIndexed () && nlrs > 0) {
03421       // allocate data for local indices
03422       if (getProfileType() == StaticProfile) {
03423         // If GO and LO are the same size, we can reuse the existing
03424         // array of 1-D index storage to convert column indices from
03425         // GO to LO.  Otherwise, we'll just allocate a new buffer.
03426         if (nodeNumAllocated_ && sizeof (LO) == sizeof (GO)) {
03427           lclInds1D_ = arcp_reinterpret_cast<LO> (gblInds1D_).persistingView (0, nodeNumAllocated_);
03428         }
03429         else {
03430           lclInds1D_ = sparse_ops_type::template allocStorage<LO> (getRowMap ()->getNode (), rowPtrs_ ());
03431         }
03432         for (size_t r = 0; r < nlrs; ++r) {
03433           const size_t offset   = rowPtrs_[r];
03434           const size_t numentry = numRowEntries_[r];
03435           for (size_t j = 0; j < numentry; ++j) {
03436             const GO gid = gblInds1D_[offset + j];
03437             const LO lid = colMap_->getLocalElement (gid);
03438             lclInds1D_[offset + j] = lid;
03439 #ifdef HAVE_TPETRA_DEBUG
03440             TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03441               lclInds1D_[offset + j] == Teuchos::OrdinalTraits<LO>::invalid(),
03442               std::logic_error,
03443               ": In local row r=" << r << ", global column " << gid << " is "
03444               "not in the column Map.  This should never happen.  Please "
03445               "report this bug to the Tpetra developers.");
03446 #endif // HAVE_TPETRA_DEBUG
03447           }
03448         }
03449         // We've converted column indices from global to local, so we
03450         // can deallocate the global column indices (which we know are
03451         // in 1-D storage, because the graph has static profile).
03452         gblInds1D_ = null;
03453       }
03454       else {  // the graph has dynamic profile (2-D index storage)
03455         lclInds2D_ = arcp<Array<LO> > (nlrs);
03456         for (size_t r = 0; r < getNodeNumRows (); ++r) {
03457           if (! gblInds2D_[r].empty ()) {
03458             const GO* const ginds = gblInds2D_[r].getRawPtr ();
03459             const size_t rna = gblInds2D_[r].size ();
03460             const size_t numentry = numRowEntries_[r];
03461             lclInds2D_[r].resize (rna);
03462             LO* const linds = lclInds2D_[r].getRawPtr ();
03463             for (size_t j = 0; j < numentry; ++j) {
03464               GO gid = ginds[j];
03465               LO lid = colMap_->getLocalElement (gid);
03466               linds[j] = lid;
03467 #ifdef HAVE_TPETRA_DEBUG
03468               TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03469                 linds[j] == Teuchos::OrdinalTraits<LO>::invalid(),
03470                 std::logic_error,
03471                 ": Global column ginds[j=" << j << "]=" << ginds[j]
03472                 << " of local row r=" << r << " is not in the column Map.  "
03473                 "This should never happen.  Please report this bug to the "
03474                 "Tpetra developers.");
03475 #endif // HAVE_TPETRA_DEBUG
03476             }
03477           }
03478         }
03479         gblInds2D_ = null;
03480       }
03481     } // globallyIndexed() && nlrs > 0
03482     indicesAreLocal_  = true;
03483     indicesAreGlobal_ = false;
03484     checkInternalState();
03485   }
03486 
03487 
03490   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03491   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::sortAllIndices()
03492   {
03493     TEUCHOS_TEST_FOR_EXCEPT(isGloballyIndexed()==true);   // this should be called only after makeIndicesLocal()
03494     if (isSorted() == false) {
03495       for (size_t row=0; row < getNodeNumRows(); ++row) {
03496         RowInfo rowInfo = getRowInfo(row);
03497         sortRowIndices(rowInfo);
03498       }
03499     }
03500     // we just sorted every row
03501     indicesAreSorted_ = true;
03502   }
03503 
03504 
03507   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03508   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::makeColMap ()
03509   {
03510     using Teuchos::Array;
03511     using Teuchos::ArrayView;
03512     using Teuchos::rcp;
03513     using Teuchos::REDUCE_MAX;
03514     using Teuchos::reduceAll;
03515     using std::endl;
03516     typedef LocalOrdinal LO;
03517     typedef GlobalOrdinal GO;
03518     const char tfecfFuncName[] = "makeColMap";
03519 
03520     if (hasColMap ()) { // The graph already has a column Map.
03521       // FIXME (mfh 26 Feb 2013): This currently prevents structure
03522       // changes that affect the column Map.
03523       return;
03524     }
03525 
03526     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03527       isLocallyIndexed (), std::runtime_error,
03528       ": The graph is locally indexed.  Calling makeColMap() to make the "
03529       "column Map requires that the graph be globally indexed.");
03530 
03531     // After the calling process is done going through all of the rows
03532     // it owns, myColumns will contain the list of indices owned by
03533     // this process in the column Map.
03534     Array<GO> myColumns;
03535 
03536     // If we reach this point, we don't have a column Map yet, so the
03537     // graph can't be locally indexed.  Thus, isGloballyIndexed() ==
03538     // false means that the graph is empty on this process, so
03539     // myColumns will be left empty.
03540     if (isGloballyIndexed ()) {
03541       // Go through all the rows, finding the populated column indices.
03542       //
03543       // Our final list of indices for the column Map constructor will
03544       // have the following properties (all of which are with respect
03545       // to the calling process):
03546       //
03547       // 1. Indices in the domain Map go first.
03548       // 2. Indices not in the domain Map follow, ordered first
03549       //    contiguously by their owning process rank (in the domain
03550       //    Map), then in increasing order within that.
03551       // 3. No duplicate indices.
03552       //
03553       // This imitates the ordering used by Aztec(OO) and Epetra.
03554       // Storing indices owned by the same process (in the domain Map)
03555       // contiguously permits the use of contiguous send and receive
03556       // buffers.
03557       //
03558       // We begin by partitioning the column indices into "local" GIDs
03559       // (owned by the domain Map) and "remote" GIDs (not owned by the
03560       // domain Map).  We use the same order for local GIDs as the
03561       // domain Map, so we track them in place in their array.  We use
03562       // an std::set (RemoteGIDSet) to keep track of remote GIDs, so
03563       // that we don't have to merge duplicates later.
03564       const LO LINV = Teuchos::OrdinalTraits<LO>::invalid ();
03565       size_t numLocalColGIDs = 0, numRemoteColGIDs = 0;
03566 
03567       // GIDisLocal[lid] == 0 if and only if local index lid in the
03568       // domain Map is remote (not local).
03569       Array<char> GIDisLocal (domainMap_->getNodeNumElements (), 0);
03570       std::set<GO> RemoteGIDSet;
03571       // This preserves the not-sorted Epetra order of GIDs.
03572       std::vector<GO> RemoteGIDUnorderedVector;
03573       const size_t myNumRows = getNodeNumRows ();
03574       for (size_t r = 0; r < myNumRows; ++r) {
03575         RowInfo rowinfo = getRowInfo (r);
03576         if (rowinfo.numEntries > 0) {
03577           // NOTE (mfh 02 Sep 2014) getGlobalView() returns a view of
03578           // all the space in the row, not just the occupied entries.
03579           // (This matters for the case of unpacked 1-D storage.  We
03580           // might not have packed it yet.)  That's why we need to
03581           // take a subview.
03582           ArrayView<const GO> rowGids = getGlobalView (rowinfo);
03583           rowGids = rowGids (0, rowinfo.numEntries);
03584 
03585           for (size_t k = 0; k < rowinfo.numEntries; ++k) {
03586             const GO gid = rowGids[k];
03587             const LO lid = domainMap_->getLocalElement (gid);
03588             if (lid != LINV) { // gid is locally owned
03589               const char alreadyFound = GIDisLocal[lid];
03590               if (alreadyFound == 0) {
03591                 GIDisLocal[lid] = static_cast<char> (1);
03592                 ++numLocalColGIDs;
03593               }
03594             }
03595             else {
03596               const bool notAlreadyFound = RemoteGIDSet.insert (gid).second;
03597               if (notAlreadyFound) { // gid did not exist in the set before
03598                 if (! sortGhostsAssociatedWithEachProcessor_) {
03599                   // The user doesn't want to sort remote GIDs (for
03600                   // each remote process); they want us to keep remote
03601                   // GIDs in their original order.  We do this by
03602                   // stuffing each remote GID into an array as we
03603                   // encounter it for the first time.  The std::set
03604                   // helpfully tracks first encounters.
03605                   RemoteGIDUnorderedVector.push_back (gid);
03606                 }
03607                 ++numRemoteColGIDs;
03608               }
03609             }
03610           } // for each entry k in row r
03611         } // if row r contains > 0 entries
03612       } // for each locally owned row r
03613 
03614       // Possible short-circuit for serial scenario:
03615       //
03616       // If all domain GIDs are present as column indices, then set
03617       // ColMap=DomainMap.  By construction, LocalGIDs is a subset of
03618       // DomainGIDs.
03619       //
03620       // If we have
03621       //   * Number of remote GIDs is 0, so that ColGIDs == LocalGIDs,
03622       // and
03623       //   * Number of local GIDs is number of domain GIDs
03624       // then
03625       //   * LocalGIDs \subset DomainGIDs && size(LocalGIDs) ==
03626       //     size(DomainGIDs) => DomainGIDs == LocalGIDs == ColGIDs
03627       // on the calling process.
03628       //
03629       // We will concern ourselves only with the special case of a
03630       // serial DomainMap, obviating the need for communication.
03631       //
03632       // If
03633       //   * DomainMap has a serial communicator
03634       // then we can set the column Map as the domain Map
03635       // return. Benefit: this graph won't need an Import object
03636       // later.
03637       //
03638       // Note, for a serial domain map, there can be no RemoteGIDs,
03639       // because there are no remote processes.  Likely explanations
03640       // for this are:
03641       //  * user submitted erroneous column indices
03642       //  * user submitted erroneous domain Map
03643       if (domainMap_->getComm ()->getSize () == 1) {
03644         TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03645           numRemoteColGIDs != 0, std::runtime_error,
03646           ": " << numRemoteColGIDs << " column "
03647           << (numRemoteColGIDs != 1 ? "indices are" : "index is")
03648           << " not in the domain Map." << endl
03649           << "Either these indices are invalid or the domain Map is invalid."
03650           << endl << "Remember that nonsquare matrices, or matrices where the "
03651           "row and range Maps are different, require calling the version of "
03652           "fillComplete that takes the domain and range Maps as input.");
03653         if (numLocalColGIDs == domainMap_->getNodeNumElements()) {
03654           colMap_ = domainMap_;
03655           checkInternalState ();
03656           return;
03657         }
03658       }
03659 
03660       // Populate myColumns with a list of all column GIDs.  Put
03661       // locally owned (in the domain Map) GIDs at the front: they
03662       // correspond to "same" and "permuted" entries between the
03663       // column Map and the domain Map.  Put remote GIDs at the back.
03664       myColumns.resize (numLocalColGIDs + numRemoteColGIDs);
03665       // get pointers into myColumns for each part
03666       ArrayView<GO> LocalColGIDs  = myColumns (0, numLocalColGIDs);
03667       ArrayView<GO> RemoteColGIDs = myColumns (numLocalColGIDs, numRemoteColGIDs);
03668 
03669       // Copy the remote GIDs into myColumns
03670       if (sortGhostsAssociatedWithEachProcessor_) {
03671         // The std::set puts GIDs in increasing order.
03672         std::copy (RemoteGIDSet.begin(), RemoteGIDSet.end(),
03673                    RemoteColGIDs.begin());
03674       } else {
03675         // Respect the originally encountered order.
03676         std::copy (RemoteGIDUnorderedVector.begin(),
03677                    RemoteGIDUnorderedVector.end(), RemoteColGIDs.begin());
03678       }
03679 
03680       // Make a list of process ranks corresponding to the remote GIDs.
03681       Array<int> RemoteImageIDs (numRemoteColGIDs);
03682       // Look up the remote process' ranks in the domain Map.
03683       {
03684         const LookupStatus stat =
03685           domainMap_->getRemoteIndexList (RemoteColGIDs, RemoteImageIDs ());
03686 #ifdef HAVE_TPETRA_DEBUG
03687         // If any process returns IDNotPresent, then at least one of
03688         // the remote indices was not present in the domain Map.  This
03689         // means that the Import object cannot be constructed, because
03690         // of incongruity between the column Map and domain Map.
03691         // This has two likely causes:
03692         //   - The user has made a mistake in the column indices
03693         //   - The user has made a mistake with respect to the domain Map
03694         const int missingID_lcl = (stat == IDNotPresent ? 1 : 0);
03695         int missingID_gbl = 0;
03696         reduceAll<int, int> (*getComm (), REDUCE_MAX, missingID_lcl,
03697                              outArg (missingID_gbl));
03698         TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03699           missingID_gbl == 1, std::runtime_error,
03700           ": Some column indices are not in the domain Map." << endl
03701           << "Either these column indices are invalid or the domain Map is "
03702           "invalid." << endl << "Likely cause: For a nonsquare matrix, you "
03703           "must give the domain and range Maps as input to fillComplete.");
03704 #else
03705         (void) stat; // forestall compiler warning for unused variable
03706 #endif // HAVE_TPETRA_DEBUG
03707       }
03708       // Sort incoming remote column indices by their owning process
03709       // rank, so that all columns coming from a given remote process
03710       // are contiguous.  This means the Import's Distributor doesn't
03711       // need to reorder data.
03712       //
03713       // NOTE (mfh 02 Sep 2014) This needs to be a stable sort, so
03714       // that it respects either of the possible orderings of GIDs
03715       // (sorted, or original order) specified above.
03716       sort2 (RemoteImageIDs.begin(), RemoteImageIDs.end(), RemoteColGIDs.begin());
03717 
03718       // Copy the local GIDs into myColumns. Two cases:
03719       // 1. If the number of Local column GIDs is the same as the
03720       //    number of Local domain GIDs, we can simply read the domain
03721       //    GIDs into the front part of ColIndices (see logic above
03722       //    from the serial short circuit case)
03723       // 2. We step through the GIDs of the DomainMap, checking to see
03724       //    if each domain GID is a column GID.  We want to do this to
03725       //    maintain a consistent ordering of GIDs between the columns
03726       //    and the domain.
03727 
03728       const size_t numDomainElts = domainMap_->getNodeNumElements ();
03729       if (numLocalColGIDs == numDomainElts) {
03730         // If the number of locally owned GIDs are the same as the
03731         // number of local domain Map elements, then the local domain
03732         // Map elements are the same as the locally owned GIDs.
03733         if (domainMap_->isContiguous ()) {
03734           // NOTE (mfh 03 Mar 2013, 02 Sep 2014) In the common case
03735           // that the domain Map is contiguous, it's more efficient to
03736           // avoid calling getNodeElementList(), since that
03737           // permanently constructs and caches the GID list in the
03738           // contiguous Map.
03739           GO curColMapGid = domainMap_->getMinGlobalIndex ();
03740           for (size_t k = 0; k < numLocalColGIDs; ++k, ++curColMapGid) {
03741             LocalColGIDs[k] = curColMapGid;
03742           }
03743         }
03744         else {
03745           ArrayView<const GO> domainElts = domainMap_->getNodeElementList ();
03746           std::copy (domainElts.begin(), domainElts.end(), LocalColGIDs.begin());
03747         }
03748       }
03749       else {
03750         // Count the number of locally owned GIDs, both to keep track
03751         // of the current array index, and as a sanity check.
03752         size_t numLocalCount = 0;
03753         if (domainMap_->isContiguous ()) {
03754           // NOTE (mfh 03 Mar 2013, 02 Sep 2014) In the common case
03755           // that the domain Map is contiguous, it's more efficient to
03756           // avoid calling getNodeElementList(), since that
03757           // permanently constructs and caches the GID list in the
03758           // contiguous Map.
03759           GO curColMapGid = domainMap_->getMinGlobalIndex ();
03760           for (size_t i = 0; i < numDomainElts; ++i, ++curColMapGid) {
03761             if (GIDisLocal[i]) {
03762               LocalColGIDs[numLocalCount++] = curColMapGid;
03763             }
03764           }
03765         }
03766         else {
03767           ArrayView<const GO> domainElts = domainMap_->getNodeElementList ();
03768           for (size_t i = 0; i < numDomainElts; ++i) {
03769             if (GIDisLocal[i]) {
03770               LocalColGIDs[numLocalCount++] = domainElts[i];
03771             }
03772           }
03773         }
03774         TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
03775           numLocalCount != numLocalColGIDs, std::logic_error,
03776           ": numLocalCount = " << numLocalCount << " != numLocalColGIDs = "
03777           << numLocalColGIDs << ".  This should never happen.  Please report "
03778           "this bug to the Tpetra developers.");
03779       }
03780 
03781       // FIXME (mfh 03 Apr 2013) Now would be a good time to use the
03782       // information we collected above to construct the Import.  In
03783       // particular, building an Import requires:
03784       //
03785       // 1. numSameIDs (length of initial contiguous sequence of GIDs
03786       //    on this process that are the same in both Maps; this
03787       //    equals the number of domain Map elements on this process)
03788       //
03789       // 2. permuteToLIDs and permuteFromLIDs (both empty in this
03790       //    case, since there's no permutation going on; the column
03791       //    Map starts with the domain Map's GIDs, and immediately
03792       //    after them come the remote GIDs)
03793       //
03794       // 3. remoteGIDs (exactly those GIDs that we found out above
03795       //    were not in the domain Map) and remoteLIDs (which we could
03796       //    have gotten above by using the three-argument version of
03797       //    getRemoteIndexList() that computes local indices as well
03798       //    as process ranks, instead of the two-argument version that
03799       //    was used above)
03800       //
03801       // 4. remotePIDs (which we have from the getRemoteIndexList()
03802       //    call above)
03803       //
03804       // 5. Sorting remotePIDs, and applying that permutation to
03805       //    remoteGIDs and remoteLIDs (by calling sort3 above instead
03806       //    of sort2)
03807       //
03808       // 6. Everything after the sort3 call in Import::setupExport():
03809       //    a. Create the Distributor via createFromRecvs(), which
03810       //       computes exportGIDs and exportPIDs
03811       //    b. Compute exportLIDs from exportGIDs (by asking the
03812       //       source Map, in this case the domain Map, to convert
03813       //       global to local)
03814       //
03815       // Steps 1-5 come for free, since we must do that work anyway in
03816       // order to compute the column Map.  In particular, Step 3 is
03817       // even more expensive than Step 6a, since it involves both
03818       // creating and using a new Distributor object.
03819 
03820     } // if the graph is globally indexed
03821 
03822     const global_size_t gstInv =
03823       Teuchos::OrdinalTraits<global_size_t>::invalid ();
03824     // FIXME (mfh 05 Mar 2014) Doesn't the index base of a Map have to
03825     // be the same as the Map's min GID? If the first column is empty
03826     // (contains no entries), then the column Map's min GID won't
03827     // necessarily be the same as the domain Map's index base.
03828     const GO indexBase = domainMap_->getIndexBase ();
03829     colMap_ = rcp (new map_type (gstInv, myColumns, indexBase,
03830                                  domainMap_->getComm (),
03831                                  domainMap_->getNode ()));
03832     checkInternalState ();
03833   }
03834 
03835 
03836   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03837   void CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::mergeAllIndices()
03838   {
03839     TEUCHOS_TEST_FOR_EXCEPT( isGloballyIndexed() ); // call only after makeIndicesLocal()
03840     TEUCHOS_TEST_FOR_EXCEPT( ! isSorted() ); // call only after sortIndices()
03841     if (! isMerged ()) {
03842       for (size_t row=0; row < getNodeNumRows(); ++row) {
03843         RowInfo rowInfo = getRowInfo(row);
03844         mergeRowIndices(rowInfo);
03845       }
03846       // we just merged every row
03847       noRedundancies_ = true;
03848     }
03849   }
03850 
03851 
03852   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03853   void
03854   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::makeImportExport()
03855   {
03856     TEUCHOS_TEST_FOR_EXCEPTION(! hasColMap (), std::logic_error, "Tpetra::"
03857       "CrsGraph: It's not allowed to call makeImportExport() unless the graph "
03858       "has a column Map.");
03859     RCP<ParameterList> params = this->getNonconstParameterList (); // could be null
03860 
03861     // Don't do any checks to see if we need to create the Import, if
03862     // it exists already.
03863     //
03864     // FIXME (mfh 25 Mar 2013) This will become incorrect if we
03865     // change CrsGraph in the future to allow changing the column
03866     // Map after fillComplete.  For now, the column Map is fixed
03867     // after the first fillComplete call.
03868     if (importer_.is_null ()) {
03869       // Create the Import instance if necessary.
03870       if (domainMap_ != colMap_ && (! domainMap_->isSameAs (*colMap_))) {
03871         if (params.is_null () || ! params->isSublist ("Import")) {
03872           importer_ = rcp (new import_type (domainMap_, colMap_));
03873         } else {
03874           RCP<ParameterList> importSublist = sublist (params, "Import", true);
03875           importer_ = rcp (new import_type (domainMap_, colMap_, importSublist));
03876         }
03877       }
03878     }
03879 
03880     // Don't do any checks to see if we need to create the Export, if
03881     // it exists already.
03882     if (exporter_.is_null ()) {
03883       // Create the Export instance if necessary.
03884       if (rangeMap_ != rowMap_ && ! rangeMap_->isSameAs (*rowMap_)) {
03885         if (params.is_null () || ! params->isSublist ("Export")) {
03886           exporter_ = rcp (new export_type (rowMap_, rangeMap_));
03887         }
03888         else {
03889           RCP<ParameterList> exportSublist = sublist (params, "Export", true);
03890           exporter_ = rcp (new export_type (rowMap_, rangeMap_, exportSublist));
03891         }
03892       }
03893     }
03894   }
03895 
03896 
03897   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03898   std::string
03899   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::description() const
03900   {
03901     std::ostringstream oss;
03902     oss << DistObject<GlobalOrdinal,LocalOrdinal,GlobalOrdinal,Node>::description();
03903     if (isFillComplete()) {
03904       oss << "{status = fill complete"
03905           << ", global rows = " << getGlobalNumRows()
03906           << ", global cols = " << getGlobalNumCols()
03907           << ", global num entries = " << getGlobalNumEntries()
03908           << "}";
03909     }
03910     else {
03911       oss << "{status = fill not complete"
03912           << ", global rows = " << getGlobalNumRows()
03913           << "}";
03914     }
03915     return oss.str();
03916   }
03917 
03918 
03919   template <class LocalOrdinal, class GlobalOrdinal, class Node>
03920   void
03921   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
03922   describe (Teuchos::FancyOStream &out,
03923             const Teuchos::EVerbosityLevel verbLevel) const
03924   {
03925     const char tfecfFuncName[] = "describe()";
03926     using std::endl;
03927     using std::setw;
03928     using Teuchos::VERB_DEFAULT;
03929     using Teuchos::VERB_NONE;
03930     using Teuchos::VERB_LOW;
03931     using Teuchos::VERB_MEDIUM;
03932     using Teuchos::VERB_HIGH;
03933     using Teuchos::VERB_EXTREME;
03934     Teuchos::EVerbosityLevel vl = verbLevel;
03935     if (vl == VERB_DEFAULT) vl = VERB_LOW;
03936     RCP<const Comm<int> > comm = this->getComm();
03937     const int myImageID = comm->getRank(),
03938               numImages = comm->getSize();
03939     size_t width = 1;
03940     for (size_t dec=10; dec<getGlobalNumRows(); dec *= 10) {
03941       ++width;
03942     }
03943     width = std::max<size_t>(width,Teuchos::as<size_t>(11)) + 2;
03944     Teuchos::OSTab tab(out);
03945     //    none: print nothing
03946     //     low: print O(1) info from node 0
03947     //  medium: print O(P) info, num entries per node
03948     //    high: print O(N) info, num entries per row
03949     // extreme: print O(NNZ) info: print graph indices
03950     //
03951     // for medium and higher, print constituent objects at specified verbLevel
03952     if (vl != VERB_NONE) {
03953       if (myImageID == 0) out << this->description() << std::endl;
03954       // O(1) globals, minus what was already printed by description()
03955       if (isFillComplete() && myImageID == 0) {
03956         out << "Global number of diagonals = " << globalNumDiags_ << std::endl;
03957         out << "Global max number of row entries = " << globalMaxNumRowEntries_ << std::endl;
03958       }
03959       // constituent objects
03960       if (vl == VERB_MEDIUM || vl == VERB_HIGH || vl == VERB_EXTREME) {
03961         if (myImageID == 0) out << "\nRow map: " << std::endl;
03962         rowMap_->describe(out,vl);
03963         if (colMap_ != null) {
03964           if (myImageID == 0) out << "\nColumn map: " << std::endl;
03965           colMap_->describe(out,vl);
03966         }
03967         if (domainMap_ != null) {
03968           if (myImageID == 0) out << "\nDomain map: " << std::endl;
03969           domainMap_->describe(out,vl);
03970         }
03971         if (rangeMap_ != null) {
03972           if (myImageID == 0) out << "\nRange map: " << std::endl;
03973           rangeMap_->describe(out,vl);
03974         }
03975       }
03976       // O(P) data
03977       if (vl == VERB_MEDIUM || vl == VERB_HIGH || vl == VERB_EXTREME) {
03978         for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
03979           if (myImageID == imageCtr) {
03980             out << "Node ID = " << imageCtr << std::endl
03981                 << "Node number of entries = " << nodeNumEntries_ << std::endl
03982                 << "Node number of diagonals = " << nodeNumDiags_ << std::endl
03983                 << "Node max number of entries = " << nodeMaxNumRowEntries_ << std::endl;
03984             if (isUpperTriangular()) {
03985               out << "Graph is upper triangular" << std::endl;
03986             }
03987             if (isLowerTriangular()) {
03988               out << "Graph is lower triangular" << std::endl;
03989             }
03990             if (indicesAreAllocated()) {
03991               out << "Node number of allocated entries = " << nodeNumAllocated_ << std::endl;
03992             }
03993             else {
03994               out << "Indices are not allocated." << std::endl;
03995             }
03996           }
03997           comm->barrier();
03998           comm->barrier();
03999           comm->barrier();
04000         }
04001       }
04002       // O(N) and O(NNZ) data
04003       if (vl == VERB_HIGH || vl == VERB_EXTREME) {
04004         TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(hasRowInfo() == false, std::runtime_error, ": reduce verbosity level; graph row information was deleted at fillComplete().");
04005         for (int imageCtr = 0; imageCtr < numImages; ++imageCtr) {
04006           if (myImageID == imageCtr) {
04007             out << std::setw(width) << "Node ID"
04008                 << std::setw(width) << "Global Row"
04009                 << std::setw(width) << "Num Entries";
04010             if (vl == VERB_EXTREME) {
04011               out << "Entries";
04012             }
04013             out << std::endl;
04014             for (size_t r=0; r < getNodeNumRows(); ++r) {
04015               RowInfo rowinfo = getRowInfo(r);
04016               GlobalOrdinal gid = rowMap_->getGlobalElement(r);
04017               out << std::setw(width) << myImageID
04018                   << std::setw(width) << gid
04019                   << std::setw(width) << rowinfo.numEntries;
04020               if (vl == VERB_EXTREME) {
04021                 if (isGloballyIndexed()) {
04022                   ArrayView<const GlobalOrdinal> rowview = getGlobalView(rowinfo);
04023                   for (size_t j=0; j < rowinfo.numEntries; ++j) out << rowview[j] << " ";
04024                 }
04025                 else if (isLocallyIndexed()) {
04026                   ArrayView<const LocalOrdinal> rowview = getLocalView(rowinfo);
04027                   for (size_t j=0; j < rowinfo.numEntries; ++j) out << colMap_->getGlobalElement(rowview[j]) << " ";
04028                 }
04029               }
04030               out << std::endl;
04031             }
04032           }
04033           comm->barrier();
04034           comm->barrier();
04035           comm->barrier();
04036         }
04037       }
04038     }
04039   }
04040 
04041 
04042   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04043   bool
04044   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04045   checkSizes (const SrcDistObject& source)
04046   {
04047     (void) source; // forestall "unused variable" compiler warnings
04048 
04049     // It's not clear what kind of compatibility checks on sizes can
04050     // be performed here.  Epetra_CrsGraph doesn't check any sizes for
04051     // compatibility.
04052     return true;
04053   }
04054 
04055 
04056   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04057   void
04058   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04059   copyAndPermute (const SrcDistObject& source,
04060                   size_t numSameIDs,
04061                   const Teuchos::ArrayView<const LocalOrdinal> &permuteToLIDs,
04062                   const Teuchos::ArrayView<const LocalOrdinal> &permuteFromLIDs)
04063   {
04064     using Teuchos::Array;
04065     using Teuchos::ArrayView;
04066     typedef LocalOrdinal LO;
04067     typedef GlobalOrdinal GO;
04068     const char tfecfFuncName[] = "copyAndPermute";
04069     typedef CrsGraph<LO, GO, Node> this_type;
04070     typedef RowGraph<LO, GO, Node> row_graph_type;
04071 
04072     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04073       permuteToLIDs.size() != permuteFromLIDs.size(), std::runtime_error,
04074       ": permuteToLIDs and permuteFromLIDs must have the same size.");
04075     // Make sure that the source object has the right type.  We only
04076     // actually need it to be a RowGraph, with matching first three
04077     // template parameters.  If it's a CrsGraph, we can use view mode
04078     // instead of copy mode to get each row's data.
04079     //
04080     // FIXME (mfh 07 Jul 2013) It should not be necessary for any of
04081     // the template parameters but GO to match.  GO has to match
04082     // because the graph has to send indices as global ordinals, if
04083     // the source and target graphs do not have the same column Map.
04084     // If LO doesn't match, the graphs could communicate using global
04085     // indices.  It could be possible that Node affects the graph's
04086     // storage format, but packAndPrepare should assume a common
04087     // communication format in any case.
04088     const row_graph_type* srcRowGraph = dynamic_cast<const row_graph_type*> (&source);
04089     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04090       srcRowGraph == NULL, std::invalid_argument,
04091       ": The source object must be a RowGraph with matching first three "
04092       "template parameters.");
04093 
04094     // If the source object is actually a CrsGraph, we can use view
04095     // mode instead of copy mode to access the entries in each row,
04096     // if the graph is not fill complete.
04097     const this_type* srcCrsGraph = dynamic_cast<const this_type*> (&source);
04098 
04099     const map_type& srcRowMap = * (srcRowGraph->getRowMap ());
04100     const map_type& tgtRowMap = * (this->getRowMap ());
04101     const bool src_filled = srcRowGraph->isFillComplete ();
04102     Array<GO> row_copy;
04103     LO myid = 0;
04104 
04105     //
04106     // "Copy" part of "copy and permute."
04107     //
04108     if (src_filled || srcCrsGraph == NULL) {
04109       // If the source graph is fill complete, we can't use view mode,
04110       // because the data might be stored in a different format not
04111       // compatible with the expectations of view mode.  Also, if the
04112       // source graph is not a CrsGraph, we can't use view mode,
04113       // because RowGraph only provides copy mode access to the data.
04114       for (size_t i = 0; i < numSameIDs; ++i, ++myid) {
04115         const GO gid = srcRowMap.getGlobalElement (myid);
04116         size_t row_length = srcRowGraph->getNumEntriesInGlobalRow (gid);
04117         row_copy.resize (row_length);
04118         size_t check_row_length = 0;
04119         srcRowGraph->getGlobalRowCopy (gid, row_copy (), check_row_length);
04120         this->insertGlobalIndices (gid, row_copy ());
04121       }
04122     } else {
04123       for (size_t i = 0; i < numSameIDs; ++i, ++myid) {
04124         const GO gid = srcRowMap.getGlobalElement (myid);
04125         ArrayView<const GO> row;
04126         srcCrsGraph->getGlobalRowView (gid, row);
04127         this->insertGlobalIndices (gid, row);
04128       }
04129     }
04130 
04131     //
04132     // "Permute" part of "copy and permute."
04133     //
04134     if (src_filled || srcCrsGraph == NULL) {
04135       for (LO i = 0; i < permuteToLIDs.size (); ++i) {
04136         const GO mygid = tgtRowMap.getGlobalElement (permuteToLIDs[i]);
04137         const GO srcgid = srcRowMap.getGlobalElement (permuteFromLIDs[i]);
04138         size_t row_length = srcRowGraph->getNumEntriesInGlobalRow (srcgid);
04139         row_copy.resize (row_length);
04140         size_t check_row_length = 0;
04141         srcRowGraph->getGlobalRowCopy (srcgid, row_copy (), check_row_length);
04142         this->insertGlobalIndices (mygid, row_copy ());
04143       }
04144     } else {
04145       for (LO i = 0; i < permuteToLIDs.size (); ++i) {
04146         const GO mygid = tgtRowMap.getGlobalElement (permuteToLIDs[i]);
04147         const GO srcgid = srcRowMap.getGlobalElement (permuteFromLIDs[i]);
04148         ArrayView<const GO> row;
04149         srcCrsGraph->getGlobalRowView (srcgid, row);
04150         this->insertGlobalIndices (mygid, row);
04151       }
04152     }
04153   }
04154 
04155 
04156   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04157   void
04158   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04159   packAndPrepare (const SrcDistObject& source,
04160                   const Teuchos::ArrayView<const LocalOrdinal> &exportLIDs,
04161                   Teuchos::Array<GlobalOrdinal> &exports,
04162                   const Teuchos::ArrayView<size_t> & numPacketsPerLID,
04163                   size_t& constantNumPackets,
04164                   Distributor &distor)
04165   {
04166     using Teuchos::Array;
04167     const char tfecfFuncName[] = "packAndPrepare";
04168     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04169       exportLIDs.size() != numPacketsPerLID.size(), std::runtime_error,
04170       ": exportLIDs and numPacketsPerLID must have the same size.");
04171     typedef RowGraph<LocalOrdinal, GlobalOrdinal, Node> row_graph_type;
04172     const row_graph_type& srcGraph = dynamic_cast<const row_graph_type&> (source);
04173 
04174     // We don't check whether src_graph has had fillComplete called,
04175     // because it doesn't matter whether the *source* graph has been
04176     // fillComplete'd. The target graph can not be fillComplete'd yet.
04177     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04178       this->isFillComplete (), std::runtime_error,
04179       ": The target graph of an Import or Export must not be fill complete.");
04180 
04181     srcGraph.pack (exportLIDs, exports, numPacketsPerLID, constantNumPackets, distor);
04182   }
04183 
04184 
04185   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04186   void
04187   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04188   pack (const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs,
04189         Teuchos::Array<GlobalOrdinal>& exports,
04190         const Teuchos::ArrayView<size_t>& numPacketsPerLID,
04191         size_t& constantNumPackets,
04192         Distributor& distor) const
04193   {
04194     using Teuchos::Array;
04195     typedef LocalOrdinal LO;
04196     typedef GlobalOrdinal GO;
04197     const char tfecfFuncName[] = "pack";
04198     (void) distor; // forestall "unused argument" compiler warning
04199 
04200     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04201       exportLIDs.size() != numPacketsPerLID.size(), std::runtime_error,
04202       ": exportLIDs and numPacketsPerLID must have the same size.");
04203 
04204     const map_type& srcMap = * (this->getMap ());
04205     constantNumPackets = 0;
04206 
04207     // Set numPacketsPerLID[i] to the number of entries owned by the
04208     // calling process in (local) row exportLIDs[i] of the graph, that
04209     // the caller wants us to send out.  Compute the total number of
04210     // packets (that is, entries) owned by this process in all the
04211     // rows that the caller wants us to send out.
04212     size_t totalNumPackets = 0;
04213     Array<GO> row;
04214     for (LO i = 0; i < exportLIDs.size (); ++i) {
04215       const GO GID = srcMap.getGlobalElement (exportLIDs[i]);
04216       size_t row_length = this->getNumEntriesInGlobalRow (GID);
04217       numPacketsPerLID[i] = row_length;
04218       totalNumPackets += row_length;
04219     }
04220 
04221     exports.resize (totalNumPackets);
04222 
04223     // Loop again over the rows to export, and pack rows of indices
04224     // into the output buffer.
04225     size_t exportsOffset = 0;
04226     for (LO i = 0; i < exportLIDs.size (); ++i) {
04227       const GO GID = srcMap.getGlobalElement (exportLIDs[i]);
04228       size_t row_length = this->getNumEntriesInGlobalRow (GID);
04229       row.resize (row_length);
04230       size_t check_row_length = 0;
04231       this->getGlobalRowCopy (GID, row (), check_row_length);
04232       typename Array<GO>::const_iterator row_iter = row.begin();
04233       typename Array<GO>::const_iterator row_end = row.end();
04234       size_t j = 0;
04235       for (; row_iter != row_end; ++row_iter, ++j) {
04236         exports[exportsOffset+j] = *row_iter;
04237       }
04238       exportsOffset += row.size();
04239     }
04240   }
04241 
04242 
04243   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04244   void
04245   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04246   unpackAndCombine (const Teuchos::ArrayView<const LocalOrdinal> &importLIDs,
04247                     const Teuchos::ArrayView<const GlobalOrdinal> &imports,
04248                     const Teuchos::ArrayView<size_t> &numPacketsPerLID,
04249                     size_t constantNumPackets,
04250                     Distributor& /* distor */,
04251                     CombineMode /* CM */)
04252   {
04253     // FIXME (mfh 02 Apr 2012) REPLACE combine mode has a perfectly
04254     // reasonable meaning, whether or not the matrix is fill complete.
04255     // It's just more work to implement.
04256 
04257     // We are not checking the value of the CombineMode input
04258     // argument.  For CrsGraph, we only support import/export
04259     // operations if fillComplete has not yet been called.  Any
04260     // incoming column-indices are inserted into the target graph. In
04261     // this context, CombineMode values of ADD vs INSERT are
04262     // equivalent. What is the meaning of REPLACE for CrsGraph? If a
04263     // duplicate column-index is inserted, it will be compressed out
04264     // when fillComplete is called.
04265     //
04266     // Note: I think REPLACE means that an existing row is replaced by
04267     // the imported row, i.e., the existing indices are cleared. CGB,
04268     // 6/17/2010
04269 
04270     const char tfecfFuncName[] = "unpackAndCombine";
04271     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04272       importLIDs.size() != numPacketsPerLID.size(), std::runtime_error,
04273       ": importLIDs and numPacketsPerLID must have the same size.");
04274     TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
04275       isFillComplete (), std::runtime_error,
04276       ": Import or Export operations are not allowed on the destination "
04277       "CrsGraph if it is fill complete.");
04278     size_t importsOffset = 0;
04279 
04280     typedef typename ArrayView<const LocalOrdinal>::const_iterator iter_type;
04281     iter_type impLIDiter = importLIDs.begin();
04282     iter_type impLIDend = importLIDs.end();
04283 
04284     for (size_t i = 0; impLIDiter != impLIDend; ++impLIDiter, ++i) {
04285       LocalOrdinal row_length = numPacketsPerLID[i];
04286       ArrayView<const GlobalOrdinal> row (&imports[importsOffset], row_length);
04287       insertGlobalIndicesFiltered (this->getMap ()->getGlobalElement (*impLIDiter), row);
04288       importsOffset += row_length;
04289     }
04290   }
04291 
04292 
04293   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04294   void
04295   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04296   removeEmptyProcessesInPlace (const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& newMap)
04297   {
04298     using Teuchos::Comm;
04299     using Teuchos::null;
04300     using Teuchos::ParameterList;
04301     using Teuchos::RCP;
04302 
04303     // We'll set all the state "transactionally," so that this method
04304     // satisfies the strong exception guarantee.  This object's state
04305     // won't be modified until the end of this method.
04306     RCP<const map_type> rowMap, domainMap, rangeMap, colMap;
04307     RCP<import_type> importer;
04308     RCP<export_type> exporter;
04309 
04310     rowMap = newMap;
04311     RCP<const Comm<int> > newComm =
04312       (newMap.is_null ()) ? null : newMap->getComm ();
04313 
04314     if (! domainMap_.is_null ()) {
04315       if (domainMap_.getRawPtr () == rowMap_.getRawPtr ()) {
04316         // Common case: original domain and row Maps are identical.
04317         // In that case, we need only replace the original domain Map
04318         // with the new Map.  This ensures that the new domain and row
04319         // Maps _stay_ identical.
04320         domainMap = newMap;
04321       } else {
04322         domainMap = domainMap_->replaceCommWithSubset (newComm);
04323       }
04324     }
04325     if (! rangeMap_.is_null ()) {
04326       if (rangeMap_.getRawPtr () == rowMap_.getRawPtr ()) {
04327         // Common case: original range and row Maps are identical.  In
04328         // that case, we need only replace the original range Map with
04329         // the new Map.  This ensures that the new range and row Maps
04330         // _stay_ identical.
04331         rangeMap = newMap;
04332       } else {
04333         rangeMap = rangeMap_->replaceCommWithSubset (newComm);
04334       }
04335     }
04336     if (! colMap.is_null ()) {
04337       colMap = colMap_->replaceCommWithSubset (newComm);
04338     }
04339 
04340     // (Re)create the Export and / or Import if necessary.
04341     if (! newComm.is_null ()) {
04342       RCP<ParameterList> params = this->getNonconstParameterList (); // could be null
04343       //
04344       // The operations below are collective on the new communicator.
04345       //
04346       // (Re)create the Export object if necessary.  If I haven't
04347       // called fillComplete yet, I don't have a rangeMap, so I must
04348       // first check if the _original_ rangeMap is not null.  Ditto
04349       // for the Import object and the domain Map.
04350       if (! rangeMap_.is_null () &&
04351           rangeMap != rowMap &&
04352           ! rangeMap->isSameAs (*rowMap)) {
04353         if (params.is_null () || ! params->isSublist ("Export")) {
04354           exporter = rcp (new export_type (rowMap, rangeMap));
04355         }
04356         else {
04357           RCP<ParameterList> exportSublist = sublist (params, "Export", true);
04358           exporter = rcp (new export_type (rowMap, rangeMap, exportSublist));
04359         }
04360       }
04361       // (Re)create the Import object if necessary.
04362       if (! domainMap_.is_null () &&
04363           domainMap != colMap &&
04364           ! domainMap->isSameAs (*colMap)) {
04365         if (params.is_null () || ! params->isSublist ("Import")) {
04366           importer = rcp (new import_type (domainMap, colMap));
04367         } else {
04368           RCP<ParameterList> importSublist = sublist (params, "Import", true);
04369           importer = rcp (new import_type (domainMap, colMap, importSublist));
04370         }
04371       }
04372     } // if newComm is not null
04373 
04374     // Defer side effects until the end.  If no destructors throw
04375     // exceptions (they shouldn't anyway), then this method satisfies
04376     // the strong exception guarantee.
04377     exporter_ = exporter;
04378     importer_ = importer;
04379     rowMap_ = rowMap;
04380     // mfh 31 Mar 2013: DistObject's map_ is the row Map of a CrsGraph
04381     // or CrsMatrix.  CrsGraph keeps a redundant pointer (rowMap_) to
04382     // the same object.  We might want to get rid of this redundant
04383     // pointer sometime, but for now, we'll leave it alone and just
04384     // set map_ to the same object.
04385     this->map_ = rowMap;
04386     domainMap_ = domainMap;
04387     rangeMap_ = rangeMap;
04388     colMap_ = colMap;
04389   }
04390 
04391 
04392   template <class LocalOrdinal, class GlobalOrdinal, class Node>
04393   bool
04394   CrsGraph<LocalOrdinal,GlobalOrdinal,Node>::
04395   hasRowInfo () const
04396   {
04397     if (indicesAreAllocated () &&
04398         getProfileType () == StaticProfile &&
04399         rowPtrs_.is_null ()) {
04400       return false;
04401     } else {
04402       return true;
04403     }
04404   }
04405 
04406 } // namespace Tpetra
04407 
04408 // Include KokkosRefactor partial specialisation if enabled
04409 #if defined(TPETRA_HAVE_KOKKOS_REFACTOR)
04410 #include "Tpetra_KokkosRefactor_CrsGraph_def.hpp"
04411 #endif
04412 
04413 
04414 //
04415 // Explicit instantiation macro
04416 //
04417 // Must be expanded from within the Tpetra namespace!
04418 //
04419 #define TPETRA_CRSGRAPH_GRAPH_INSTANT(LO,GO,NODE) template class CrsGraph< LO , GO , NODE >;
04420 #define TPETRA_CRSGRAPH_SORTROWINDICESANDVALUES_INSTANT(S,LO,GO,NODE) template void CrsGraph< LO , GO , NODE >::sortRowIndicesAndValues< S >(const RowInfo, const Teuchos::ArrayView< S >& );
04421 #define TPETRA_CRSGRAPH_MERGEROWINDICESANDVALUES_INSTANT(S,LO,GO,NODE) template void CrsGraph< LO , GO , NODE >::mergeRowIndicesAndValues< S >(RowInfo, const ArrayView< S >& );
04422 #define TPETRA_CRSGRAPH_ALLOCATEVALUES1D_INSTANT(S,LO,GO,NODE) template ArrayRCP< S > CrsGraph< LO , GO , NODE >::allocateValues1D< S >() const;
04423 #define TPETRA_CRSGRAPH_ALLOCATEVALUES2D_INSTANT(S,LO,GO,NODE) template ArrayRCP< Array< S > > CrsGraph< LO , GO , NODE >::allocateValues2D< S >() const;
04424 
04425 #define TPETRA_CRSGRAPH_INSTANT(S,LO,GO,NODE)                    \
04426   TPETRA_CRSGRAPH_SORTROWINDICESANDVALUES_INSTANT(S,LO,GO,NODE)  \
04427   TPETRA_CRSGRAPH_MERGEROWINDICESANDVALUES_INSTANT(S,LO,GO,NODE) \
04428   TPETRA_CRSGRAPH_ALLOCATEVALUES1D_INSTANT(S,LO,GO,NODE)         \
04429   TPETRA_CRSGRAPH_ALLOCATEVALUES2D_INSTANT(S,LO,GO,NODE)
04430 
04431 #endif // TPETRA_CRSGRAPH_DEF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines