Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Test_Sphynx.cpp
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 
14 #include <Zoltan2_TestHelpers.hpp>
15 #include <iostream>
16 #include <limits>
17 #include <Teuchos_ParameterList.hpp>
18 #include <Teuchos_RCP.hpp>
19 #include <Teuchos_FancyOStream.hpp>
20 #include <Teuchos_CommandLineProcessor.hpp>
21 #include <Tpetra_CrsMatrix.hpp>
22 #include <Tpetra_Vector.hpp>
23 #include <MatrixMarket_Tpetra.hpp>
24 
25 using Teuchos::RCP;
26 
28 // This program is a modified version of partitioning1.cpp (Karen Devine, 2011)
29 // which can be found in zoltan2/test/core/partition/.
30 // This version demonstrates use of Sphynx to partition a Tpetra matrix
31 // (read from a MatrixMarket file or generated by Galeri::Xpetra).
32 // Usage:
33 // Zoltan2_Sphynx.exe [--inputFile=filename] [--outputFile=outfile] [--verbose]
34 // [--x=#] [--y=#] [--z=#] [--matrix={Laplace1D,Laplace2D,Laplace3D}
35 // [--normalized] [--generalized] [--polynomial]
37 
39 // Eventually want to use Teuchos unit tests to vary z2TestLO and
40 // GO. For now, we set them at compile time based on whether Tpetra
41 // is built with explicit instantiation on. (in Zoltan2_TestHelpers.hpp)
42 
43 typedef zlno_t z2TestLO;
44 typedef zgno_t z2TestGO;
46 
47 typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
48 typedef Tpetra::CrsGraph<z2TestLO, z2TestGO> SparseGraph;
49 typedef Tpetra::Vector<z2TestScalar, z2TestLO, z2TestGO> VectorT;
50 typedef VectorT::node_type Node;
51 
55 
56 
57 // Integer vector
58 typedef Tpetra::Vector<int, z2TestLO, z2TestGO> IntVector;
60 
61 #define epsilon 0.00000001
62 #define NNZ_IDX 1
63 
65 int main(int narg, char** arg)
66 {
67  std::string inputFile = ""; // Matrix Market or Zoltan file to read
68  std::string outputFile = ""; // Matrix Market or Zoltan file to write
69  std::string inputPath = testDataFilePath; // Directory with input file
70  bool verbose = false; // Verbosity of output
71  bool distributeInput = true;
72  bool haveFailure = false;
73  int nVwgts = 0;
74  int testReturn = 0;
75 
76  // Sphynx-related parameters
77  bool isNormalized = false;
78  bool isGeneralized = false;
79  std::string precType = "jacobi";
80  std::string initialGuess = "random";
81  bool useFullOrtho = true;
82 
84  Tpetra::ScopeGuard tscope(&narg, &arg);
85  RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
86  int me = comm->getRank();
87  int commsize = comm->getSize();
88 
89  // Read run-time options.
90  Teuchos::CommandLineProcessor cmdp (false, false);
91  cmdp.setOption("inputPath", &inputPath,
92  "Path to the MatrixMarket or Zoltan file to be read; "
93  "if not specified, a default path will be used.");
94  cmdp.setOption("inputFile", &inputFile,
95  "Name of the Matrix Market or Zoltan file to read; "
96  "if not specified, a matrix will be generated by MueLu.");
97  cmdp.setOption("outputFile", &outputFile,
98  "Name of the Matrix Market sparse matrix file to write, "
99  "echoing the input/generated matrix.");
100  cmdp.setOption("vertexWeights", &nVwgts,
101  "Number of weights to generate for each vertex");
102  cmdp.setOption("verbose", "quiet", &verbose,
103  "Print messages and results.");
104  cmdp.setOption("distribute", "no-distribute", &distributeInput,
105  "indicate whether or not to distribute "
106  "input across the communicator");
107  // Sphynx-related parameters:
108  cmdp.setOption("normalized", "combinatorial", &isNormalized,
109  "indicate whether or not to use a normalized Laplacian.");
110  cmdp.setOption("generalized", "non-generalized", &isGeneralized,
111  "indicate whether or not to use a generalized Laplacian.");
112  cmdp.setOption("precond", &precType,
113  "indicate which preconditioner to use [muelu|jacobi|polynomial].");
114  cmdp.setOption("initialGuess", &initialGuess,
115  "initial guess for LOBPCG");
116  cmdp.setOption("useFullOrtho", "partialOrtho", &useFullOrtho,
117  "use full orthogonalization.");
118 
120  // Even with cmdp option "true", I get errors for having these
121  // arguments on the command line. (On redsky build)
122  // KDDKDD Should just be warnings, right? Code should still work with these
123  // KDDKDD params in the create-a-matrix file. Better to have them where
124  // KDDKDD they are used.
125  int xdim=10;
126  int ydim=10;
127  int zdim=10;
128  std::string matrixType("Laplace3D");
129 
130  cmdp.setOption("x", &xdim,
131  "number of gridpoints in X dimension for "
132  "mesh used to generate matrix.");
133  cmdp.setOption("y", &ydim,
134  "number of gridpoints in Y dimension for "
135  "mesh used to generate matrix.");
136  cmdp.setOption("z", &zdim,
137  "number of gridpoints in Z dimension for "
138  "mesh used to generate matrix.");
139  cmdp.setOption("matrix", &matrixType,
140  "Matrix type: Laplace1D, Laplace2D, or Laplace3D");
142 
143  cmdp.parse(narg, arg);
144 
145  RCP<UserInputForTests> uinput;
146 
147  if (inputFile != "") // Input file specified; read a matrix
148  uinput = rcp(new UserInputForTests(inputPath, inputFile, comm,
149  true, distributeInput));
150 
151  else // Let MueLu generate a default matrix
152  uinput = rcp(new UserInputForTests(xdim, ydim, zdim, string(""), comm,
153  true, distributeInput));
154 
155  RCP<SparseMatrix> origMatrix = uinput->getUITpetraCrsMatrix();
156 
157  if (origMatrix->getGlobalNumRows() < 40) {
158  Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false));
159  origMatrix->describe(out, Teuchos::VERB_EXTREME);
160  }
161 
162 
163  if (outputFile != "") {
164  // Just a sanity check.
165  Tpetra::MatrixMarket::Writer<SparseMatrix>::writeSparseFile(outputFile,
166  origMatrix, verbose);
167  }
168 
169  if (me == 0)
170  std::cout << "NumRows = " << origMatrix->getGlobalNumRows() << std::endl
171  << "NumNonzeros = " << origMatrix->getGlobalNumEntries() << std::endl
172  << "NumProcs = " << comm->getSize() << std::endl
173  << "NumLocalRows (rank 0) = " << origMatrix->getLocalNumRows() << std::endl;
174 
176  RCP<VectorT> origVector, origProd;
177  origProd = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
178  origMatrix->getRangeMap());
179  origVector = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
180  origMatrix->getDomainMap());
181  origVector->randomize();
182 
184  Teuchos::RCP<Teuchos::ParameterList> params(new Teuchos::ParameterList);
185  params->set("num_global_parts", commsize);
186  Teuchos::RCP<Teuchos::ParameterList> sphynxParams(new Teuchos::ParameterList);
187  sphynxParams->set("sphynx_skip_preprocessing", true); // Preprocessing has not been implemented yet.
188  sphynxParams->set("sphynx_preconditioner_type", precType);
189  sphynxParams->set("sphynx_verbosity", verbose ? 1 : 0);
190  sphynxParams->set("sphynx_initial_guess", initialGuess);
191  sphynxParams->set("sphynx_use_full_ortho", useFullOrtho);
192  std::string problemType = "combinatorial";
193  if(isNormalized)
194  problemType = "normalized";
195  else if(isGeneralized)
196  problemType = "generalized";
197  sphynxParams->set("sphynx_problem_type", problemType); // Type of the eigenvalue problem.
198 
200  Teuchos::RCP<SparseGraphAdapter> adapter = Teuchos::rcp( new SparseGraphAdapter(origMatrix->getCrsGraph(), nVwgts));
201 
205 
206  zscalar_t *vwgts = NULL;
207  if (nVwgts) {
208  // Test vertex weights with stride nVwgts.
209  size_t nrows = origMatrix->getLocalNumRows();
210  if (nrows) {
211  vwgts = new zscalar_t[nVwgts * nrows];
212  for (size_t i = 0; i < nrows; i++) {
213  size_t idx = i * nVwgts;
214  vwgts[idx] = zscalar_t(origMatrix->getRowMap()->getGlobalElement(i));
215  for (int j = 1; j < nVwgts; j++) vwgts[idx+j] = 1.;
216  }
217  for (int j = 0; j < nVwgts; j++) {
218  if (j != NNZ_IDX) adapter->setVertexWeights(&vwgts[j], nVwgts, j);
219  else adapter->setVertexWeightIsDegree(NNZ_IDX);
220  }
221  }
222  }
223 
225  Zoltan2::SphynxProblem<SparseGraphAdapter> problem(adapter.get(), params.get(), sphynxParams);
226 
227  try {
228  if (me == 0) std::cout << "Calling solve() " << std::endl;
229 
230  problem.solve();
231 
232  if (me == 0) std::cout << "Done solve() " << std::endl;
233  }
234  catch (std::runtime_error &e) {
235  delete [] vwgts;
236  std::cout << "Runtime exception returned from solve(): " << e.what();
237  if (!strncmp(e.what(), "BUILD ERROR", 11)) {
238  // Catching build errors as exceptions is OK in the tests
239  std::cout << " PASS" << std::endl;
240  return 0;
241  }
242  else {
243  // All other runtime_errors are failures
244  std::cout << " FAIL" << std::endl;
245  return -1;
246  }
247  }
248  catch (std::logic_error &e) {
249  delete [] vwgts;
250  std::cout << "Logic exception returned from solve(): " << e.what()
251  << " FAIL" << std::endl;
252  return -1;
253  }
254  catch (std::bad_alloc &e) {
255  delete [] vwgts;
256  std::cout << "Bad_alloc exception returned from solve(): " << e.what()
257  << " FAIL" << std::endl;
258  return -1;
259  }
260  catch (std::exception &e) {
261  delete [] vwgts;
262  std::cout << "Unknown exception returned from solve(). " << e.what()
263  << " FAIL" << std::endl;
264  return -1;
265  }
266 
269  size_t checkNparts = comm->getSize();
270 
271  size_t checkLength = origMatrix->getLocalNumRows();
272  const SparseGraphAdapter::part_t *checkParts = problem.getSolution().getPartListView();
273 
274  // Check for load balance
275  size_t *countPerPart = new size_t[checkNparts];
276  size_t *globalCountPerPart = new size_t[checkNparts];
277  zscalar_t *wtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL);
278  zscalar_t *globalWtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL);
279  for (size_t i = 0; i < checkNparts; i++) countPerPart[i] = 0;
280  for (size_t i = 0; i < checkNparts * nVwgts; i++) wtPerPart[i] = 0.;
281 
282  for (size_t i = 0; i < checkLength; i++) {
283  if (size_t(checkParts[i]) >= checkNparts)
284  std::cout << "Invalid Part " << checkParts[i] << ": FAIL" << std::endl;
285  countPerPart[checkParts[i]]++;
286  for (int j = 0; j < nVwgts; j++) {
287  if (j != NNZ_IDX)
288  wtPerPart[checkParts[i]*nVwgts+j] += vwgts[i*nVwgts+j];
289  else
290  wtPerPart[checkParts[i]*nVwgts+j] += origMatrix->getNumEntriesInLocalRow(i);
291  }
292  }
293  Teuchos::reduceAll<int, size_t>(*comm, Teuchos::REDUCE_SUM, checkNparts,
294  countPerPart, globalCountPerPart);
295  Teuchos::reduceAll<int, zscalar_t>(*comm, Teuchos::REDUCE_SUM,
296  checkNparts*nVwgts,
297  wtPerPart, globalWtPerPart);
298 
299  size_t min = std::numeric_limits<std::size_t>::max();
300  size_t max = 0;
301  size_t sum = 0;
302  size_t minrank = 0, maxrank = 0;
303  for (size_t i = 0; i < checkNparts; i++) {
304  if (globalCountPerPart[i] < min) {min = globalCountPerPart[i]; minrank = i;}
305  if (globalCountPerPart[i] > max) {max = globalCountPerPart[i]; maxrank = i;}
306  sum += globalCountPerPart[i];
307  }
308 
309  if (me == 0) {
310  float avg = (float) sum / (float) checkNparts;
311  std::cout << "Minimum count: " << min << " on rank " << minrank << std::endl;
312  std::cout << "Maximum count: " << max << " on rank " << maxrank << std::endl;
313  std::cout << "Average count: " << avg << std::endl;
314  std::cout << "Total count: " << sum
315  << (sum != origMatrix->getGlobalNumRows()
316  ? "Work was lost; FAIL"
317  : " ")
318  << std::endl;
319  std::cout << "Imbalance: " << max / avg << std::endl;
320  if (nVwgts) {
321  std::vector<zscalar_t> minwt(nVwgts, std::numeric_limits<zscalar_t>::max());
322  std::vector<zscalar_t> maxwt(nVwgts, 0.);
323  std::vector<zscalar_t> sumwt(nVwgts, 0.);
324  for (size_t i = 0; i < checkNparts; i++) {
325  for (int j = 0; j < nVwgts; j++) {
326  size_t idx = i*nVwgts+j;
327  if (globalWtPerPart[idx] < minwt[j]) minwt[j] = globalWtPerPart[idx];
328  if (globalWtPerPart[idx] > maxwt[j]) maxwt[j] = globalWtPerPart[idx];
329  sumwt[j] += globalWtPerPart[idx];
330  }
331  }
332  for (int j = 0; j < nVwgts; j++) {
333  float avgwt = (float) sumwt[j] / (float) checkNparts;
334  std::cout << std::endl;
335  std::cout << "Minimum weight[" << j << "]: " << minwt[j] << std::endl;
336  std::cout << "Maximum weight[" << j << "]: " << maxwt[j] << std::endl;
337  std::cout << "Average weight[" << j << "]: " << avgwt << std::endl;
338  std::cout << "Imbalance: " << maxwt[j] / avgwt << std::endl;
339  }
340  }
341  }
342 
343  delete [] countPerPart;
344  delete [] wtPerPart;
345  delete [] globalCountPerPart;
346  delete [] globalWtPerPart;
347  delete [] vwgts;
348 
350  if (me == 0) std::cout << "Redistributing matrix..." << std::endl;
351  SparseMatrix *redistribMatrix;
352  SparseMatrixAdapter adapterMatrix(origMatrix);
353  adapterMatrix.applyPartitioningSolution(*origMatrix, redistribMatrix,
354  problem.getSolution());
355  if (redistribMatrix->getGlobalNumRows() < 40) {
356  Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false));
357  redistribMatrix->describe(out, Teuchos::VERB_EXTREME);
358  }
359 
360  if (me == 0) std::cout << "Redistributing vectors..." << std::endl;
361  VectorT *redistribVector;
362  MultiVectorAdapter adapterVector(origVector); //, weights, weightStrides);
363  adapterVector.applyPartitioningSolution(*origVector, redistribVector,
364  problem.getSolution());
365 
366  RCP<VectorT> redistribProd;
367  redistribProd = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
368  redistribMatrix->getRangeMap());
369 
370  // Test redistributing an integer vector with the same solution.
371  // This test is mostly to make sure compilation always works.
372  RCP<IntVector> origIntVec;
373  IntVector *redistIntVec;
374  origIntVec = Tpetra::createVector<int,z2TestLO,z2TestGO>(
375  origMatrix->getRangeMap());
376  for (size_t i = 0; i < origIntVec->getLocalLength(); i++)
377  origIntVec->replaceLocalValue(i, me);
378 
379  IntVectorAdapter int_vec_adapter(origIntVec);
380  int_vec_adapter.applyPartitioningSolution(*origIntVec, redistIntVec,
381  problem.getSolution());
382  int origIntNorm = origIntVec->norm1();
383  int redistIntNorm = redistIntVec->norm1();
384  if (me == 0) std::cout << "IntegerVectorTest: " << origIntNorm << " == "
385  << redistIntNorm << " ?";
386  if (origIntNorm != redistIntNorm) {
387  if (me == 0) std::cout << " FAIL" << std::endl;
388  haveFailure = true;
389  }
390  else if (me == 0) std::cout << " OK" << std::endl;
391  delete redistIntVec;
392 
395 
396  if (me == 0) std::cout << "Matvec original..." << std::endl;
397  origMatrix->apply(*origVector, *origProd);
398  z2TestScalar origNorm = origProd->norm2();
399  if (me == 0)
400  std::cout << "Norm of Original matvec prod: " << origNorm << std::endl;
401 
402  if (me == 0) std::cout << "Matvec redistributed..." << std::endl;
403  redistribMatrix->apply(*redistribVector, *redistribProd);
404  z2TestScalar redistribNorm = redistribProd->norm2();
405  if (me == 0)
406  std::cout << "Norm of Redistributed matvec prod: " << redistribNorm << std::endl;
407 
408  if (redistribNorm > origNorm+epsilon || redistribNorm < origNorm-epsilon) {
409  testReturn = 1;
410  haveFailure = true;
411  }
412 
413  delete redistribVector;
414  delete redistribMatrix;
415 
416  if (me == 0) {
417  if (testReturn) {
418  std::cout << "Mat-Vec product changed; FAIL" << std::endl;
419  haveFailure = true;
420  }
421  if (!haveFailure)
422  std::cout << "PASS" << std::endl;
423  }
424 
425  return testReturn;
426 }
zgno_t z2TestGO
Definition: coloring1.cpp:41
zlno_t z2TestLO
Definition: coloring1.cpp:40
Provides access for Zoltan2 to Xpetra::CrsMatrix data.
Tpetra::CrsMatrix< z2TestScalar, z2TestLO, z2TestGO > SparseMatrix
Definition: coloring1.cpp:44
Provides access for Zoltan2 to Xpetra::CrsGraph data.
Zoltan2::XpetraCrsGraphAdapter< SparseGraph > SparseGraphAdapter
int main(int narg, char **arg)
Definition: coloring1.cpp:164
common code used by tests
typename InputTraits< User >::part_t part_t
#define epsilon
Definition: Test_Sphynx.cpp:61
Defines the XpetraMultiVectorAdapter.
Defines XpetraCrsGraphAdapter class.
Defines the XpetraCrsMatrixAdapter class.
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
An adapter for Xpetra::MultiVector.
Tpetra::Map::local_ordinal_type zlno_t
#define NNZ_IDX
Definition: Test_Sphynx.cpp:62
Zoltan2::XpetraMultiVectorAdapter< IntVector > IntVectorAdapter
Tpetra::CrsGraph< z2TestLO, z2TestGO > SparseGraph
Zoltan2::XpetraCrsMatrixAdapter< SparseMatrix > SparseMatrixAdapter
Definition: coloring1.cpp:50
Tpetra::Vector< int, z2TestLO, z2TestGO > IntVector
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
zscalar_t z2TestScalar
Definition: coloring1.cpp:42
float zscalar_t
Zoltan2::XpetraMultiVectorAdapter< Vector > MultiVectorAdapter
Tpetra::Map::global_ordinal_type zgno_t
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > VectorT
Definition: Test_Sphynx.cpp:49
void solve(bool updateInputData=true)
Direct the problem to create a solution.
Vector::node_type Node
Definition: coloring1.cpp:46
std::string testDataFilePath(".")