Tpetra Matrix/Vector Services Version of the Day
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
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 __MatrixMarket_Tpetra_hpp
00043 #define __MatrixMarket_Tpetra_hpp
00044 
00056 #include "Tpetra_CrsMatrix.hpp"
00057 #include "MatrixMarket_raw.hpp"
00058 #include "MatrixMarket_Banner.hpp"
00059 #include "MatrixMarket_CoordDataReader.hpp"
00060 #include "MatrixMarket_util.hpp"
00061 
00062 #include <algorithm>
00063 #include <fstream>
00064 #include <iostream>
00065 #include <iterator>
00066 #include <vector>
00067 #include <stdexcept>
00068 
00069 namespace Tpetra {
00097   namespace MatrixMarket {
00098 
00162     template<class SparseMatrixType>
00163     class Reader {
00164     public:
00167       typedef SparseMatrixType sparse_matrix_type;
00168       typedef RCP<sparse_matrix_type> sparse_matrix_ptr;
00169 
00172       typedef typename SparseMatrixType::scalar_type scalar_type;
00175       typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
00182       typedef typename SparseMatrixType::global_ordinal_type 
00183         global_ordinal_type;
00184 
00187       typedef typename SparseMatrixType::node_type node_type;
00188 
00191       typedef MultiVector<scalar_type, 
00192         local_ordinal_type, 
00193         global_ordinal_type, 
00194         node_type> multivector_type;
00195 
00196       typedef RCP<node_type> node_ptr;
00197       typedef Comm<int> comm_type;
00198       typedef RCP<const comm_type> comm_ptr;
00199       typedef Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00200       typedef RCP<const map_type> map_ptr;
00201 
00202     private:
00203 
00206       typedef typename ArrayRCP<global_ordinal_type>::size_type size_type;
00207 
00220       static RCP<const map_type>
00221       makeRangeMap (const RCP<const comm_type>& pComm,
00222                     const RCP<node_type>& pNode,
00223                     const global_ordinal_type numRows)
00224       {
00225         // A conventional, uniformly partitioned, contiguous map.
00226         return rcp (new map_type (static_cast<global_size_t> (numRows), 
00227                                   static_cast<global_ordinal_type> (0),
00228                                   pComm, GloballyDistributed, pNode));
00229       }
00230 
00263       static RCP<const map_type>
00264       makeRowMap (const RCP<const map_type>& pRowMap, 
00265       const RCP<const comm_type>& pComm,
00266       const RCP<node_type>& pNode,
00267       const global_ordinal_type numRows)
00268       {
00269   // If the caller didn't provide a map, return a conventional,
00270   // uniformly partitioned, contiguous map.
00271   if (pRowMap.is_null()) {
00272     return rcp (new map_type (static_cast<global_size_t> (numRows), 
00273             static_cast<global_ordinal_type> (0),
00274             pComm, GloballyDistributed, pNode));
00275   } else {
00276     TEUCHOS_TEST_FOR_EXCEPTION(! pRowMap->isDistributed() && pComm->getSize() > 1, 
00277            std::invalid_argument,
00278            "The specified row map is not distributed, but "
00279            "the given communicator includes more than one "
00280            "rank (in fact, there are " << pComm->getSize() 
00281            << " ranks).");
00282     TEUCHOS_TEST_FOR_EXCEPTION(pRowMap->getComm() != pComm, 
00283            std::invalid_argument,
00284            "The specified row map's communicator (pRowMap->"
00285            "getComm()) is different than the given separately "
00286            "supplied communicator pComm.");
00287     TEUCHOS_TEST_FOR_EXCEPTION(pRowMap->getNode() != pNode,
00288            std::invalid_argument,
00289            "The specified row map's node (pRowMap->getNode()) "
00290            "is different than the given separately supplied "
00291            "node pNode.");
00292     return pRowMap;
00293   }
00294       }
00295 
00310       static map_ptr
00311       makeDomainMap (const map_ptr& pRangeMap,
00312                      const global_ordinal_type numRows,
00313                      const global_ordinal_type numCols)
00314       {
00315   // Abbreviations so that the map creation call isn't too long.
00316         typedef local_ordinal_type LO;
00317         typedef global_ordinal_type GO;
00318         typedef node_type Node;
00319 
00320         if (numRows == numCols) {
00321           return pRangeMap;
00322         } else {
00323           comm_ptr pComm = pRangeMap->getComm();
00324           node_ptr pNode = pRangeMap->getNode();
00325           return createUniformContigMapWithNode<LO,GO,Node> (numCols, 
00326                    pComm, 
00327                    pNode);
00328         }
00329       }
00330 
00403       static void
00404       distribute (ArrayRCP<size_t>& myNumEntriesPerRow,
00405                   ArrayRCP<size_type>& myRowPtr,
00406                   ArrayRCP<global_ordinal_type>& myColInd,
00407                   ArrayRCP<scalar_type>& myValues,
00408                   const RCP<const map_type>& pRowMap,
00409                   ArrayRCP<size_t>& numEntriesPerRow,
00410                   ArrayRCP<size_type>& rowPtr,
00411                   ArrayRCP<global_ordinal_type>& colInd,
00412                   ArrayRCP<scalar_type>& values,
00413                   const bool debug=false)
00414       {
00415          using Teuchos::CommRequest;
00416          using Teuchos::receive;
00417          using Teuchos::send;
00418          using std::cerr;
00419          using std::endl;
00420 
00421          const bool extraDebug = false;
00422          comm_ptr pComm = pRowMap->getComm();
00423          const int numProcs = Teuchos::size (*pComm);
00424          const int myRank = Teuchos::rank (*pComm);
00425          const int rootRank = 0;
00426 
00427    // Type abbreviations to make the code more concise.
00428    typedef global_ordinal_type GO;
00429    typedef local_ordinal_type LO;
00430 
00431          // List of the global indices of my rows.  They may or may
00432          // not be contiguous, and the row map need not be one-to-one.
00433          ArrayView<const GO> myRows = pRowMap->getNodeElementList();
00434          const size_type myNumRows = myRows.size();
00435          TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) != 
00436           pRowMap->getNodeNumElements(),
00437                             std::logic_error,
00438                             "pRowMap->getNodeElementList().size() = " 
00439                             << myNumRows
00440                             << " != pRowMap->getNodeNumElements() = "
00441                             << pRowMap->getNodeNumElements() << ".  "
00442                             "Please report this bug to the Tpetra developers.");
00443          TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
00444                             std::logic_error,
00445                             "On Proc 0: numEntriesPerRow.size() = "
00446                             << numEntriesPerRow.size()
00447                             << " != pRowMap->getNodeElementList().size() = " 
00448                             << myNumRows << ".  Please report this bug to the "
00449                             "Tpetra developers.");
00450 
00451          // Space for my proc's number of entries per row.  
00452          // Will be filled in below.
00453          myNumEntriesPerRow = arcp<size_t> (myNumRows);
00454 
00455          // Teuchos::receive() returns an int; here is space for it.
00456          int recvResult = 0;
00457 
00458          if (myRank != rootRank)
00459            {
00460              // Tell the root how many rows we have.  If we're sending
00461              // none, then we don't have anything else to send, nor
00462              // does the root have to receive anything else.
00463              send (*pComm, myNumRows, rootRank);
00464              if (myNumRows != 0)
00465                {
00466                  // Now send my rows' global indices.  Hopefully the
00467                  // cast to int doesn't overflow.  This is unlikely,
00468                  // since it should fit in a LO, even
00469                  // though it is a GO.
00470                  send (*pComm, static_cast<int> (myNumRows), 
00471                        myRows.getRawPtr(), rootRank);
00472 
00473                  // I (this proc) don't care if my global row indices
00474                  // are contiguous, though the root proc does (since
00475                  // otherwise it needs to pack noncontiguous data into
00476                  // contiguous storage before sending).  That's why we
00477                  // don't check for contiguousness here.
00478 
00479                  // Ask the root processor for my part of the array of the
00480                  // number of entries per row.
00481                  recvResult = receive (*pComm, rootRank, 
00482                                        static_cast<int> (myNumRows),
00483                                        myNumEntriesPerRow.getRawPtr());
00484 
00485                  // Use the resulting array to figure out how many column
00486                  // indices and values for which I should ask from the root
00487                  // processor.  
00488                  const size_t myNumEntries = 
00489                    std::accumulate (myNumEntriesPerRow.begin(), 
00490                                     myNumEntriesPerRow.end(), 
00491                                     static_cast<size_t> (0));
00492 
00493                  // Make space for my entries of the sparse matrix.
00494                  // Note that they don't have to be sorted by row
00495                  // index.  Iterating through all my rows requires
00496                  // computing a running sum over myNumEntriesPerRow.
00497                  myColInd = arcp<GO> (myNumEntries);
00498                  myValues = arcp<scalar_type> (myNumEntries);
00499                  if (myNumEntries > 0)
00500                    { // Ask for that many column indices and values, 
00501          // if there are any.
00502                      recvResult = receive (*pComm, rootRank, 
00503                                            static_cast<int> (myNumEntries), 
00504                                            myColInd.getRawPtr());
00505                      recvResult = receive (*pComm, rootRank, 
00506                                            static_cast<int> (myNumEntries), 
00507                                            myValues.getRawPtr());
00508                    }
00509                } // If I own at least one row
00510            } // If I am not the root processor
00511          else // I _am_ the root processor
00512            {
00513              if (debug)
00514                cerr << "-- Proc 0: Copying my data from global arrays" << endl;
00515 
00516              // Proc 0 (the root processor) still needs to (allocate,
00517              // if not done already) and fill its part of the matrix
00518              // (my*).
00519              for (size_type k = 0; k < myNumRows; ++k)
00520                {
00521                  const GO myCurRow = myRows[k];
00522                  const size_t numEntriesInThisRow = numEntriesPerRow[myCurRow];
00523                  //myNumEntriesPerRow[k] = numEntriesPerRow[myCurRow];
00524                  myNumEntriesPerRow[k] = numEntriesInThisRow;
00525                }
00526              if (extraDebug && debug)
00527                {
00528                  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm())) 
00529                       << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
00530                  for (size_type k = 0; k < myNumRows; ++k)
00531                    {
00532                      cerr << myNumEntriesPerRow[k];
00533                      if (k < myNumRows-1)
00534                        cerr << " ";
00535                    }
00536                  cerr << "]" << endl;
00537                }
00538              // The total number of matrix entries that my proc owns.
00539              const size_t myNumEntries = 
00540                std::accumulate (myNumEntriesPerRow.begin(), 
00541                                 myNumEntriesPerRow.end(), 
00542                                 static_cast<size_t> (0));
00543              if (debug)
00544                cerr << "-- Proc 0: I own " << myNumRows << " rows and " 
00545                     << myNumEntries << " entries" << endl;
00546 
00547              myColInd = arcp<GO> (myNumEntries);
00548              myValues = arcp<scalar_type> (myNumEntries);
00549 
00550              // Copy Proc 0's part of the matrix into the my* arrays.
00551              // It's important that myCurPos be updated _before_ k,
00552              // otherwise myCurPos will get the wrong number of entries
00553              // per row (it should be for the row in the just-completed
00554              // iteration, not for the next iteration's row).
00555              size_t myCurPos = 0;
00556              for (size_type k = 0; k < myNumRows; 
00557                   myCurPos += myNumEntriesPerRow[k], ++k)
00558                {
00559                  const size_t curNumEntries = myNumEntriesPerRow[k];
00560                  const GO myRow = myRows[k];
00561                  const size_t curPos = rowPtr[myRow];
00562                  if (extraDebug && debug)
00563                    {
00564                      cerr << "k = " << k << ", myRow = " << myRow << ": colInd("
00565                           << curPos << "," << curNumEntries << "), myColInd(" 
00566                           << myCurPos << "," << curNumEntries << ")" << endl;
00567                    }
00568                  // Only copy if there are entries to copy, in order
00569                  // not to construct empty ranges for the ArrayRCP
00570                  // views.
00571                  if (curNumEntries > 0)
00572                    {
00573                      ArrayView<GO> colIndView = colInd(curPos, curNumEntries);
00574                      ArrayView<GO> myColIndView = 
00575            myColInd(myCurPos, curNumEntries);
00576                      std::copy (colIndView.begin(), colIndView.end(), 
00577                                 myColIndView.begin());
00578 
00579                      ArrayView<scalar_type> valuesView = 
00580                        values(curPos, curNumEntries);
00581                      ArrayView<scalar_type> myValuesView = 
00582                        myValues(myCurPos, curNumEntries);
00583                      std::copy (valuesView.begin(), valuesView.end(), 
00584                                 myValuesView.begin());
00585                    }
00586                }
00587 
00588              // Proc 0 processes each other proc p in turn.
00589              for (int p = 1; p < numProcs; ++p)
00590                {
00591                  if (debug)
00592                    cerr << "-- Proc 0: Processing proc " << p << endl;
00593 
00594                  size_type theirNumRows = 0;
00595                  // Ask Proc p how many rows it has.  If it doesn't
00596                  // have any, we can move on to the next proc.  This
00597                  // has to be a standard receive so that we can avoid
00598                  // the degenerate case of sending zero data.
00599                  recvResult = receive (*pComm, p, &theirNumRows);
00600                  if (debug)
00601                    cerr << "-- Proc 0: Proc " << p << " owns " 
00602                         << theirNumRows << " rows" << endl;
00603                  if (theirNumRows != 0)
00604                    { // Ask Proc p which rows it owns.  The resulting
00605                      // global row indices are not guaranteed to be
00606                      // contiguous or sorted.  Global row indices are
00607                      // themselves indices into the numEntriesPerRow
00608                      // array.
00609                      ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
00610                      recvResult = receive (*pComm, p, 
00611                                            static_cast<int> (theirNumRows), 
00612                                            theirRows.getRawPtr());
00613                      // Extra test to make sure that the rows we
00614                      // received are all sensible.  This is a good
00615                      // idea since we are going to use the global row
00616                      // indices we've received to index into the
00617                      // numEntriesPerRow array.  Better to catch any
00618                      // bugs here and print a sensible error message,
00619                      // rather than segfault and print a cryptic error
00620                      // message.
00621                      {
00622                        const global_size_t numRows = 
00623                          pRowMap->getGlobalNumElements();
00624                        bool theirRowsValid = true;
00625                        for (size_type k = 0; k < theirNumRows; ++k)
00626                          {
00627                            // global_ordinal_t is generally a signed type.
00628                            if (theirRows[k] < 0)
00629                              theirRowsValid = false;
00630                            // Signed to unsigned cast should not
00631                            // overflow.  We cast in order to avoid
00632                            // compiler warnings about comparing signed
00633                            // and unsigned types, in case
00634                            // global_size_t is unsigned.
00635                            else if (static_cast<global_size_t> (theirRows[k]) >= numRows)
00636                              theirRowsValid = false;
00637                          }
00638                        if (! theirRowsValid)
00639                          {
00640                            std::ostringstream os;
00641                            std::copy (theirRows.begin(), theirRows.end(), 
00642                                       std::ostream_iterator<GO>(os, " "));
00643                            TEUCHOS_TEST_FOR_EXCEPTION(! theirRowsValid, 
00644                                               std::logic_error,
00645                                               "Proc " << p << " has at least "
00646                                               "one invalid row index.  Here are"
00647                                               " all of them: [ " << os.str() 
00648                                               << "]");
00649                          }
00650                      }
00651 
00652                      // Perhaps we could save a little work if we
00653                      // check whether Proc p's row indices are
00654                      // contiguous.  That would make lookups in the
00655                      // global data arrays faster.  For now, we just
00656                      // implement the general case and don't
00657                      // prematurely optimize.  (Remember that you're
00658                      // making Proc 0 read the whole file, so you've
00659                      // already lost scalability.)
00660 
00661                      // Compute the number of entries in each of Proc
00662                      // p's rows.  (Proc p will compute its row
00663                      // pointer array on its own, after it gets the
00664                      // data from Proc 0.)
00665                      ArrayRCP<size_t> theirNumEntriesPerRow;
00666                      theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
00667                      for (size_type k = 0; k < theirNumRows; ++k)
00668                        theirNumEntriesPerRow[k] = 
00669        numEntriesPerRow[theirRows[k]];
00670 
00671                      // Tell Proc p the number of entries in each of
00672                      // its rows.  Hopefully the cast to int doesn't
00673                      // overflow.  This is unlikely, since it should
00674                      // fit in a LO, even though it is
00675                      // a GO.
00676                      send (*pComm, static_cast<int> (theirNumRows), 
00677                            theirNumEntriesPerRow.getRawPtr(), p);
00678 
00679                      // Figure out how many entries Proc p owns.
00680                      const size_t theirNumEntries = 
00681                        std::accumulate (theirNumEntriesPerRow.begin(),
00682                                         theirNumEntriesPerRow.end(), 
00683                                         static_cast<size_t> (0));
00684 
00685                      if (debug)
00686                        cerr << "-- Proc 0: Proc " << p << " owns " 
00687                             << theirNumEntries << " entries" << endl;
00688 
00689                      // If there are no entries to send, then we're
00690                      // done with Proc p.
00691                      if (theirNumEntries == 0)
00692                        continue; 
00693 
00694                      // Construct (views of) proc p's column indices
00695                      // and values.  Later, we might like to optimize
00696                      // for the (common) contiguous case, for which we
00697                      // don't need to copy data into separate "their*"
00698                      // arrays (we can just use contiguous views of
00699                      // the global arrays).
00700                      ArrayRCP<GO> theirColInd = arcp<GO> (theirNumEntries);
00701                      ArrayRCP<scalar_type> theirValues = 
00702                        arcp<scalar_type> (theirNumEntries);
00703                      // Copy Proc p's part of the matrix into the
00704                      // their* arrays.  It's important that
00705                      // theirCurPos be updated _before_ k, otherwise
00706                      // theirCurPos will get the wrong number of
00707                      // entries per row (it should be for the row in
00708                      // the just-completed iteration, not for the next
00709                      // iteration's row).
00710                      size_t theirCurPos = 0;
00711                      for (size_type k = 0; k < theirNumRows; 
00712                           theirCurPos += theirNumEntriesPerRow[k], k++)
00713                        {
00714                          const size_t curNumEntries = theirNumEntriesPerRow[k];
00715                          const GO theirRow = theirRows[k];
00716                          const size_t curPos = rowPtr[theirRow];
00717 
00718                          // Only copy if there are entries to copy, in
00719                          // order not to construct empty ranges for
00720                          // the ArrayRCP views.
00721                          if (curNumEntries > 0)
00722                            {
00723                              ArrayView<GO> colIndView = 
00724              colInd(curPos, curNumEntries);
00725                              ArrayView<GO> theirColIndView = 
00726                                theirColInd(theirCurPos, curNumEntries);
00727                              std::copy (colIndView.begin(), colIndView.end(), 
00728                                         theirColIndView.begin());
00729                          
00730                              ArrayView<scalar_type> valuesView = 
00731                                values(curPos, curNumEntries);
00732                              ArrayView<scalar_type> theirValuesView = 
00733                                theirValues(theirCurPos, curNumEntries);
00734                              std::copy (valuesView.begin(), valuesView.end(), 
00735                                         theirValuesView.begin());
00736                            }
00737                        }
00738                      // Send Proc p its column indices and values.
00739                      // Hopefully the cast to int doesn't overflow.
00740                      // This is unlikely, since it should fit in a LO,
00741                      // even though it is a GO.
00742                      send (*pComm, static_cast<int> (theirNumEntries), 
00743                            theirColInd.getRawPtr(), p);
00744                      send (*pComm, static_cast<int> (theirNumEntries), 
00745                            theirValues.getRawPtr(), p);
00746 
00747                      if (debug)
00748                        cerr << "-- Proc 0: Finished with proc " << p << endl;
00749                    } // If proc p owns at least one row
00750                } // For each proc p not the root proc 0
00751            } // If I'm (not) the root proc 0
00752 
00753          // Invalidate the input data to save space, since we don't
00754          // need it anymore.
00755          numEntriesPerRow = null;
00756          rowPtr = null;
00757          colInd = null;
00758          values = null;
00759 
00760          if (debug && myRank == 0)
00761            cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
00762 
00763          // Allocate and fill in myRowPtr (the row pointer array for
00764          // my rank's rows).  We delay this until the end because we
00765          // don't need it to compute anything else in distribute().
00766          // Each proc can do this work for itself, since it only needs
00767          // myNumEntriesPerRow to do so.
00768          myRowPtr = arcp<size_type> (myNumRows+1);
00769          myRowPtr[0] = 0;
00770          for (size_type k = 1; k < myNumRows+1; ++k)
00771            myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
00772          if (extraDebug && debug)
00773            {
00774              cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm())) 
00775                   << ": myRowPtr[0.." << myNumRows << "] = [";
00776              for (size_type k = 0; k < myNumRows+1; ++k)
00777                {
00778                  cerr << myRowPtr[k];
00779                  if (k < myNumRows)
00780                    cerr << " ";
00781                }
00782              cerr << "]" << endl << endl;
00783            }
00784 
00785          if (debug && myRank == 0)
00786            cerr << "-- Proc 0: Done with distribute" << endl;
00787       }
00788 
00799       static sparse_matrix_ptr
00800       makeMatrix (ArrayRCP<size_t>& myNumEntriesPerRow,
00801                   ArrayRCP<size_type>& myRowPtr,
00802                   ArrayRCP<global_ordinal_type>& myColInd,
00803                   ArrayRCP<scalar_type>& myValues,
00804                   const map_ptr& pRowMap,
00805                   const map_ptr& pRangeMap,
00806                   const map_ptr& pDomainMap,
00807                   const bool callFillComplete = true)
00808       {
00809         using std::cerr;
00810         using std::endl;
00811   // Typedef to make certain type declarations shorter.
00812   typedef global_ordinal_type GO;
00813 
00814   const bool extraDebug = false;
00815         const bool debug = false;
00816 
00817         // The row pointer array always has at least one entry, even
00818         // if the matrix has zero rows.  myNumEntriesPerRow, myColInd,
00819         // and myValues would all be empty arrays in that degenerate
00820         // case, but the row and domain maps would still be nonnull
00821         // (though they would be trivial maps).
00822         TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
00823                            "makeMatrix: myRowPtr array is null.  "
00824                            "Please report this bug to the Tpetra developers.");
00825         TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
00826                            "makeMatrix: domain map is null.  "
00827                            "Please report this bug to the Tpetra developers.");
00828         TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
00829                            "makeMatrix: range map is null.  "
00830                            "Please report this bug to the Tpetra developers.");
00831         TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
00832                            "makeMatrix: row map is null.  "
00833                            "Please report this bug to the Tpetra developers.");
00834 
00835         // Handy for debugging output; not needed otherwise.
00836         const int myRank = Teuchos::rank (*(pRangeMap->getComm()));
00837 
00838         if (extraDebug && debug)
00839           {
00840             cerr << "Proc " << myRank << ":" << endl
00841                  << "-- myRowPtr = [ ";
00842             std::copy (myRowPtr.begin(), myRowPtr.end(), 
00843                        std::ostream_iterator<size_type>(cerr, " "));
00844             cerr << "]" << endl << "-- myColInd = [ ";
00845             std::copy (myColInd.begin(), myColInd.end(), 
00846                        std::ostream_iterator<size_type>(cerr, " "));
00847             cerr << "]" << endl << endl;
00848           }
00849 
00850         // Go through all of my columns, and see if any are not in the
00851         // domain map.  This is possible if numProcs > 1, otherwise
00852         // not.
00853         if (extraDebug && debug)
00854           {
00855             size_type numRemote = 0;
00856             std::vector<GO> remoteGIDs;
00857 
00858             typedef typename ArrayRCP<GO>::const_iterator iter_type;
00859             for (iter_type it = myColInd.begin(); it != myColInd.end(); ++it)
00860               {
00861                 if (! pDomainMap->isNodeGlobalElement (*it))
00862                   {
00863                     numRemote++;
00864                     remoteGIDs.push_back (*it);
00865                   }
00866               }
00867             if (numRemote > 0)
00868               {
00869                 cerr << "Proc " << myRank << ": " << numRemote 
00870                      << " remote GIDs = [ " << endl;
00871                 std::copy (remoteGIDs.begin(), remoteGIDs.end(),
00872                            std::ostream_iterator<GO>(cerr, " "));
00873                 cerr << "]" << endl;
00874               }
00875           }
00876 
00877         // Construct the CrsMatrix, using the row map, with the
00878         // constructor specifying the number of nonzeros for each row.
00879         // Create with DynamicProfile, so that the fillComplete() can
00880         // do first-touch reallocation (a NUMA (Non-Uniform Memory
00881         // Access) optimization on multicore CPUs).
00882         sparse_matrix_ptr A = 
00883           rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow, 
00884                                        DynamicProfile));
00885         TEUCHOS_TEST_FOR_EXCEPTION(A.is_null(), std::logic_error,
00886                            "makeMatrix: Initial allocation of CrsMatrix failed"
00887                            ".  Please report this bug to the Tpetra developers"
00888                            ".");
00889         // List of the global indices of my rows.
00890         // They may or may not be contiguous.
00891         ArrayView<const GO> myRows = pRowMap->getNodeElementList();
00892         const size_type myNumRows = myRows.size();
00893 
00894         // Add this processor's matrix entries to the CrsMatrix.
00895         for (size_type k = 0; k < myNumRows; ++k)
00896           {
00897             const size_type myCurPos = myRowPtr[k];
00898             const size_t curNumEntries = myNumEntriesPerRow[k];
00899 
00900             if (extraDebug && debug)
00901               {
00902                 cerr << "Proc " << myRank << ": k = " << k 
00903                      << ", myCurPos = " << myCurPos
00904                      << ", curNumEntries = " << curNumEntries
00905                      << endl;
00906               }
00907             // Avoid constructing empty views of ArrayRCP objects.
00908             if (curNumEntries > 0)
00909               A->insertGlobalValues (myRows[k], 
00910                                      myColInd(myCurPos, curNumEntries),
00911                                      myValues(myCurPos, curNumEntries));
00912           }
00913         // We've entered in all our matrix entries, so we can delete
00914         // the original data.  This will save memory when we call
00915         // fillComplete(), so that we never keep more than two copies
00916         // of the matrix's data in memory at once.
00917         myNumEntriesPerRow = null;
00918         myRowPtr = null;
00919         myColInd = null;
00920         myValues = null;
00921 
00922         if (callFillComplete)
00923           A->fillComplete (pDomainMap, pRangeMap, DoOptimizeStorage);
00924         return A;
00925       }
00926 
00927     private:
00928 
00945       static RCP<const Banner>
00946       readBanner (std::istream& in,
00947                   size_t& lineNumber,
00948                   const comm_ptr& pComm,
00949                   const bool tolerant=false,
00950                   const bool debug=false)
00951       {
00952         using std::cerr;
00953         using std::endl;
00954 
00955         const int myRank = Teuchos::rank (*pComm);
00956 
00957         // The pointer will be non-null on return only on MPI Rank 0.
00958         // Using a pointer lets the data persist outside the
00959         // "myRank==0" scopes.
00960         RCP<Banner> pBanner;
00961         if (myRank == 0)
00962           {
00963             typedef Teuchos::ScalarTraits<scalar_type> STS;
00964 
00965             std::string line;
00966             // Try to read a line from the input stream.
00967             const bool readFailed = ! getline(in, line);
00968             TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
00969                                "Failed to get Matrix Market banner line "
00970                                "from input.");
00971             // We read a line from the input stream.
00972             lineNumber++; 
00973 
00974             // Assume that the line we found is the banner line.
00975             try {
00976               pBanner = rcp (new Banner (line, tolerant));
00977             } catch (std::exception& e) {
00978               TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 
00979                                  "Matrix Market banner line contains syntax "
00980                                  "error(s): " << e.what());
00981             }
00982             TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
00983                                std::invalid_argument,
00984                                "The Matrix Market file does not contain "
00985                                "matrix data.  Its banner (first) line says that"
00986                                " its object type is \"" << pBanner->matrixType()
00987                                << "\", rather than the required \"matrix\".");
00988 
00989             // Validate the data type of the matrix, with respect to
00990             // the Scalar type of the CrsMatrix entries.
00991             TEUCHOS_TEST_FOR_EXCEPTION(! STS::isComplex && 
00992              pBanner->dataType() == "complex",
00993                                std::invalid_argument,
00994                                "The Matrix Market file contains complex-valued "
00995                                "data, but you are trying to read it into a "
00996                                "matrix containing entries of the real-valued "
00997                                "Scalar type \"" 
00998                                << Teuchos::TypeNameTraits<scalar_type>::name() 
00999                                << "\".");
01000             TEUCHOS_TEST_FOR_EXCEPTION(pBanner->dataType() != "real" && 
01001                                pBanner->dataType() != "complex" && 
01002                                pBanner->dataType() != "integer",
01003                                std::invalid_argument,
01004                                "When reading Matrix Market data into a "
01005                                "CrsMatrix, the Matrix Market file may not "
01006                                "contain a \"pattern\" matrix.  A pattern matrix"
01007                                " is really just a graph with no weights.  It "
01008                                "should be stored in a CrsGraph, not a "
01009                                "CrsMatrix.");
01010           }
01011         return pBanner;
01012       }
01013 
01036       static Tuple<global_ordinal_type, 3>
01037       readCoordDims (std::istream& in,
01038                      size_t& lineNumber,
01039                      const RCP<const Banner>& pBanner,
01040                      const comm_ptr& pComm,
01041                      const bool tolerant = false,
01042                      const bool debug = false)
01043       {
01044         // Packed coordinate matrix dimensions (numRows, numCols,
01045         // numNonzeros); computed on Rank 0 and broadcasted to all MPI
01046         // ranks.
01047         Tuple<global_ordinal_type, 3> dims;
01048 
01049         // Read in the coordinate matrix dimensions from the input
01050         // stream.  "success" tells us whether reading in the
01051         // coordinate matrix dimensions succeeded ("Guilty unless
01052         // proven innocent").
01053         bool success = false;
01054         if (pComm->getRank() == 0) {
01055     TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate", 
01056             std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
01057       "only accepts \"coordinate\" (sparse) matrix data.");
01058     // Unpacked coordinate matrix dimensions
01059     global_ordinal_type numRows, numCols, numNonzeros;
01060     // Only MPI Rank 0 reads from the input stream
01061     success = readCoordinateDimensions (in, numRows, numCols, 
01062                 numNonzeros, lineNumber, 
01063                 tolerant);
01064     // Pack up the data into a Tuple so we can send them with
01065     // one broadcast instead of three.
01066     dims[0] = numRows;
01067     dims[1] = numCols;
01068     dims[2] = numNonzeros;
01069   }
01070         // Only Rank 0 did the reading, so it decides success.
01071         //
01072         // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
01073         // to send bools.  For now, we convert to/from int instead,
01074         // using the usual "true is 1, false is 0" encoding.
01075         {
01076           int the_success = success ? 1 : 0; // only matters on MPI Rank 0
01077           Teuchos::broadcast (*pComm, 0, &the_success);
01078           success = (the_success == 1);
01079         }
01080         if (success) {
01081           // Broadcast (numRows, numCols, numNonzeros) from Rank 0
01082           // to all the other MPI ranks.  
01083           Teuchos::broadcast (*pComm, 0, dims);
01084   }
01085         else {
01086           // Perhaps in tolerant mode, we could set all the
01087           // dimensions to zero for now, and deduce correct
01088           // dimensions by reading all of the file's entries and
01089           // computing the max(row index) and max(column index).
01090           // However, for now we just error out in that case.
01091     TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
01092       "Error reading Matrix Market sparse matrix: failed to read "
01093             "coordinate matrix dimensions.");
01094   }
01095         return dims;
01096       }
01097       
01108       typedef SymmetrizingAdder<Raw::Adder<scalar_type, global_ordinal_type> >
01109         adder_type;
01110 
01136       static RCP<adder_type>
01137       makeAdder (const RCP<const Comm<int> >& pComm,
01138                  RCP<const Banner>& pBanner, 
01139                  const Tuple<global_ordinal_type, 3>& dims,
01140                  const bool tolerant=false,
01141                  const bool debug=false)
01142       {
01143         if (pComm->getRank() == 0) {
01144     typedef Raw::Adder<scalar_type, global_ordinal_type> raw_adder_type;
01145     RCP<raw_adder_type> pRaw = 
01146       rcp (new raw_adder_type (dims[0], dims[1], dims[2], tolerant, debug));
01147     return rcp (new adder_type (pRaw, pBanner->symmType()));
01148   }
01149   else {
01150           return null;
01151   }
01152       }
01153 
01154     public:
01155 
01180       static sparse_matrix_ptr
01181       readSparseFile (const std::string& filename,
01182                       const RCP<const Comm<int> >& pComm, 
01183                       const RCP<node_type>& pNode,
01184                       const bool callFillComplete=true,
01185                       const bool tolerant=false,
01186                       const bool debug=false)
01187       {
01188         const int myRank = Teuchos::rank (*pComm);
01189         std::ifstream in;
01190 
01191         // Only open the file on Rank 0.
01192         if (myRank == 0)
01193           in.open (filename.c_str());
01194         return readSparse (in, pComm, pNode, callFillComplete, tolerant, debug);
01195         // We can rely on the destructor of the input stream to close
01196         // the file on scope exit, even if readSparse() throws an
01197         // exception.
01198       }
01199 
01226       static sparse_matrix_ptr
01227       readSparse (std::istream& in,        
01228                   const RCP<const Comm<int> >& pComm, 
01229                   const RCP<node_type>& pNode,
01230                   const bool callFillComplete=true,
01231                   const bool tolerant=false,
01232                   const bool debug=false)
01233       {
01234         using std::cerr;
01235         using std::endl;
01236         typedef Teuchos::ScalarTraits<scalar_type> STS;
01237 
01238         const bool extraDebug = false;
01239         const int myRank = Teuchos::rank (*pComm);
01240 
01241         // Current line number in the input stream.  Various calls
01242         // will modify this depending on the number of lines that are
01243         // read from the input stream.  Only Rank 0 modifies this.
01244         size_t lineNumber = 1;
01245 
01246         if (debug && myRank == 0) {
01247           cerr << "Matrix Market reader: readSparse:" << endl
01248          << "-- Reading banner line" << endl;
01249   }
01250 
01251         // The "Banner" tells you whether the input stream represents
01252         // a sparse matrix, the symmetry type of the matrix, and the
01253         // type of the data it contains.
01254         //
01255         // pBanner will only be nonnull on MPI Rank 0.  It will be
01256         // null on all other MPI processes.
01257         RCP<const Banner> pBanner;
01258         if (myRank == 0)
01259           { // Read the Banner line from the input stream.
01260             pBanner = readBanner (in, lineNumber, pComm, tolerant, debug);
01261             // Validate the Banner for the case of a sparse matrix.
01262 
01263             // In tolerant mode, we allow the matrix type to be
01264             // anything other than "array" (which would mean that the
01265             // file contains a dense matrix).
01266             TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && 
01267              pBanner->matrixType() != "coordinate",
01268                                std::runtime_error,
01269                                "Matrix Market file must contain a "
01270                                "\"coordinate\"-format sparse matrix in "
01271                                "order to create a Tpetra::CrsMatrix "
01272                                "object from it, but the file's matrix "
01273                                "type is \"" << pBanner->matrixType() 
01274                                << "\" instead.");
01275 
01276             // In tolerant mode, we allow the matrix type to be
01277             // anything other than "array" (which would mean that the
01278             // file contains a dense matrix).
01279             TEUCHOS_TEST_FOR_EXCEPTION(tolerant && pBanner->matrixType() == "array",
01280                                std::runtime_error,
01281                                "Matrix Market file must contain a "
01282                                "\"coordinate\"-format sparse matrix in "
01283                                "order to create a Tpetra::CrsMatrix "
01284                                "object from it, but the file's matrix "
01285                                "type is \"array\" instead.  That means the "
01286                                "file contains dense matrix data.");
01287           }
01288         if (debug && myRank == 0)
01289           cerr << "-- Reading dimensions line" << endl;
01290 
01291         // Read the matrix dimensions from the Matrix Market metadata.
01292         // dims = (numRows, numCols, numEntries).  Rank 0 does the
01293         // reading, but it broadcasts the results to all MPI
01294         // processes.  Thus, readCoordDims() is a collective
01295         // operation.
01296         Tuple<global_ordinal_type, 3> dims = 
01297           readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
01298 
01299         if (debug && myRank == 0)
01300           cerr << "-- Making Adder for collecting matrix data" << endl;
01301 
01302         // "Adder" object for collecting all the sparse matrix entries
01303         // from the input stream.  This is only nonnull on Rank 0.
01304         RCP<adder_type> pAdder =
01305           makeAdder (pComm, pBanner, dims, tolerant, debug);
01306 
01307         if (debug && myRank == 0)
01308           cerr << "-- Reading matrix data" << endl;
01309         //
01310         // Read the matrix entries from the input stream on Rank 0.
01311         //
01312         // We use readSuccess to broadcast the results of the read
01313         // (succeeded or not) to all MPI processes.  "Guilty until
01314         // proven innocent" (the read didn't succeed unless we
01315         // proclaim that it did).
01316         bool readSuccess = false;
01317         if (myRank == 0) {
01318     // Reader for "coordinate" format sparse matrix data.
01319     typedef CoordDataReader<adder_type, global_ordinal_type, 
01320       scalar_type, STS::isComplex> reader_type;
01321     reader_type reader (pAdder);
01322 
01323     // Read the sparse matrix entries.
01324     //
01325     // FIXME (mfh 28 Mar 2011) We should catch exceptions
01326     // here, and broadcast any error messages to all
01327     // processors so that the exception can be rethrown
01328     // everywhere (fail fast and hard, rather than hoping that
01329     // MPI propagates the exceptions quickly).
01330     std::pair<bool, std::vector<size_t> > results = 
01331       reader.read (in, lineNumber, tolerant, debug);
01332 
01333     readSuccess = results.first;
01334   }
01335         // The broadcast of readSuccess from MPI Rank 0 serves as a
01336         // barrier.  Note that Tpetra::CrsMatrix::fillComplete() only
01337         // starts with a barrier in debug mode, so we need some kind
01338         // of barrier or synchronization beforehand.
01339         //
01340         // Currently, Teuchos::broadcast doesn't know how to send
01341         // bools.  For now, we convert to/from int instead, using the
01342         // usual "true is 1, false is 0" encoding.
01343         {
01344     // The value of this Boolean only matters on MPI Proc 0.
01345           int the_readSuccess = readSuccess ? 1 : 0;
01346           Teuchos::broadcast (*pComm, 0, &the_readSuccess);
01347           readSuccess = (the_readSuccess == 1);
01348         }
01349         // It would be nice to add a "verbose" flag, so that in
01350         // tolerant mode, we could log any bad line number(s) on MPI
01351         // Rank 0.  For now, we just throw if the read fails to
01352         // succeed.
01353         //
01354         // Question: Should we run fillComplete() in tolerant mode, if
01355         // the read did not succeed?
01356         TEUCHOS_TEST_FOR_EXCEPTION(! readSuccess, std::runtime_error,
01357                            "Failed to read in the Matrix Market sparse "
01358                            "matrix.");
01359         if (debug && myRank == 0)
01360           cerr << "-- Successfully read the Matrix Market data" << endl;
01361 
01362         // In tolerant mode, we need to rebroadcast the matrix
01363         // dimensions, since they may be different after reading the
01364         // actual matrix data.  We only need to broadcast the number
01365         // of rows and columns.  Only Rank 0 needs to know the actual
01366         // global number of entries, since (a) we need to merge
01367         // duplicates on Rank 0 first anyway, and (b) when we
01368         // distribute the entries, each rank other than Rank 0 will
01369         // only need to know how many entries it owns, not the total
01370         // number of entries.
01371         if (tolerant)
01372           {
01373             if (debug && myRank == 0)
01374               {
01375                 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions" 
01376                      << endl
01377                      << "----- Dimensions before: " 
01378          << dims[0] << " x " << dims[1]
01379                      << endl;
01380               }
01381             // Packed coordinate matrix dimensions (numRows, numCols).
01382             Tuple<global_ordinal_type, 2> updatedDims;
01383             if (myRank == 0)
01384               { // If one or more bottom rows of the matrix contain no
01385                 // entries, then the Adder will report that the number
01386                 // of rows is less than that specified in the
01387                 // metadata.  We allow this case, and favor the
01388                 // metadata so that the zero row(s) will be included.
01389                 updatedDims[0] = 
01390       std::max (dims[0], pAdder->getAdder()->numRows());
01391                 updatedDims[1] = pAdder->getAdder()->numCols();
01392               }
01393             Teuchos::broadcast (*pComm, 0, updatedDims);
01394             dims[0] = updatedDims[0];
01395             dims[1] = updatedDims[1];
01396             if (debug && myRank == 0) {
01397         cerr << "----- Dimensions after: " << dims[0] << " x " 
01398        << dims[1] << endl;
01399       }
01400           }
01401         else 
01402           { // In strict mode, we require that the matrix's metadata
01403             // and its actual data agree, at least somewhat.  In
01404             // particular, the number of rows must agree, since
01405             // otherwise we cannot distribute the matrix correctly.
01406 
01407             // Teuchos::broadcast() doesn't know how to broadcast
01408             // bools, so we use an int with the standard 1 == true, 0
01409             // == false encoding.
01410             int dimsMatch = 1;
01411             if (myRank == 0)
01412               { // If one or more bottom rows of the matrix contain no
01413                 // entries, then the Adder will report that the number
01414                 // of rows is less than that specified in the
01415                 // metadata.  We allow this case, and favor the
01416                 // metadata, but do not allow the Adder to think there
01417                 // are more rows in the matrix than the metadata says.
01418                 if (dims[0] < pAdder->getAdder()->numRows())
01419                   dimsMatch = 0;
01420               }
01421             Teuchos::broadcast (*pComm, 0, &dimsMatch);
01422             if (dimsMatch == 0)
01423               { // We're in an error state anyway, so we might as well
01424                 // work a little harder to print an informative error
01425                 // message.
01426                 //
01427                 // Broadcast the Adder's idea of the matrix dimensions
01428                 // from Proc 0 to all processes.
01429                 Tuple<global_ordinal_type, 2> addersDims;
01430                 if (myRank == 0)
01431                   {
01432                     addersDims[0] = pAdder->getAdder()->numRows();
01433                     addersDims[1] = pAdder->getAdder()->numCols();
01434                   }
01435                 Teuchos::broadcast (*pComm, 0, addersDims);
01436                 TEUCHOS_TEST_FOR_EXCEPTION(dimsMatch == 0, std::runtime_error,
01437                                    "The matrix metadata says that the matrix is "
01438                                    << dims[0] << " x " << dims[1] << ", but the "
01439                                    "actual data says that the matrix is " 
01440                                    << addersDims[0] << " x " << addersDims[1]
01441                                    << ".  That means the data includes more "
01442                                    "rows than reported in the metadata.  This "
01443                                    "is not allowed when parsing in strict mode."
01444                                    "  Parse the matrix in tolerant mode to "
01445                                    "ignore the metadata when it disagrees with "
01446                                    "the data.");
01447               }
01448           }
01449 
01450         if (debug && myRank == 0)
01451           cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
01452 
01453         // Now that we've read in all the matrix entries from the
01454         // input stream into the adder on Rank 0, post-process them
01455         // into CSR format (still on Rank 0).  This will facilitate
01456         // distributing them to all the processors.
01457         //
01458         // These arrays represent the global matrix data as a CSR
01459         // matrix (with numEntriesPerRow as redundant but convenient
01460         // metadata, since it's computable from rowPtr and vice
01461         // versa).  They are valid only on Rank 0.
01462         ArrayRCP<size_t> numEntriesPerRow;
01463         ArrayRCP<size_type> rowPtr;
01464         ArrayRCP<global_ordinal_type> colInd;
01465         ArrayRCP<scalar_type> values;
01466 
01467         // Rank 0 first merges duplicate entries, and then converts
01468         // the coordinate-format matrix data to CSR.
01469         if (myRank == 0)
01470           {
01471             typedef Raw::Element<scalar_type, global_ordinal_type> element_type;
01472             typedef typename std::vector<element_type>::const_iterator iter_type;
01473 
01474             // Additively merge duplicate matrix entries.
01475             pAdder->getAdder()->merge ();
01476 
01477             // Get a temporary const view of the merged matrix entries.
01478             const std::vector<element_type>& entries = 
01479               pAdder->getAdder()->getEntries();
01480 
01481             // Number of rows in the matrix.  If we are in tolerant
01482             // mode, we've already synchronized dims with the actual
01483             // matrix data.  If in strict mode, we should use dims (as
01484             // read from the file's metadata) rather than the matrix
01485             // data to determine the dimensions.  (The matrix data
01486             // will claim fewer rows than the metadata, if one or more
01487             // rows have no entries stored in the file.)
01488             const size_type numRows = dims[0]; 
01489 
01490             // Number of matrix entries (after merging).
01491             const size_type numEntries = entries.size();
01492 
01493             if (debug)
01494               cerr << "----- Proc 0: Matrix has numRows=" << numRows 
01495                    << " rows and numEntries=" << numEntries 
01496                    << " entries." << endl;
01497 
01498             // Make space for the CSR matrix data.  The conversion to
01499             // CSR algorithm is easier if we fill numEntriesPerRow
01500             // with zeros at first.
01501             numEntriesPerRow = arcp<size_t> (numRows);
01502             std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 
01503                        static_cast<size_t>(0));
01504             rowPtr = arcp<size_type> (numRows+1);
01505             std::fill (rowPtr.begin(), rowPtr.end(), 
01506                        static_cast<size_type>(0));
01507             colInd = arcp<global_ordinal_type> (numEntries);
01508             values = arcp<scalar_type> (numEntries);
01509 
01510             // Convert from array-of-structs coordinate format to CSR
01511             // (compressed sparse row) format.
01512             {
01513               global_ordinal_type prvRow = 0;
01514               size_type curPos = 0;
01515               rowPtr[0] = 0;
01516               for (curPos = 0; curPos < numEntries; ++curPos)
01517                 {
01518                   const element_type& curEntry = entries[curPos];
01519                   const global_ordinal_type curRow = curEntry.rowIndex();
01520                   TEUCHOS_TEST_FOR_EXCEPTION(curRow < prvRow, std::logic_error,
01521                                      "Row indices out of order, even though "
01522                                      "they are supposed to be sorted.  curRow"
01523                                      " = " << curRow << ", prvRow = " 
01524                                      << prvRow << ", at curPos = " << curPos 
01525                                      << ".  Please report this bug to the "
01526                                      "Tpetra developers.");
01527                   if (curRow > prvRow)
01528                     {
01529                       for (size_type r = prvRow+1; r <= curRow; ++r)
01530                         rowPtr[r] = curPos;
01531                       prvRow = curRow;
01532                     }
01533                   numEntriesPerRow[curRow]++;
01534                   colInd[curPos] = curEntry.colIndex();
01535                   values[curPos] = curEntry.value();
01536                 }
01537               // rowPtr has one more entry than numEntriesPerRow.  The
01538               // last entry of rowPtr is the number of entries in
01539               // colInd and values.
01540               rowPtr[numRows] = numEntries;
01541             }
01542             if (debug)
01543               {
01544                 const size_type maxToDisplay = 100;
01545 
01546                 cerr << "----- Proc 0: numEntriesPerRow[0.." 
01547          << (numEntriesPerRow.size()-1) << "] ";
01548                 if (numRows > maxToDisplay)
01549                   cerr << "(only showing first and last few entries) ";
01550                 cerr << "= [";
01551                 if (numRows > 0)
01552                   {
01553                     if (numRows > maxToDisplay)
01554                       {
01555                         for (size_type k = 0; k < 2; ++k)
01556                           cerr << numEntriesPerRow[k] << " ";
01557                         cerr << "... ";
01558                         for (size_type k = numRows-2; k < numRows-1; ++k)
01559                           cerr << numEntriesPerRow[k] << " ";
01560                       }
01561                     else
01562                       {                   
01563                         for (size_type k = 0; k < numRows-1; ++k)
01564                           cerr << numEntriesPerRow[k] << " ";
01565                       }
01566                     cerr << numEntriesPerRow[numRows-1];
01567                   }
01568                 cerr << "]" << endl;
01569 
01570                 cerr << "----- Proc 0: rowPtr ";
01571                 if (numRows > maxToDisplay)
01572                   cerr << "(only showing first and last few entries) ";
01573                 cerr << "= [";
01574                 if (numRows > maxToDisplay)
01575                   {
01576                     for (size_type k = 0; k < 2; ++k)
01577                       cerr << rowPtr[k] << " ";
01578                     cerr << "... ";
01579                     for (size_type k = numRows-2; k < numRows; ++k)
01580                       cerr << rowPtr[k] << " ";
01581                   }
01582                 else
01583                   {
01584                     for (size_type k = 0; k < numRows; ++k)
01585                       cerr << rowPtr[k] << " ";
01586                   }
01587                 cerr << rowPtr[numRows] << "]" << endl;
01588               }
01589           } // if (myRank == 0)
01590 
01591         // Now we're done with the Adder, so we can release the
01592         // reference ("free" it) to save space.  This only actually
01593         // does anything on Rank 0, since pAdder is null on all the
01594         // other MPI processes.
01595         pAdder = null;
01596 
01597         if (debug && myRank == 0)
01598           cerr << "-- Making range, domain, and row maps" << endl;
01599 
01600         // Make the maps that describe the matrix'x range and domain,
01601         // and the distribution of its rows.
01602         map_ptr pRangeMap = makeRangeMap (pComm, pNode, dims[0]);
01603         map_ptr pDomainMap = makeDomainMap (pRangeMap, dims[0], dims[1]);
01604         map_ptr pRowMap = makeRowMap (null, pComm, pNode, dims[0]);
01605 
01606         if (debug && myRank == 0)
01607           cerr << "-- Distributing the matrix data" << endl;
01608 
01609         // Distribute the matrix data.  Each processor has to add the
01610         // rows that it owns.  If you try to make Rank 0 call
01611         // insertGlobalValues() for _all_ the rows, not just those it
01612         // owns, then fillComplete() will compute the number of
01613         // columns incorrectly.  That's why Rank 0 has to distribute
01614         // the matrix data and why we make all the processors (not
01615         // just Rank 0) call insertGlobalValues() on their own data.
01616         //
01617         // These arrays represent each processor's part of the matrix
01618         // data, in "CSR" format (sort of, since the row indices might
01619         // not be contiguous).
01620         ArrayRCP<size_t> myNumEntriesPerRow;
01621         ArrayRCP<size_type> myRowPtr;
01622         ArrayRCP<global_ordinal_type> myColInd;
01623         ArrayRCP<scalar_type> myValues;
01624         // Distribute the matrix data.
01625         distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
01626                     numEntriesPerRow, rowPtr, colInd, values, debug);
01627 
01628         if (debug && myRank == 0)
01629           {
01630             cerr << "-- Inserting matrix entries on each processor";
01631             if (callFillComplete)
01632               cerr << " and calling fillComplete()";
01633             cerr << endl;
01634           }
01635         // Each processor inserts its part of the matrix data, and
01636         // then they all call fillComplete().  This method invalidates
01637         // the my* distributed matrix data before calling
01638         // fillComplete(), in order to save space.  In general, we
01639         // never store more than two copies of the matrix's entries in
01640         // memory at once, which is no worse than what Tpetra
01641         // promises.
01642         sparse_matrix_ptr pMatrix = 
01643           makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
01644                       pRowMap, pRangeMap, pDomainMap, callFillComplete);
01645         TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
01646                            "Reader::makeMatrix() returned a null pointer.  "
01647                            "Please report this bug to the Tpetra developers.");
01648 
01649         // We can't get the dimensions of the matix until after
01650         // fillComplete() is called.  Thus, we can't do the sanity
01651         // check (dimensions read from the Matrix Market data,
01652         // vs. dimensions reported by the CrsMatrix) unless the user
01653         // asked makeMatrix() to call fillComplete().
01654         //
01655         // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
01656         // what one might think it does, so you have to ask the range
01657         // resp. domain map for the number of rows resp. columns.
01658         if (callFillComplete)
01659           {
01660             if (extraDebug && debug)
01661               {
01662                 const global_size_t globalNumRows = 
01663                   pRangeMap->getGlobalNumElements();
01664                 const global_size_t globalNumCols = 
01665                   pDomainMap->getGlobalNumElements();
01666                 if (myRank == 0)
01667                   {
01668                     cerr << "-- Matrix is " 
01669                          << globalNumRows << " x " << globalNumCols 
01670                          << " with " << pMatrix->getGlobalNumEntries()
01671                          << " entries, and index base " 
01672                          << pMatrix->getIndexBase() << "." << endl;
01673                   }
01674                 Teuchos::barrier (*pComm);
01675                 for (int p = 0; p < Teuchos::size (*pComm); ++p)
01676                   {
01677                     if (myRank == p)
01678                       {
01679                         cerr << "-- Proc " << p << " owns " 
01680                              << pMatrix->getNodeNumCols() 
01681                              << " columns, and " 
01682                              << pMatrix->getNodeNumEntries()
01683                              << " entries." << endl;
01684                       }
01685                     Teuchos::barrier (*pComm);
01686                   }
01687               } // if (extraDebug && debug)
01688           } // if (callFillComplete)
01689 
01690         if (debug && myRank == 0)
01691           cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
01692          << endl;
01693 
01694         return pMatrix;
01695       }
01696 
01726       static RCP<multivector_type>
01727       readDenseFile (const std::string& filename,
01728                      const RCP<const comm_type>& pComm, 
01729                      const RCP<node_type>& pNode,
01730                      RCP<const map_type>& pMap,
01731                      const bool tolerant=false,
01732                      const bool debug=false)
01733       {
01734         const int myRank = Teuchos::rank (*pComm);
01735         std::ifstream in;
01736 
01737         // Only open the file on Rank 0.
01738         if (myRank == 0)
01739           in.open (filename.c_str());
01740         return readDense (in, pComm, pNode, pMap, tolerant, debug);
01741         // We can rely on the destructor of the input stream to close
01742         // the file on scope exit, even if readSparse() throws an
01743         // exception.
01744       }
01745 
01810       static RCP<multivector_type>
01811       readDense (std::istream& in,
01812                  const RCP<const comm_type>& pComm,
01813                  const RCP<node_type>& pNode,
01814                  RCP<const map_type>& pMap,
01815                  const bool tolerant=false,
01816                  const bool debug=false)
01817       {
01818         using std::cerr;
01819         using std::endl;
01820 
01821         // Abbreviations for typedefs, to make the code more concise.
01822         typedef scalar_type S;
01823         typedef local_ordinal_type LO;
01824         typedef global_ordinal_type GO;
01825         typedef node_type Node;
01826         typedef Teuchos::ScalarTraits<S> STS;
01827         typedef typename STS::magnitudeType M;
01828         typedef Teuchos::ScalarTraits<M> STM;
01829 
01830         // Rank 0 is the only (MPI) process allowed to read from the
01831         // input stream.
01832         const int myRank = pComm->getRank ();
01833 
01834         if (debug && myRank == 0) {
01835           cerr << "Matrix Market reader: readDense:" << endl;
01836   }
01837 
01838         // If pMap is nonnull, check the precondition that its
01839         // communicator resp. node equal pComm resp. pNode.  Checking
01840         // now avoids doing a lot of file reading before we detect the
01841         // violated precondition.
01842         TEUCHOS_TEST_FOR_EXCEPTION(! pMap.is_null() && 
01843            (pMap->getComm() != pComm || 
01844             pMap->getNode() != pNode),
01845     std::invalid_argument, "If you supply a nonnull Map, the Map's "
01846           "communicator and node must equal the supplied communicator resp. "
01847           "node.");
01848 
01849         // Rank 0 will read in the matrix dimensions from the file,
01850         // and broadcast them to all ranks in the given communicator.
01851         // There are only 2 dimensions in the matrix, but we use the
01852         // third element of the Tuple to encode the banner's reported
01853         // data type: "real" == 0, "complex" == 1, and "integer" == 0
01854         // (same as "real").  We don't allow pattern matrices (i.e.,
01855         // graphs) since they only make sense for sparse data.
01856         Tuple<GO, 3> dims;
01857         dims[0] = 0;
01858         dims[1] = 0;
01859 
01860         // Current line number in the input stream.  Only valid on
01861         // Rank 0.  Various calls will modify this depending on the
01862         // number of lines that are read from the input stream.
01863         size_t lineNumber = 1;         
01864 
01865         // Only Rank 0 gets to read matrix data from the input stream.
01866         if (myRank == 0) {
01867     if (debug && myRank == 0) {
01868       cerr << "-- Reading banner line (dense)" << endl;
01869     }
01870 
01871     // The "Banner" tells you whether the input stream
01872     // represents a dense matrix, the symmetry type of the
01873     // matrix, and the type of the data it contains.
01874     RCP<const Banner> pBanner = 
01875       readBanner (in, lineNumber, pComm, tolerant, debug);
01876     TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "array",
01877             std::invalid_argument, "The Matrix Market file does not contain "
01878             "dense matrix data.  Its banner (first) line says that its matrix "
01879       "type is \"" << pBanner->matrixType() << "\", rather than the "
01880             "required \"array\".");
01881     TEUCHOS_TEST_FOR_EXCEPTION(pBanner->dataType() == "pattern",
01882       std::invalid_argument, "The Matrix Market file's banner (first) "
01883             "line claims that the matrix's data type is \"pattern\".  This does "
01884             "not make sense for a dense matrix, yet the file reports the matrix "
01885             "as dense.  The only valid data types for a dense matrix are "
01886             "\"real\", \"complex\", and \"integer\".");
01887     // Encode the data type reported by the Banner as the third
01888     // element of the dimensions Tuple.
01889     dims[2] = encodeDataType (pBanner->dataType());
01890 
01891           if (debug && myRank == 0) {
01892       cerr << "-- Reading dimensions line (dense)" << endl;
01893     }
01894           // Keep reading lines from the input stream until we find a
01895           // non-comment line, or until we run out of lines.  The
01896           // latter is an error, since every "array" format Matrix
01897           // Market file must have a dimensions line after the banner
01898           // (even if the matrix has zero rows or columns, or zero
01899           // entries).
01900           std::string line;
01901           bool commentLine = true;
01902           while (commentLine) {
01903             // Test whether it is even valid to read from the
01904             // input stream wrapping the line.
01905             TEUCHOS_TEST_FOR_EXCEPTION(in.eof() || in.fail(), std::runtime_error,
01906         "Unable to get array dimensions line (at all) from line " 
01907               << lineNumber << " of input stream.  The input stream claims that "
01908               "it is " << (in.eof() ? "at end-of-file." : "in a failed state."));
01909             // Try to get the next line from the input stream.
01910             if (getline(in, line)) {
01911               ++lineNumber; // We did actually read a line.
01912       }
01913             // Is the current line a comment line?  Ignore start and
01914             // size; they are only useful for reading the actual
01915             // matrix entries.  (We could use them here as an
01916             // optimization, but we've chosen not to.)
01917             size_t start = 0, size = 0;
01918             commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
01919           }
01920           //
01921           // Read in <numRows> <numCols> from input line.
01922           //
01923           std::istringstream istr (line);
01924     
01925           // Test whether it is even valid to read from the input
01926           // stream wrapping the line.
01927           TEUCHOS_TEST_FOR_EXCEPTION(istr.eof() || istr.fail(), std::runtime_error,
01928              "Unable to read any data from line " << lineNumber
01929              << " of input; the line should contain the matrix "
01930              << "dimensions \"<numRows> <numCols>\".");
01931           // Read in <numRows>.
01932           {
01933             GO theNumRows = 0;
01934             istr >> theNumRows;
01935             TEUCHOS_TEST_FOR_EXCEPTION(istr.fail(), std::runtime_error,
01936                "Failed to get number of rows from line " 
01937                << lineNumber << " of input; the line should "
01938                "contain the matrix dimensions \"<numRows> "
01939                "<numCols>\".");
01940             // Capture the validly read result before checking for eof.
01941             dims[0] = theNumRows;
01942           }
01943           // There should be one more thing to read.
01944           TEUCHOS_TEST_FOR_EXCEPTION(istr.eof(), std::runtime_error,
01945              "No more data after number of rows on line " 
01946              << lineNumber << " of input; the line should "
01947              "contain the matrix dimensions \"<numRows> "
01948              "<numCols>\".");
01949           // Read in <numCols>
01950           {
01951             GO theNumCols = 0;
01952             istr >> theNumCols;
01953             TEUCHOS_TEST_FOR_EXCEPTION(istr.fail(), std::runtime_error,
01954                "Failed to get number of columns from line " 
01955                << lineNumber << " of input; the line should "
01956                "contain the matrix dimensions \"<numRows> "
01957                "<numCols>\".");
01958             // Capture the validly read result.
01959             dims[1] = theNumCols;
01960           }
01961         } // if (myRank == 0)
01962 
01963         // Broadcast matrix dimensions and the encoded data type from
01964         // MPI Rank 0 to all the MPI processes.
01965         Teuchos::broadcast (*pComm, 0, dims);
01966 
01967         // Tpetra objects want the matrix dimensions in these types.
01968         const global_size_t numRows = static_cast<global_size_t> (dims[0]);
01969         const size_t numCols = static_cast<size_t> (dims[1]);
01970 
01971         // Make an "everything on Rank 0" map pRank0Map.  We'll use
01972         // this to construct a "distributed" vector X owned entirely
01973         // by Rank 0.  Rank 0 will then read all the matrix entries
01974         // and put them in X.
01975         RCP<const map_type> pRank0Map = 
01976           createContigMapWithNode<LO, GO, Node> (numRows, 
01977                                                  (myRank == 0 ? numRows : 0),
01978                                                  pComm, pNode);
01979 
01980         // Make a multivector X owned entirely by Rank 0.
01981         RCP<multivector_type> X = 
01982           createMultiVector<S, LO, GO, Node> (pRank0Map, numCols);
01983         
01984         //
01985         // On Rank 0, read the Matrix Market data from the input
01986         // stream into the multivector X.
01987         //
01988         if (myRank == 0) {
01989     if (debug && myRank == 0) {
01990       cerr << "-- Reading matrix data (dense)" << endl;
01991     }
01992 
01993     // Make sure that we can get a 1-D view of X.
01994     TEUCHOS_TEST_FOR_EXCEPTION(! X->isConstantStride (), std::logic_error,
01995              "Can't get a 1-D view of the entries of the "
01996              "MultiVector X on Rank 0, because the stride "
01997              "between the columns of X is not constant.  "
01998              "This shouldn't happen because we just created "
01999              "X and haven't filled it in yet.  Please report "
02000              "this bug to the Tpetra developers.");
02001     
02002     // Get a writeable 1-D view of the entries of X.  Rank 0
02003     // owns all of them.  The view will expire at the end of
02004     // scope, so (if necessary) it will be written back to X
02005     // at this time.
02006     ArrayRCP<S> X_view = X->get1dViewNonConst ();
02007     TEUCHOS_TEST_FOR_EXCEPTION(static_cast<global_size_t> (X_view.size()) < numRows * numCols,
02008              std::logic_error,
02009              "The view of X has size " << X_view 
02010              << " which is not enough to accommodate the "
02011              "expected number of entries numRows*numCols = " 
02012              << numRows << "*" << numCols << " = " 
02013              << numRows*numCols << ".  Please report this "
02014              "bug to the Tpetra developers.");
02015     const size_t stride = X->getStride ();
02016 
02017     // The third element of the dimensions Tuple encodes the data
02018     // type reported by the Banner: "real" == 0, "complex" == 1,
02019     // "integer" == 0 (same as "real"), "pattern" == 2.  We do not
02020     // allow dense matrices to be pattern matrices, so dims[2] ==
02021     // 0 or 1.  We've already checked for this above.
02022     const bool isComplex = (dims[2] == 1);
02023     typename ArrayRCP<S>::size_type count = 0, curRow = 0, curCol = 0;
02024 
02025     std::string line;
02026     while (getline(in, line)) {
02027       ++lineNumber;
02028       // Is the current line a comment line?  If it's not,
02029       // line.substr(start,size) contains the data.
02030       size_t start = 0, size = 0;
02031       const bool commentLine = 
02032         checkCommentLine (line, start, size, lineNumber, tolerant);
02033       if (! commentLine) {
02034         // Make sure we have room in which to put the new matrix
02035         // entry.  We check this only after checking for a
02036         // comment line, because there may be one or more
02037         // comment lines at the end of the file.  In tolerant
02038         // mode, we simply ignore any extra data.
02039         if (count >= X_view.size()) {
02040     if (tolerant) {
02041       break;
02042     }
02043     else {
02044       TEUCHOS_TEST_FOR_EXCEPTION(count >= X_view.size(), 
02045                                              std::runtime_error,
02046                                              "The Matrix Market input stream has "
02047                                              "more data in it than its metadata "
02048                                              "reported.  Current line number is "
02049                                              << lineNumber << ".");
02050     }
02051         }
02052         std::istringstream istr (line.substr (start, size));
02053         // Does the line contain anything at all?  Can we
02054         // safely read from the input stream wrapping the
02055         // line?
02056         if (istr.eof() || istr.fail()) {
02057     // In tolerant mode, simply ignore the line.
02058     if (tolerant) {
02059       break;
02060     }
02061     // We repeat the full test here so the exception
02062     // message is more informative.
02063     TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && (istr.eof() || istr.fail()),
02064                   std::runtime_error, "Line " << lineNumber << " of the Matrix "
02065                   "Market file is empty, or we cannot read from it for some "
02066       "other reason.");
02067         }
02068         // Current matrix entry to read in.
02069         S val = STS::zero();
02070         // Real and imaginary parts of the current matrix entry.
02071         // The imaginary part is zero if the matrix is
02072         // real-valued.
02073         M real = STM::zero(), imag = STM::zero();
02074 
02075         // isComplex refers to the input stream's data, not to
02076         // the scalar type S.  It's OK to read real-valued data
02077         // into a matrix storing complex-valued data; in that
02078         // case, all entries' imaginary parts are zero.
02079         if (isComplex) {
02080     // STS::real() and STS::imag() return a copy of their
02081     // respective components, not a writeable reference.
02082     // Otherwise we could just assign to them using the
02083     // istream extraction operator (>>).  That's why we
02084     // have separate magnitude type "real" and "imag"
02085     // variables.
02086                         
02087     // Attempt to read the real part of the current matrix
02088     // entry.
02089     istr >> real;
02090     if (istr.fail()) {
02091       TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && istr.fail(),
02092                std::runtime_error,
02093                "Failed to get real part of a "
02094                "complex-valued matrix entry "
02095                "from line " << lineNumber 
02096                << " of Matrix Market file.");
02097       // In tolerant mode, just skip bad lines.
02098       if (tolerant) {
02099         break;
02100       }
02101     }
02102     else if (istr.eof()) {
02103       TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && istr.eof(),
02104                std::runtime_error,
02105                "Missing imaginary part of a "
02106                "complex-valued matrix entry "
02107                "on line " << lineNumber 
02108                << " of Matrix Market file.");
02109       // In tolerant mode, let any missing imaginary part
02110       // be 0.
02111     }
02112     else {
02113       // Attempt to read the imaginary part of the current
02114       // matrix entry.
02115       istr >> imag;
02116       TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && istr.fail(),
02117                std::runtime_error,
02118                "Failed to get imaginary part "
02119                "of a complex-valued matrix "
02120                "entry from line " << lineNumber
02121                << " of Matrix Market file.");
02122       // In tolerant mode, let any missing
02123       // or corrupted imaginary part be 0.
02124     }
02125         }
02126         else { // Matrix Market file contains real-valued data.
02127     // Attempt to read the current matrix entry.
02128     istr >> real;
02129     TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && istr.fail(),
02130                                            std::runtime_error,
02131                                            "Failed to get a real-valued matrix "
02132                                            "entry from line " << lineNumber 
02133                                            << " of Matrix Market file.");
02134     // In tolerant mode, simply ignore the line if
02135     // we failed to read a matrix entry.
02136     if (istr.fail() && tolerant) {
02137       break;
02138     }
02139         }
02140 
02141         // In tolerant mode, we simply let pass through whatever
02142         // data we got.
02143         TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && istr.fail(), 
02144            std::runtime_error,
02145            "Failed to read matrix data from line " 
02146            << lineNumber << " of the Matrix Market "
02147            "file.");
02148         
02149         // val = S(real, imag), without potential badness
02150         // if S is a real type.
02151         details::assignScalar<S> (val, real, imag);
02152         
02153         curRow = count % numRows;
02154         curCol = count / numRows;
02155         X_view[curRow + curCol*stride] = val;
02156         ++count;
02157       } // if not a comment line
02158     } // while there are still lines in the file, get the next one
02159 
02160     TEUCHOS_TEST_FOR_EXCEPTION(! tolerant && 
02161              static_cast<global_size_t> (count) < numRows * numCols,
02162              std::runtime_error,
02163              "The Matrix Market metadata reports that the "
02164              "dense matrix is " << numRows <<  " x " 
02165              << numCols << ", and thus has " 
02166              << numRows*numCols << " total entries, but we "
02167              "only managed to find " << count << " entr" 
02168              << (count == 1 ? "y" : "ies") 
02169              << " in the file.");
02170   } // if (myRank == 0)
02171 
02172         // If there's only one MPI process and the user didn't supply
02173         // a Map (i.e., pMap is null), we're done.  Set pMap to the
02174         // Map used to distribute X, and return X.
02175         if (pComm->getSize() == 1 && pMap.is_null()) {
02176     pMap = pRank0Map;
02177     if (debug && myRank == 0) {
02178       cerr << "-- Done reading multivector" << endl;
02179     }
02180           return X;
02181   }
02182 
02183         if (debug && myRank == 0) {
02184           cerr << "-- Creating distributed Map and target MultiVector" << endl;
02185   }
02186 
02187         // If pMap is null, make a distributed map.  We've already
02188         // checked the preconditions above, in the case that pMap was
02189         // not null on input to this method.
02190         if (pMap.is_null()) {
02191           pMap = createUniformContigMapWithNode<LO, GO, Node> (numRows, pComm, pNode);
02192         }
02193         // Make a multivector Y with the distributed map pMap.
02194         RCP<multivector_type> Y = createMultiVector<S, LO, GO, Node> (pMap, numCols);
02195 
02196         // Make an Export object that will export X to Y.  First
02197         // argument is the source map, second argument is the target
02198         // map.
02199         Export<LO, GO, Node> exporter (pRank0Map, pMap);
02200 
02201         if (debug && myRank == 0) {
02202     cerr << "-- Exporting from X (owned by Rank 0) to globally owned Y" 
02203          << endl;
02204   }
02205         // Export X into Y.
02206         Y->doExport (*X, exporter, INSERT);
02207 
02208         if (debug && myRank == 0) {
02209     cerr << "-- Done reading multivector" << endl;
02210   }
02211 
02212         // Y is distributed over all process(es) in the communicator.
02213         return Y;
02214       }
02215 
02216     private:
02217       
02228       static int
02229       encodeDataType (const std::string& dataType)
02230       {
02231   if (dataType == "real" || dataType == "integer") {
02232     return 0;
02233   }
02234   else if (dataType == "complex") {
02235     return 1;
02236   }
02237   else if (dataType == "pattern") {
02238     return 2;
02239   }
02240   else {
02241     // We should never get here, since Banner validates the
02242     // reported data type and ensures it is one of the accepted
02243     // values.
02244     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, 
02245             "Unrecognized Matrix Market data type \"" << dataType << "\".");
02246   }
02247       }
02248     };
02249 
02289     template<class SparseMatrixType>
02290     class Writer {
02291     public:
02292       typedef SparseMatrixType sparse_matrix_type;
02293       typedef RCP<sparse_matrix_type> sparse_matrix_ptr;
02294 
02297       typedef typename SparseMatrixType::scalar_type scalar_type;
02300       typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
02307       typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
02310       typedef typename SparseMatrixType::node_type node_type;
02311 
02314       typedef MultiVector<scalar_type, 
02315         local_ordinal_type, 
02316         global_ordinal_type, 
02317         node_type> multivector_type;
02320       typedef Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
02321 
02353       static void
02354       writeSparseFile (const std::string& filename,
02355                        const RCP<const sparse_matrix_type>& pMatrix,
02356            const std::string& matrixName,
02357            const std::string& matrixDescription,
02358                        const bool debug=false)
02359       {
02360         const int myRank = Teuchos::rank (*(pMatrix->getComm()));
02361         std::ofstream out;        
02362 
02363         // Only open the file on Rank 0.
02364         if (myRank == 0) out.open (filename.c_str());
02365         writeSparse (out, pMatrix, matrixName, matrixDescription, debug);
02366         // We can rely on the destructor of the output stream to close
02367         // the file on scope exit, even if writeSparse() throws an
02368         // exception.
02369       }
02370 
02391       static void
02392       writeSparseFile (const std::string& filename,
02393                        const RCP<const sparse_matrix_type>& pMatrix,
02394                        const bool debug=false)
02395       {
02396   writeSparseFile (filename, pMatrix, "", "", debug);
02397       }
02398 
02399     public:
02400 
02431       static void
02432       writeSparse (std::ostream& out,
02433                    const RCP<const sparse_matrix_type>& pMatrix,
02434        const std::string& matrixName,
02435        const std::string& matrixDescription,
02436                    const bool debug=false)
02437       {
02438         using std::cerr;
02439         using std::endl;
02440         typedef typename Teuchos::ScalarTraits<scalar_type> STS;
02441         typedef typename STS::magnitudeType magnitude_type;
02442         typedef typename Teuchos::ScalarTraits<magnitude_type> STM;
02443         typedef typename ArrayView<scalar_type>::size_type size_type;
02444 
02445         // Convenient abbreviations.
02446         typedef local_ordinal_type LO;
02447         typedef global_ordinal_type GO;
02448         
02449         // Make the output stream write floating-point numbers in
02450         // scientific notation.  It will politely put the output
02451         // stream back to its state on input, when this scope
02452         // terminates.
02453         details::SetScientific<scalar_type> sci (out);
02454 
02455         RCP<const Comm<int> > pComm = pMatrix->getComm();
02456         const int myRank = Teuchos::rank (*pComm);
02457         // Whether to print debugging output to stderr.
02458         const bool debugPrint = debug && myRank == 0;
02459 
02460         const global_size_t numRows = 
02461     pMatrix->getRangeMap()->getGlobalNumElements();
02462         const global_size_t numCols = 
02463     pMatrix->getDomainMap()->getGlobalNumElements();
02464         if (debugPrint) {
02465           cerr << "writeSparse:" << endl
02466                << "-- Input sparse matrix is:" 
02467                << "---- " << numRows << " x " << numCols << " with "
02468                << pMatrix->getGlobalNumEntries() << " entries;" << endl
02469                << "---- " 
02470                << (pMatrix->isGloballyIndexed() ? "Globally" : "Locally")
02471                << " indexed." << endl;
02472         }
02473         RCP<const map_type> pRowMap = pMatrix->getRowMap();
02474         if (debugPrint) {
02475           RCP<const map_type> pColMap = pMatrix->getColMap();
02476           cerr << "---- Its row map has " << pRowMap->getGlobalNumElements() 
02477                << " elements." << endl
02478                << "---- Its col map has " << pColMap->getGlobalNumElements() 
02479                << " elements." << endl;
02480         }
02481         // Make the "gather" row map, where Proc 0 owns all rows and
02482         // the other procs own no rows.
02483         const size_t localNumRows = (myRank == 0) ? numRows : 0;
02484         RCP<node_type> pNode = pRowMap->getNode();
02485         RCP<const map_type> pGatherRowMap = 
02486           createContigMapWithNode<LO, GO, node_type> (numRows, localNumRows,
02487                                                       pComm, pNode);
02488         // Since the matrix may in general be non-square, we need to
02489         // make a column map as well.  In this case, the column map
02490         // contains all the columns of the original matrix, because we
02491         // are gathering the whole matrix onto Proc 0.
02492         const size_t localNumCols = (myRank == 0) ? numCols : 0;
02493         RCP<const map_type> pGatherColMap = 
02494           createContigMapWithNode<LO, GO, node_type> (numCols, localNumCols,
02495                                                       pComm, pNode);
02496 
02497         // Current map is the source map, gather map is the target map.
02498         typedef Import<LO, GO, node_type> import_type;
02499         import_type importer (pRowMap, pGatherRowMap);
02500 
02501         // Create a new CrsMatrix to hold the result of the import.
02502         // The constructor needs a column map as well as a row map,
02503         // for the case that the matrix is not square.
02504         RCP<sparse_matrix_type> newMatrix = 
02505           rcp (new sparse_matrix_type (pGatherRowMap, 
02506                pGatherColMap, 
02507                size_t(0)));
02508         // Import the sparse matrix onto Proc 0.
02509         newMatrix->doImport (*pMatrix, importer, INSERT);
02510 
02511         // fillComplete() needs the domain and range maps for the case
02512         // that the matrix is not square.
02513         {
02514           RCP<const map_type> pGatherDomainMap = 
02515             createContigMapWithNode<LO, GO, node_type> (numCols, localNumCols,
02516                                                         pComm, pNode);
02517           RCP<const map_type> pGatherRangeMap = 
02518             createContigMapWithNode<LO, GO, node_type> (numRows, localNumRows,
02519                                                         pComm, pNode);
02520           newMatrix->fillComplete (pGatherDomainMap, pGatherRangeMap);
02521         }
02522 
02523         if (debugPrint) {
02524           cerr << "-- Output sparse matrix is:" 
02525                << "---- " << newMatrix->getRangeMap()->getGlobalNumElements() 
02526                << " x " 
02527                << newMatrix->getDomainMap()->getGlobalNumElements() 
02528                << " with " 
02529                << newMatrix->getGlobalNumEntries() << " entries;" << endl
02530                << "---- " 
02531                << (newMatrix->isGloballyIndexed() ? "Globally" : "Locally")
02532                << " indexed." << endl
02533                << "---- Its row map has " 
02534                << newMatrix->getRowMap()->getGlobalNumElements() 
02535                << " elements." << endl
02536                << "---- Its col map has " 
02537                << newMatrix->getColMap()->getGlobalNumElements() 
02538                << " elements (may be different than the input matrix's column"
02539                << " map, if some columns of the matrix contain no entries)." 
02540                << endl;
02541         }
02542 
02543         //
02544         // Print the metadata and the matrix entries on Rank 0.
02545         //
02546         if (myRank == 0) {
02547           // Print the Matrix Market banner line.  CrsMatrix stores
02548           // data nonsymmetrically ("general").  This implies that
02549           // readSparse() on a symmetrically stored input file,
02550           // followed by writeSparse() on the resulting sparse matrix,
02551           // will result in an output file with a different banner
02552           // line than the original input file.
02553           out << "%%MatrixMarket matrix coordinate " 
02554               << (STS::isComplex ? "complex" : "real") 
02555               << " general" << endl;
02556 
02557     // Print comments (the matrix name and / or description).
02558     if (matrixName != "")
02559       printAsComment (out, matrixName);
02560     if (matrixDescription != "")
02561       printAsComment (out, matrixDescription);
02562       
02563           // Print the Matrix Market header (# rows, # columns, #
02564           // nonzeros).  Use the range resp. domain map for the
02565           // number of rows resp. columns, since Tpetra::CrsMatrix
02566           // uses the column map for the number of columns.  That
02567           // only corresponds to the "linear-algebraic" number of
02568           // columns when the column map is 1-1, which only happens
02569           // if the matrix is (block) diagonal.
02570           out << newMatrix->getRangeMap()->getGlobalNumElements() 
02571               << " "
02572               << newMatrix->getDomainMap()->getGlobalNumElements() 
02573               << " "
02574               << newMatrix->getGlobalNumEntries() 
02575               << endl;
02576 
02577           // Index base (0-based or 1-based) for the row map.
02578           const GO rowIndexBase = pGatherRowMap->getIndexBase();
02579           // Index base (0-based or 1-based) for the column map.
02580           const GO colIndexBase = newMatrix->getColMap()->getIndexBase();
02581 
02582           //
02583           // Print the entries of the matrix.
02584           //
02585           // newMatrix can never be globally indexed, since we
02586           // called fillComplete() on it.  We include code for both
02587           // cases (globally or locally indexed) just in case that
02588           // ever changes.
02589           if (newMatrix->isGloballyIndexed()) {
02590             for (GO globalRowIndex = pGatherRowMap->getMinAllGlobalIndex();
02591                  globalRowIndex <= pGatherRowMap->getMaxAllGlobalIndex();
02592                  ++globalRowIndex)
02593         {
02594     ArrayView<const GO> ind;
02595     ArrayView<const scalar_type> val;
02596 
02597     newMatrix->getGlobalRowView (globalRowIndex, ind, val);
02598     typename ArrayView<const GO>::const_iterator indIter = 
02599       ind.begin();
02600     typename ArrayView<const scalar_type>::const_iterator valIter = 
02601       val.begin();
02602     for (; indIter != ind.end() && valIter != val.end();
02603          ++indIter, ++valIter)
02604       {
02605         const GO globalColIndex = *indIter;
02606 
02607         // Matrix Market files use 1-based indices.
02608         out << (globalRowIndex + 1 - rowIndexBase) << " " 
02609       << (globalColIndex + 1 - colIndexBase) << " ";
02610         if (STS::isComplex) 
02611           out << STS::real(*valIter) << " " << STS::imag(*valIter);
02612         else
02613           out << *valIter;
02614         out << endl;
02615       }
02616         }
02617           }
02618           else // newMatrix is locally indexed
02619       {
02620         typedef OrdinalTraits<GO> OTG;
02621         RCP<const map_type> pColMap = newMatrix->getColMap ();
02622 
02623         for (LO localRowIndex = pGatherRowMap->getMinLocalIndex();
02624        localRowIndex <= pGatherRowMap->getMaxLocalIndex();
02625        ++localRowIndex)
02626     {
02627       // Convert from local to global row index.
02628       const GO globalRowIndex = 
02629         pGatherRowMap->getGlobalElement (localRowIndex);
02630       TEUCHOS_TEST_FOR_EXCEPTION(globalRowIndex == OTG::invalid(), 
02631              std::logic_error,
02632              "Failed to convert \"local\" row index " 
02633              << localRowIndex << " into a global row "
02634              "index.  Please report this bug to the "
02635              "Tpetra developers.");
02636       ArrayView<const LO> ind;
02637       ArrayView<const scalar_type> val;
02638 
02639       newMatrix->getLocalRowView (localRowIndex, ind, val);
02640       typename ArrayView<const LO>::const_iterator indIter = 
02641         ind.begin();
02642       typename ArrayView<const scalar_type>::const_iterator
02643         valIter = val.begin();
02644       for (; indIter != ind.end() && valIter != val.end(); 
02645            ++indIter, ++valIter)
02646         {
02647           // Convert from local to global index.
02648           const GO globalColIndex = 
02649       pColMap->getGlobalElement (*indIter);
02650           TEUCHOS_TEST_FOR_EXCEPTION(globalColIndex == OTG::invalid(), 
02651            std::logic_error,
02652            "Failed to convert \"local\" column " 
02653            "index " << *indIter << " into a "
02654            "global column index.  Please report "
02655            "this bug to the Tpetra developers.");
02656           // Matrix Market files use 1-based indices.
02657           out << (globalRowIndex + 1 - rowIndexBase) << " " 
02658         << (globalColIndex + 1 - colIndexBase) << " ";
02659           if (STS::isComplex) 
02660       out << STS::real(*valIter) << " " 
02661           << STS::imag(*valIter);
02662           else
02663       out << *valIter;
02664           out << endl;
02665         }
02666     }
02667       }
02668         }
02669       }
02670 
02693       static void
02694       writeSparse (std::ostream& out,
02695                    const RCP<const sparse_matrix_type>& pMatrix,
02696                    const bool debug=false)
02697       {
02698   writeSparse (out, pMatrix, "", "", debug);
02699       }
02700 
02727       static void
02728       writeDenseFile (const std::string& filename,
02729                       const RCP<const multivector_type>& X,
02730           const std::string& matrixName,
02731           const std::string& matrixDescription)
02732       {
02733         const int myRank = Teuchos::rank (*(X->getMap()->getComm()));
02734         std::ofstream out;        
02735 
02736         if (myRank == 0) // Only open the file on Rank 0.
02737     out.open (filename.c_str());
02738 
02739         writeDense (out, X, matrixName, matrixDescription);
02740         // We can rely on the destructor of the output stream to close
02741         // the file on scope exit, even if writeDense() throws an
02742         // exception.
02743       }
02744 
02763       static void
02764       writeDenseFile (const std::string& filename,
02765                       const RCP<const multivector_type>& X)
02766       {
02767   writeDenseFile (filename, X, "", "");
02768       }
02769 
02796       static void
02797       writeDense (std::ostream& out,
02798                   const RCP<const multivector_type>& X,
02799       const std::string& matrixName,
02800       const std::string& matrixDescription)
02801       {
02802   using Teuchos::rcp;
02803   using Teuchos::rcp_const_cast;
02804         using std::endl;
02805 
02806         typedef typename Teuchos::ScalarTraits<scalar_type> STS;
02807         typedef typename STS::magnitudeType magnitude_type;
02808         typedef typename Teuchos::ScalarTraits<magnitude_type> STM;
02809         typedef typename ArrayView<scalar_type>::size_type size_type;
02810 
02811         // Convenient abbreviations.
02812         typedef local_ordinal_type LO;
02813         typedef global_ordinal_type GO;
02814   typedef node_type NT;
02815 
02816   // If true, when making the "gather" Map, use the same index
02817   // base as X's Map.  Otherwise, just use the default index
02818   // base for the gather Map.
02819   const bool keepTheSameIndexBase = false;
02820 
02821         // Make the output stream write floating-point numbers in
02822         // scientific notation.  It will politely put the output
02823         // stream back to its state on input, when this scope
02824         // terminates.
02825         details::SetScientific<scalar_type> sci (out);
02826 
02827         RCP<const Comm<int> > comm = X->getMap()->getComm();
02828         const int myRank = comm->getRank ();
02829         RCP<const map_type> map = X->getMap();
02830         const global_size_t numRows = map->getGlobalNumElements();
02831   // Promote to global_size_t.
02832         const global_size_t numCols = X->getNumVectors(); 
02833 
02834         // Make the "gather" map, where Proc 0 owns all rows of X, and
02835         // the other procs own no rows.
02836         const size_t localNumRows = (myRank == 0) ? numRows : 0;
02837         RCP<NT> node = map->getNode();
02838         RCP<const map_type> gatherMap = keepTheSameIndexBase ? 
02839     rcp_const_cast<const map_type> (rcp (new map_type (numRows, localNumRows, map->getIndexBase(), comm, node))) :
02840     createContigMapWithNode<LO, GO, NT> (numRows, localNumRows, comm, node);
02841 
02842         // Create an Import object to import X's data into a
02843         // multivector Y owned entirely by Proc 0.  In the Import
02844         // constructor, X's map is the source map, and the "gather
02845         // map" is the target map.
02846         Import<LO, GO, NT> importer (map, gatherMap);
02847 
02848         // Create a new multivector Y to hold the result of the import.
02849         RCP<multivector_type> Y = 
02850     createMultiVector<scalar_type, LO, GO, NT> (gatherMap, numCols);
02851 
02852         // Import the multivector onto Proc 0.
02853         Y->doImport (*X, importer, INSERT);
02854 
02855         //
02856         // Print the matrix in Matrix Market format on Rank 0.
02857         //
02858         if (myRank == 0) {
02859     // Print the Matrix Market banner line.  MultiVector
02860     // stores data nonsymmetrically, hence "general".
02861     out << "%%MatrixMarket matrix array " 
02862         << (STS::isComplex ? "complex" : "real") 
02863         << " general" << endl;
02864 
02865     // Print comments (the matrix name and / or description).
02866     if (matrixName != "") {
02867       printAsComment (out, matrixName);
02868     }
02869     if (matrixDescription != "") {
02870       printAsComment (out, matrixDescription);
02871     }
02872     // Print the Matrix Market dimensions header for dense matrices.
02873     out << numRows << " " << numCols << endl;
02874     //
02875     // Get a read-only view of the entries of Y.  
02876     // Rank 0 owns all of the entries of Y.
02877     //
02878     // Y must have constant stride, since multivectors have
02879     // constant stride if created with a map and number of
02880     // vectors.  This should be the case even if X does not
02881     // have constant stride.  However, we check Y, just to
02882     // make sure.
02883     TEUCHOS_TEST_FOR_EXCEPTION(! Y->isConstantStride (), std::logic_error,
02884             "The multivector Y imported onto Rank 0 does not have constant "
02885             "stride.  Please report this bug to the Tpetra developers.");
02886     ArrayRCP<const scalar_type> Y_view = Y->get1dView();
02887     //
02888     // Print the entries of the matrix, in column-major order.
02889     //
02890     const global_size_t stride = Y->getStride ();
02891     for (global_size_t j = 0; j < numCols; ++j) {
02892       for (global_size_t i = 0; i < numRows; ++i) {
02893         const scalar_type Y_ij = Y_view[i + j*stride];
02894         if (STS::isComplex) {
02895     out << STS::real(Y_ij) << " " << STS::imag(Y_ij) << endl;
02896         }
02897         else {
02898     out << Y_ij << endl;
02899         }
02900       }
02901     }
02902   } // if (myRank == 0)
02903       }
02904 
02923       static void
02924       writeDense (std::ostream& out,
02925                   const RCP<const multivector_type>& X)
02926       {
02927   writeDense (out, X, "", "");
02928       }
02929 
02930     private:
02954       static void 
02955       printAsComment (std::ostream& out, const std::string& str)
02956       {
02957   using std::endl;
02958   std::istringstream istream (str);
02959   std::string line;
02960 
02961   while (getline (istream, line)) {
02962     if (! line.empty()) {
02963       // Note that getline() doesn't store '\n', so we have to
02964       // append the endline ourselves.
02965       if (line[0] == '%') { // Line starts with a comment character.
02966         out << line << endl; 
02967       }
02968       else { // Line doesn't start with a comment character.
02969         out << "%% " << line << endl;
02970       }
02971     }
02972   }
02973       }
02974     }; // class Writer
02975     
02976   } // namespace MatrixMarket
02977 } // namespace Tpetra
02978 
02979 #endif // __MatrixMarket_Tpetra_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines