Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
readMatrixFromBinaryFile.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef __READMATRIXFROMBINARYFILE_HPP
11 #define __READMATRIXFROMBINARYFILE_HPP
12 
14 // These utilities read a sparse matrix from a binary file that was
15 // created with the corresponding "largestComponent2Binary.cpp" code.
16 // Specific structure may be assumed.
17 // Note: This is research code. We do not guarantee it works in all cases.
19 #include <climits>
20 #include "Tpetra_Details_makeColMap.hpp"
21 
22 template <typename global_ordinal_type, typename local_ordinal_type, typename scalar_type, typename map_type>
23 void
24 distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
25  Teuchos::ArrayRCP<size_t>& myRowPtr,
26  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
27  Teuchos::ArrayRCP<scalar_type>& myValues,
28  const Teuchos::RCP<const map_type>& pRowMap,
29  global_ordinal_type *rowPtr,
30  global_ordinal_type *colInd,
31  const bool debug=false)
32 {
33 
34  int maxNumEnt = INT_MAX/sizeof(global_ordinal_type);
35 
36  Teuchos::RCP<const Teuchos::Comm<int>> pComm = pRowMap->getComm ();
37  const int numProcs = pComm->getSize ();
38  const int myRank = pComm->getRank ();
39  const int rootRank = 0;
40 
41  Teuchos::ArrayView<const global_ordinal_type> myRows = pRowMap->getLocalElementList();
42  const size_t myNumRows = myRows.size();
43 
44  myNumEntriesPerRow = Teuchos::ArrayRCP<size_t> (myNumRows);
45 
46  if (myRank != rootRank) {
47 
48  Teuchos::send (*pComm, myNumRows, rootRank);
49 
50  if (myNumRows != 0) {
51 
52  Teuchos::send (*pComm, static_cast<int> (myNumRows), myRows.getRawPtr(), rootRank);
53  Teuchos::receive (*pComm, rootRank, static_cast<int> (myNumRows), myNumEntriesPerRow.getRawPtr());
54 
55  const global_ordinal_type myNumEntries =
56  std::accumulate (myNumEntriesPerRow.begin(),
57  myNumEntriesPerRow.end(), 0);
58 
59  myColInd = Teuchos::ArrayRCP<global_ordinal_type> (myNumEntries);
60  myValues = Teuchos::ArrayRCP<scalar_type> (myNumEntries, 1.0);
61  if (myNumEntries > 0) {
62 
63  if(myNumEntries < maxNumEnt)
64  Teuchos::receive (*pComm, rootRank, static_cast<int> (myNumEntries), &myColInd[0]);
65  else {
66  int nchunks = myNumEntries/maxNumEnt;
67  if(myNumEntries % maxNumEnt != 0)
68  nchunks ++;
69  for(int i = 0; i < nchunks-1; i++) {
70  Teuchos::receive (*pComm, rootRank, maxNumEnt, &myColInd[maxNumEnt*i]);
71  std::cout << "Chunk " << i << " received by myRank "<< myRank << ", size: " << maxNumEnt << "\n";
72  }
73  int lastsize = (int)(myNumEntries - (nchunks-1)*maxNumEnt);
74  Teuchos::receive (*pComm, rootRank, lastsize, &myColInd[maxNumEnt*(nchunks-1)]);
75  std::cout << "Chunk " << nchunks-1 << " received by myRank " << myRank << ", size: " << lastsize << "\n";
76  }
77 
78  }
79 
80  } // If I own at least one row
81 
82  } // If I am not the root processor
83  else { // I _am_ the root processor
84  if (debug) {
85  std::cout << "-- Proc 0: Copying my data from global arrays" << std::endl;
86  }
87 
88  for (size_t k = 0; k < myNumRows; ++k) {
89  const global_ordinal_type myCurRow = myRows[k];
90  const global_ordinal_type numEntriesInThisRow = rowPtr[myCurRow+1] - rowPtr[myCurRow];
91  myNumEntriesPerRow[k] = numEntriesInThisRow;
92 
93  }
94 
95  size_t myNumEntries = std::accumulate (myNumEntriesPerRow.begin(),
96  myNumEntriesPerRow.end(), 0);
97  if (debug) {
98  std::cout << "-- Proc 0: I own " << myNumRows << " rows and "
99  << myNumEntries << " entries" << std::endl;
100  }
101  myColInd = Teuchos::ArrayRCP<global_ordinal_type> (myNumEntries);
102  myValues = Teuchos::ArrayRCP<scalar_type> (myNumEntries, 1.0);
103 
104  global_ordinal_type myCurPos = 0;
105  for (size_t k = 0; k < myNumRows; ++k) {
106  const global_ordinal_type curNumEntries = myNumEntriesPerRow[k];
107  const global_ordinal_type myRow = myRows[k];
108  global_ordinal_type curPos = rowPtr[myRow];
109 
110  if (curNumEntries > 0) {
111  for(global_ordinal_type ii = 0; ii < curNumEntries; ++ii) {
112  myColInd[myCurPos++] = colInd[curPos++];
113  }
114  }
115  }
116 
117  for (int p = 1; p < numProcs; ++p) {
118  if (debug) {
119  std::cout << "-- Proc 0: Processing proc " << p << std::endl;
120  }
121 
122  size_t theirNumRows = 0;
123  Teuchos::receive (*pComm, p, &theirNumRows);
124  if (debug) {
125  std::cout << "-- Proc 0: Proc " << p << " owns "
126  << theirNumRows << " rows" << std::endl;
127  }
128 
129  if (theirNumRows != 0) {
130  Teuchos::ArrayRCP<global_ordinal_type> theirRows(theirNumRows);
131  Teuchos::receive (*pComm, p, Teuchos::as<int> (theirNumRows), theirRows.getRawPtr ());
132 
133  Teuchos::ArrayRCP<size_t> theirNumEntriesPerRow = Teuchos::ArrayRCP<size_t> (theirNumRows);
134  for (size_t k = 0; k < theirNumRows; ++k) {
135  theirNumEntriesPerRow[k] = rowPtr[theirRows[k]+1] - rowPtr[theirRows[k]];
136  }
137 
138  Teuchos::send (*pComm, static_cast<int> (theirNumRows), theirNumEntriesPerRow.getRawPtr(), p);
139 
140  const global_ordinal_type theirNumEntries =
141  std::accumulate (theirNumEntriesPerRow.begin(),
142  theirNumEntriesPerRow.end(), 0);
143 
144  if (debug) {
145  std::cout << "-- Proc 0: Proc " << p << " owns "
146  << theirNumEntries << " entries" << std::endl;
147  }
148 
149  if (theirNumEntries == 0) {
150  continue;
151  }
152 
153  Teuchos::ArrayRCP<global_ordinal_type> theirColInd (theirNumEntries);
154 
155  global_ordinal_type theirCurPos = 0;
156  for (size_t k = 0; k < theirNumRows; k++) {
157  const global_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
158  const global_ordinal_type theirRow = theirRows[k];
159  global_ordinal_type curPos = rowPtr[theirRow];
160 
161  if (curNumEntries > 0) {
162 
163  for(global_ordinal_type ii = 0; ii < curNumEntries; ++ii) {
164  theirColInd[theirCurPos++] = colInd[curPos++];
165  }
166 
167  }
168  }
169 
170  if(theirNumEntries < maxNumEnt)
171  Teuchos::send (*pComm, static_cast<int> (theirNumEntries), &theirColInd[0], p);
172  else {
173  int nchunks = theirNumEntries/maxNumEnt;
174  if(theirNumEntries % maxNumEnt != 0)
175  nchunks ++;
176  for(int i = 0; i < nchunks-1; i++) {
177  Teuchos::send (*pComm, maxNumEnt, &theirColInd[maxNumEnt*i], p);
178  std::cout << "Chunk " << i << " sent to Rank "<< p << ", size: " << maxNumEnt << "\n";
179  }
180  int lastsize = (int)(theirNumEntries - (nchunks-1)*maxNumEnt);
181  Teuchos::send (*pComm, lastsize, &theirColInd[maxNumEnt*(nchunks-1)], p);
182  std::cout << "Chunk " << nchunks-1 << " sent to Rank "<< p << ", size: " << lastsize << "\n";
183  }
184 
185  if (debug) {
186  std::cout << "-- Proc 0: Finished with proc " << p << std::endl;
187  }
188 
189  } // If proc p owns at least one row
190  } // For each proc p not the root proc 0
191  } // If I'm (not) the root proc 0
192 
193  if (debug && myRank == 0) {
194  std::cout << "-- Proc 0: About to fill in myRowPtr" << std::endl;
195  }
196 
197  myRowPtr = Teuchos::ArrayRCP<size_t> (myNumRows+1);
198  myRowPtr[0] = 0;
199  for (size_t k = 1; k < myNumRows+1; ++k) {
200  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
201  }
202  if (debug && myRank == 0) {
203  std::cout << "-- Proc 0: Done with distribute" << std::endl;
204  }
205 }
206 
207 template <typename crs_matrix_type>
208 Teuchos::RCP<crs_matrix_type>
209 readBinaryFile(std::string filename, const Teuchos::RCP<const Teuchos::Comm<int>> pComm, bool callFillComplete=true, bool debug=false)
210 {
211  typedef typename crs_matrix_type::global_ordinal_type global_ordinal_type;
212  typedef typename crs_matrix_type::local_ordinal_type local_ordinal_type;
213  typedef typename crs_matrix_type::scalar_type scalar_type;
214  typedef typename crs_matrix_type::node_type node_type;
215 
216  typedef typename Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
217 
218  const int myRank = pComm->getRank();
219  const int rootRank = 0;
220 
221  if (debug && myRank == rootRank) {
222  std::cout << "Binary CRS reader: readSparse:" << std::endl
223  << "-- Reading started" << std::endl;
224  }
225 
226  Teuchos::RCP<std::ifstream> in;
227  global_ordinal_type globalNumRows;
228  global_ordinal_type globalNumNonzeros;
229 
230  if (myRank == rootRank) {
231 
232  // Open the file
233  in = Teuchos::RCP<std::ifstream>(new std::ifstream(filename, std::ios::in | std::ios::binary));
234 
235  // Read number of vertices and number of edges
236  in->read((char *)&globalNumRows, sizeof(global_ordinal_type));
237  in->read((char *)&globalNumNonzeros, sizeof(global_ordinal_type));
238 
239  TEUCHOS_TEST_FOR_EXCEPTION(globalNumRows <= 0 || globalNumNonzeros <= 0, std::invalid_argument,
240  "Global number of rows or nonzeros have nonpositive value." << globalNumRows << " " << globalNumNonzeros << " " << sizeof(global_ordinal_type) );
241  }
242 
243  broadcast (*pComm, rootRank, 1, &globalNumRows);
244  broadcast (*pComm, rootRank, 1, &globalNumNonzeros);
245 
246  global_ordinal_type *rowPtr = 0;
247  global_ordinal_type *colInd = 0;
248 
249  if (myRank == rootRank) {
250 
251  rowPtr = new global_ordinal_type[globalNumRows+1];
252  colInd = new global_ordinal_type[globalNumNonzeros];
253 
254  in->read((char*)rowPtr, sizeof(global_ordinal_type)*(globalNumRows+1));
255  in->read((char*)colInd, sizeof(global_ordinal_type)*(globalNumNonzeros));
256  }
257 
258  Teuchos::RCP<const map_type> pRowMap = Teuchos::rcp (new map_type (static_cast<Tpetra::global_size_t> (globalNumRows),
259  static_cast<global_ordinal_type> (0),
260  pComm, Tpetra::GloballyDistributed));
261 
262  Teuchos::RCP<const map_type> pRangeMap = Teuchos::rcp (new map_type (static_cast<Tpetra::global_size_t> (globalNumRows),
263  static_cast<global_ordinal_type> (0),
264  pComm, Tpetra::GloballyDistributed));
265 
266  Teuchos::RCP<const map_type> pDomainMap = pRangeMap;
267 
268  Teuchos::ArrayView<const global_ordinal_type> myRows = pRowMap->getLocalElementList ();
269  const size_t myNumRows = myRows.size ();
270 
271  Teuchos::ArrayRCP<size_t> myNumEntriesPerRow(myNumRows);
272  Teuchos::ArrayRCP<size_t> myRowPtr;
273  Teuchos::ArrayRCP<global_ordinal_type> myColInd;
274  Teuchos::ArrayRCP<scalar_type> myValues;
275 
276  distribute<global_ordinal_type, local_ordinal_type, scalar_type, map_type>(myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap, rowPtr, colInd, debug);
277  pComm->barrier();
278 
279  if (debug && myRank == rootRank) {
280  std::cout << "-- Inserting matrix entries on each processor";
281  if (callFillComplete) {
282  std::cout << " and calling fillComplete()";
283  }
284  std::cout << std::endl;
285  }
286 
287  Teuchos::RCP<crs_matrix_type> pMatrix = Teuchos::rcp (new crs_matrix_type (pRowMap, myNumEntriesPerRow()));
288 
289  const global_ordinal_type indexBase = pRowMap->getIndexBase ();
290  for (size_t i = 0; i < myNumRows; ++i) {
291  const size_t myCurPos = myRowPtr[i];
292  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
293  Teuchos::ArrayView<global_ordinal_type> curColInd = myColInd.view (myCurPos, curNumEntries);
294  Teuchos::ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
295 
296  for (size_t k = 0; k < curNumEntries; ++k) {
297  curColInd[k] += indexBase;
298  }
299 
300  if (curNumEntries > 0) {
301  pMatrix->insertGlobalValues (myRows[i], curColInd, curValues);
302  }
303  }
304  pComm->barrier();
305  if (debug && myRank == rootRank) {
306  std::cout << "-- Done with inserting." << std::endl;
307  }
308 
309  myNumEntriesPerRow = Teuchos::null;
310  myRowPtr = Teuchos::null;
311  myColInd = Teuchos::null;
312  myValues = Teuchos::null;
313 
314  if (callFillComplete) {
315  pMatrix->fillComplete (pDomainMap, pRangeMap);
316  }
317  pComm->barrier();
318  if (debug && myRank == rootRank) {
319  std::cout << "-- Done with fill complete." << std::endl;
320  }
321 
322 
323  if(myRank == rootRank) {
324  delete [] rowPtr;
325  delete [] colInd;
326  }
327 
328  return pMatrix;
329 }
330 
331 template <typename crs_matrix_type>
332 Teuchos::RCP<crs_matrix_type>
333 readBinaryFileFast(std::string filename, const Teuchos::RCP<const Teuchos::Comm<int>> pComm, bool callFillComplete=true, bool debug=false)
334 {
335  typedef typename crs_matrix_type::global_ordinal_type global_ordinal_type;
336  typedef typename crs_matrix_type::local_ordinal_type local_ordinal_type;
337  typedef typename crs_matrix_type::scalar_type scalar_type;
338  typedef typename crs_matrix_type::node_type node_type;
339  typedef typename crs_matrix_type::crs_graph_type crs_graph_type;
340 
341  typedef typename Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
342 
343  const int myRank = pComm->getRank();
344  const int rootRank = 0;
345 
346  if (debug && myRank == rootRank) {
347  std::cout << "Binary CRS reader: readSparse:" << std::endl
348  << "-- Reading started" << std::endl;
349  }
350 
351  Teuchos::RCP<std::ifstream> in;
352  global_ordinal_type globalNumRows;
353  global_ordinal_type globalNumNonzeros;
354 
355  if (myRank == rootRank) {
356 
357  // Open the file
358  in = Teuchos::RCP<std::ifstream>(new std::ifstream(filename, std::ios::in | std::ios::binary));
359 
360  // Read number of vertices and number of edges
361  in->read((char *)&globalNumRows, sizeof(global_ordinal_type));
362  in->read((char *)&globalNumNonzeros, sizeof(global_ordinal_type));
363 
364  TEUCHOS_TEST_FOR_EXCEPTION(globalNumRows <= 0 || globalNumNonzeros <= 0, std::invalid_argument,
365  "Global number of rows or nonzeros have nonpositive value." << globalNumRows << " " << globalNumNonzeros << " " << sizeof(global_ordinal_type) );
366  }
367 
368  broadcast (*pComm, rootRank, 1, &globalNumRows);
369  broadcast (*pComm, rootRank, 1, &globalNumNonzeros);
370 
371  global_ordinal_type *rowPtr = 0;
372  global_ordinal_type *colInd = 0;
373 
374  if (myRank == rootRank) {
375 
376  rowPtr = new global_ordinal_type[globalNumRows+1];
377  colInd = new global_ordinal_type[globalNumNonzeros];
378 
379  in->read((char*)rowPtr, sizeof(global_ordinal_type)*(globalNumRows+1));
380  in->read((char*)colInd, sizeof(global_ordinal_type)*(globalNumNonzeros));
381 
382  }
383 
384 
385  Teuchos::RCP<const map_type> pRowMap = Teuchos::rcp (new map_type (static_cast<Tpetra::global_size_t> (globalNumRows),
386  static_cast<global_ordinal_type> (0),
387  pComm, Tpetra::GloballyDistributed));
388 
389  Teuchos::RCP<const map_type> pRangeMap = Teuchos::rcp (new map_type (static_cast<Tpetra::global_size_t> (globalNumRows),
390  static_cast<global_ordinal_type> (0),
391  pComm, Tpetra::GloballyDistributed));
392 
393  Teuchos::RCP<const map_type> pDomainMap = pRangeMap;
394 
395  Teuchos::ArrayView<const global_ordinal_type> myRows = pRowMap->getLocalElementList ();
396  const size_t myNumRows = myRows.size ();
397 
398  Teuchos::ArrayRCP<size_t> myNumEntriesPerRow(myNumRows);
399  Teuchos::ArrayRCP<size_t> myRowPtr;
400  Teuchos::ArrayRCP<global_ordinal_type> myColInd;
401  Teuchos::ArrayRCP<scalar_type> myValues;
402 
403 
404  distribute<global_ordinal_type, local_ordinal_type, scalar_type, map_type>(myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap, rowPtr, colInd, debug);
405  pComm->barrier();
406 
407  if (debug && myRank == rootRank) {
408  std::cout << "-- Inserting matrix entries on each processor";
409  if (callFillComplete) {
410  std::cout << " and calling fillComplete()";
411  }
412  std::cout << std::endl;
413  }
414 
415  // get the colIds
416  std::vector<bool> mark(globalNumRows, false);
417  size_t myNumEntries = myRowPtr[myNumRows];
418  for(size_t i = 0; i < myNumEntries; i++)
419  mark[myColInd[i]] = true;
420 
421  local_ordinal_type myNumCols = 0;
422  for(global_ordinal_type i = 0; i < globalNumRows; i++)
423  if(mark[i] == true)
424  myNumCols++;
425 
426  Kokkos::View<global_ordinal_type*, typename node_type::memory_space> myColGIDs("myColGIDs", myNumCols);
427  auto myColGIDs_host = Kokkos::create_mirror_view(Kokkos::HostSpace(), myColGIDs);
428 
429  myNumCols = 0;
430  for(global_ordinal_type i = 0; i < globalNumRows; i++)
431  if(mark[i] == true) {
432  myColGIDs_host(myNumCols)= i;
433  myNumCols++;
434  };
435 
436  Kokkos::deep_copy(myColGIDs, myColGIDs_host);
437 
438  Teuchos::RCP<const map_type> pColumnMap;
439  Tpetra::Details::makeColMap(pColumnMap, pDomainMap, myColGIDs);
440 
441  std::vector<local_ordinal_type> map(globalNumRows);
442  for(global_ordinal_type i = 0; i < globalNumRows; i++) {
443  if(mark[i] == true)
444  map[i] = pColumnMap->getLocalElement(i);
445  }
446 
447  Teuchos::ArrayRCP<local_ordinal_type> myLclColInd(myNumEntries);
448  for(size_t i = 0; i < myNumEntries; i++)
449  myLclColInd[i] = map[myColInd[i]];
450 
451  local_ordinal_type *cur = myLclColInd.getRawPtr();
452 
453  for(size_t i = 0; i < myNumRows; i++) {
454  size_t start = myRowPtr[i];
455  size_t end = myRowPtr[i+1];
456 
457  std::sort(&cur[start], &cur[end]);
458  }
459 
460  Teuchos::RCP<crs_graph_type> graph(new crs_graph_type(pRowMap, pColumnMap, myRowPtr, myLclColInd));
461  graph->fillComplete(pDomainMap, pRangeMap);
462 
463  Kokkos::View<scalar_type*, typename node_type::memory_space> values("values", myNumEntries);
464  Kokkos::deep_copy(values, 1.0);
465 
466  Teuchos::RCP<crs_matrix_type> pMatrix (new crs_matrix_type(graph, values));
467  pMatrix->fillComplete(pDomainMap, pRangeMap);
468 
469  pComm->barrier();
470  if (debug && myRank == rootRank) {
471  std::cout << "-- Done with fill complete." << std::endl;
472  }
473 
474  if(myRank == rootRank) {
475  delete [] rowPtr;
476  delete [] colInd;
477  }
478 
479  return pMatrix;
480 }
481 
482 template <typename crs_matrix_type>
483 Teuchos::RCP<crs_matrix_type>
484 readMatrixFromBinaryFile(std::string filename, const Teuchos::RCP<const Teuchos::Comm<int>> pComm, bool binary=true, bool debug=false)
485 {
486  return readBinaryFileFast<crs_matrix_type>(filename, pComm, true, debug);
487 }
488 
489 #endif
490 
void distribute(Teuchos::ArrayRCP< size_t > &myNumEntriesPerRow, Teuchos::ArrayRCP< size_t > &myRowPtr, Teuchos::ArrayRCP< global_ordinal_type > &myColInd, Teuchos::ArrayRCP< scalar_type > &myValues, const Teuchos::RCP< const map_type > &pRowMap, global_ordinal_type *rowPtr, global_ordinal_type *colInd, const bool debug=false)
Teuchos::RCP< crs_matrix_type > readBinaryFileFast(std::string filename, const Teuchos::RCP< const Teuchos::Comm< int >> pComm, bool callFillComplete=true, bool debug=false)
Teuchos::RCP< crs_matrix_type > readMatrixFromBinaryFile(std::string filename, const Teuchos::RCP< const Teuchos::Comm< int >> pComm, bool binary=true, bool debug=false)
Teuchos::RCP< crs_matrix_type > readBinaryFile(std::string filename, const Teuchos::RCP< const Teuchos::Comm< int >> pComm, bool callFillComplete=true, bool debug=false)