Zoltan2
Test_Sphynx.cpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Seher Acer (sacer@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 // Karen Devine (kddevin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
50 #include <Zoltan2_TestHelpers.hpp>
51 #include <iostream>
52 #include <limits>
53 #include <Teuchos_ParameterList.hpp>
54 #include <Teuchos_RCP.hpp>
55 #include <Teuchos_FancyOStream.hpp>
56 #include <Teuchos_CommandLineProcessor.hpp>
57 #include <Tpetra_CrsMatrix.hpp>
58 #include <Tpetra_Vector.hpp>
59 #include <MatrixMarket_Tpetra.hpp>
60 
61 using Teuchos::RCP;
62 
64 // This program is a modified version of partitioning1.cpp (Karen Devine, 2011)
65 // which can be found in zoltan2/test/core/partition/.
66 // This version demonstrates use of Sphynx to partition a Tpetra matrix
67 // (read from a MatrixMarket file or generated by Galeri::Xpetra).
68 // Usage:
69 // Zoltan2_Sphynx.exe [--inputFile=filename] [--outputFile=outfile] [--verbose]
70 // [--x=#] [--y=#] [--z=#] [--matrix={Laplace1D,Laplace2D,Laplace3D}
71 // [--normalized] [--generalized] [--polynomial]
73 
75 // Eventually want to use Teuchos unit tests to vary z2TestLO and
76 // GO. For now, we set them at compile time based on whether Tpetra
77 // is built with explicit instantiation on. (in Zoltan2_TestHelpers.hpp)
78 
79 typedef zlno_t z2TestLO;
80 typedef zgno_t z2TestGO;
82 
83 typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
84 typedef Tpetra::CrsGraph<z2TestLO, z2TestGO> SparseGraph;
85 typedef Tpetra::Vector<z2TestScalar, z2TestLO, z2TestGO> Vector;
86 typedef Vector::node_type Node;
87 
91 
92 
93 // Integer vector
94 typedef Tpetra::Vector<int, z2TestLO, z2TestGO> IntVector;
96 
97 #define epsilon 0.00000001
98 #define NNZ_IDX 1
99 
101 int main(int narg, char** arg)
102 {
103  std::string inputFile = ""; // Matrix Market or Zoltan file to read
104  std::string outputFile = ""; // Matrix Market or Zoltan file to write
105  std::string inputPath = testDataFilePath; // Directory with input file
106  bool verbose = false; // Verbosity of output
107  bool distributeInput = true;
108  bool haveFailure = false;
109  int nVwgts = 0;
110  int testReturn = 0;
111 
112  // Sphynx-related parameters
113  bool isNormalized = false;
114  bool isGeneralized = false;
115  std::string precType = "jacobi";
116  std::string initialGuess = "random";
117  bool useFullOrtho = true;
118 
120  Tpetra::ScopeGuard tscope(&narg, &arg);
121  RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
122  int me = comm->getRank();
123  int commsize = comm->getSize();
124 
125  // Read run-time options.
126  Teuchos::CommandLineProcessor cmdp (false, false);
127  cmdp.setOption("inputPath", &inputPath,
128  "Path to the MatrixMarket or Zoltan file to be read; "
129  "if not specified, a default path will be used.");
130  cmdp.setOption("inputFile", &inputFile,
131  "Name of the Matrix Market or Zoltan file to read; "
132  "if not specified, a matrix will be generated by MueLu.");
133  cmdp.setOption("outputFile", &outputFile,
134  "Name of the Matrix Market sparse matrix file to write, "
135  "echoing the input/generated matrix.");
136  cmdp.setOption("vertexWeights", &nVwgts,
137  "Number of weights to generate for each vertex");
138  cmdp.setOption("verbose", "quiet", &verbose,
139  "Print messages and results.");
140  cmdp.setOption("distribute", "no-distribute", &distributeInput,
141  "indicate whether or not to distribute "
142  "input across the communicator");
143  // Sphynx-related parameters:
144  cmdp.setOption("normalized", "combinatorial", &isNormalized,
145  "indicate whether or not to use a normalized Laplacian.");
146  cmdp.setOption("generalized", "non-generalized", &isGeneralized,
147  "indicate whether or not to use a generalized Laplacian.");
148  cmdp.setOption("precond", &precType,
149  "indicate which preconditioner to use [muelu|jacobi|polynomial].");
150  cmdp.setOption("initialGuess", &initialGuess,
151  "initial guess for LOBPCG");
152  cmdp.setOption("useFullOrtho", "partialOrtho", &useFullOrtho,
153  "use full orthogonalization.");
154 
156  // Even with cmdp option "true", I get errors for having these
157  // arguments on the command line. (On redsky build)
158  // KDDKDD Should just be warnings, right? Code should still work with these
159  // KDDKDD params in the create-a-matrix file. Better to have them where
160  // KDDKDD they are used.
161  int xdim=10;
162  int ydim=10;
163  int zdim=10;
164  std::string matrixType("Laplace3D");
165 
166  cmdp.setOption("x", &xdim,
167  "number of gridpoints in X dimension for "
168  "mesh used to generate matrix.");
169  cmdp.setOption("y", &ydim,
170  "number of gridpoints in Y dimension for "
171  "mesh used to generate matrix.");
172  cmdp.setOption("z", &zdim,
173  "number of gridpoints in Z dimension for "
174  "mesh used to generate matrix.");
175  cmdp.setOption("matrix", &matrixType,
176  "Matrix type: Laplace1D, Laplace2D, or Laplace3D");
178 
179  cmdp.parse(narg, arg);
180 
181  RCP<UserInputForTests> uinput;
182 
183  if (inputFile != "") // Input file specified; read a matrix
184  uinput = rcp(new UserInputForTests(inputPath, inputFile, comm,
185  true, distributeInput));
186 
187  else // Let MueLu generate a default matrix
188  uinput = rcp(new UserInputForTests(xdim, ydim, zdim, string(""), comm,
189  true, distributeInput));
190 
191  RCP<SparseMatrix> origMatrix = uinput->getUITpetraCrsMatrix();
192 
193  if (origMatrix->getGlobalNumRows() < 40) {
194  Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false));
195  origMatrix->describe(out, Teuchos::VERB_EXTREME);
196  }
197 
198 
199  if (outputFile != "") {
200  // Just a sanity check.
201  Tpetra::MatrixMarket::Writer<SparseMatrix>::writeSparseFile(outputFile,
202  origMatrix, verbose);
203  }
204 
205  if (me == 0)
206  std::cout << "NumRows = " << origMatrix->getGlobalNumRows() << std::endl
207  << "NumNonzeros = " << origMatrix->getGlobalNumEntries() << std::endl
208  << "NumProcs = " << comm->getSize() << std::endl
209  << "NumLocalRows (rank 0) = " << origMatrix->getNodeNumRows() << std::endl;
210 
212  RCP<Vector> origVector, origProd;
213  origProd = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
214  origMatrix->getRangeMap());
215  origVector = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
216  origMatrix->getDomainMap());
217  origVector->randomize();
218 
220  Teuchos::RCP<Teuchos::ParameterList> params(new Teuchos::ParameterList);
221  params->set("num_global_parts", commsize);
222  params->set("sphynx_skip_preprocessing", true); // Preprocessing has not been implemented yet.
223  params->set("sphynx_preconditioner_type", precType);
224  params->set("sphynx_verbosity", verbose ? 1 : 0);
225  params->set("sphynx_initial_guess", initialGuess);
226  params->set("sphynx_use_full_ortho", useFullOrtho);
227  std::string problemType = "combinatorial";
228  if(isNormalized)
229  problemType = "normalized";
230  else if(isGeneralized)
231  problemType = "generalized";
232  params->set("sphynx_problem_type", problemType); // Type of the eigenvalue problem.
233 
235  Teuchos::RCP<SparseGraphAdapter> adapter = Teuchos::rcp( new SparseGraphAdapter(origMatrix->getCrsGraph(), nVwgts));
236 
240 
241  zscalar_t *vwgts = NULL;
242  if (nVwgts) {
243  // Test vertex weights with stride nVwgts.
244  size_t nrows = origMatrix->getNodeNumRows();
245  if (nrows) {
246  vwgts = new zscalar_t[nVwgts * nrows];
247  for (size_t i = 0; i < nrows; i++) {
248  size_t idx = i * nVwgts;
249  vwgts[idx] = zscalar_t(origMatrix->getRowMap()->getGlobalElement(i));
250  for (int j = 1; j < nVwgts; j++) vwgts[idx+j] = 1.;
251  }
252  for (int j = 0; j < nVwgts; j++) {
253  if (j != NNZ_IDX) adapter->setVertexWeights(&vwgts[j], nVwgts, j);
254  else adapter->setVertexWeightIsDegree(NNZ_IDX);
255  }
256  }
257  }
258 
260  Zoltan2::SphynxProblem<SparseGraphAdapter> problem(adapter, params);
261 
262  try {
263  if (me == 0) std::cout << "Calling solve() " << std::endl;
264 
265  problem.solve();
266 
267  if (me == 0) std::cout << "Done solve() " << std::endl;
268  }
269  catch (std::runtime_error &e) {
270  delete [] vwgts;
271  std::cout << "Runtime exception returned from solve(): " << e.what();
272  if (!strncmp(e.what(), "BUILD ERROR", 11)) {
273  // Catching build errors as exceptions is OK in the tests
274  std::cout << " PASS" << std::endl;
275  return 0;
276  }
277  else {
278  // All other runtime_errors are failures
279  std::cout << " FAIL" << std::endl;
280  return -1;
281  }
282  }
283  catch (std::logic_error &e) {
284  delete [] vwgts;
285  std::cout << "Logic exception returned from solve(): " << e.what()
286  << " FAIL" << std::endl;
287  return -1;
288  }
289  catch (std::bad_alloc &e) {
290  delete [] vwgts;
291  std::cout << "Bad_alloc exception returned from solve(): " << e.what()
292  << " FAIL" << std::endl;
293  return -1;
294  }
295  catch (std::exception &e) {
296  delete [] vwgts;
297  std::cout << "Unknown exception returned from solve(). " << e.what()
298  << " FAIL" << std::endl;
299  return -1;
300  }
301 
304  size_t checkNparts = comm->getSize();
305 
306  size_t checkLength = origMatrix->getNodeNumRows();
307  const SparseGraphAdapter::part_t *checkParts = problem.getSolution().getPartListView();
308 
309  // Check for load balance
310  size_t *countPerPart = new size_t[checkNparts];
311  size_t *globalCountPerPart = new size_t[checkNparts];
312  zscalar_t *wtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL);
313  zscalar_t *globalWtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL);
314  for (size_t i = 0; i < checkNparts; i++) countPerPart[i] = 0;
315  for (size_t i = 0; i < checkNparts * nVwgts; i++) wtPerPart[i] = 0.;
316 
317  for (size_t i = 0; i < checkLength; i++) {
318  if (size_t(checkParts[i]) >= checkNparts)
319  std::cout << "Invalid Part " << checkParts[i] << ": FAIL" << std::endl;
320  countPerPart[checkParts[i]]++;
321  for (int j = 0; j < nVwgts; j++) {
322  if (j != NNZ_IDX)
323  wtPerPart[checkParts[i]*nVwgts+j] += vwgts[i*nVwgts+j];
324  else
325  wtPerPart[checkParts[i]*nVwgts+j] += origMatrix->getNumEntriesInLocalRow(i);
326  }
327  }
328  Teuchos::reduceAll<int, size_t>(*comm, Teuchos::REDUCE_SUM, checkNparts,
329  countPerPart, globalCountPerPart);
330  Teuchos::reduceAll<int, zscalar_t>(*comm, Teuchos::REDUCE_SUM,
331  checkNparts*nVwgts,
332  wtPerPart, globalWtPerPart);
333 
334  size_t min = std::numeric_limits<std::size_t>::max();
335  size_t max = 0;
336  size_t sum = 0;
337  size_t minrank = 0, maxrank = 0;
338  for (size_t i = 0; i < checkNparts; i++) {
339  if (globalCountPerPart[i] < min) {min = globalCountPerPart[i]; minrank = i;}
340  if (globalCountPerPart[i] > max) {max = globalCountPerPart[i]; maxrank = i;}
341  sum += globalCountPerPart[i];
342  }
343 
344  if (me == 0) {
345  float avg = (float) sum / (float) checkNparts;
346  std::cout << "Minimum count: " << min << " on rank " << minrank << std::endl;
347  std::cout << "Maximum count: " << max << " on rank " << maxrank << std::endl;
348  std::cout << "Average count: " << avg << std::endl;
349  std::cout << "Total count: " << sum
350  << (sum != origMatrix->getGlobalNumRows()
351  ? "Work was lost; FAIL"
352  : " ")
353  << std::endl;
354  std::cout << "Imbalance: " << max / avg << std::endl;
355  if (nVwgts) {
356  std::vector<zscalar_t> minwt(nVwgts, std::numeric_limits<zscalar_t>::max());
357  std::vector<zscalar_t> maxwt(nVwgts, 0.);
358  std::vector<zscalar_t> sumwt(nVwgts, 0.);
359  for (size_t i = 0; i < checkNparts; i++) {
360  for (int j = 0; j < nVwgts; j++) {
361  size_t idx = i*nVwgts+j;
362  if (globalWtPerPart[idx] < minwt[j]) minwt[j] = globalWtPerPart[idx];
363  if (globalWtPerPart[idx] > maxwt[j]) maxwt[j] = globalWtPerPart[idx];
364  sumwt[j] += globalWtPerPart[idx];
365  }
366  }
367  for (int j = 0; j < nVwgts; j++) {
368  float avgwt = (float) sumwt[j] / (float) checkNparts;
369  std::cout << std::endl;
370  std::cout << "Minimum weight[" << j << "]: " << minwt[j] << std::endl;
371  std::cout << "Maximum weight[" << j << "]: " << maxwt[j] << std::endl;
372  std::cout << "Average weight[" << j << "]: " << avgwt << std::endl;
373  std::cout << "Imbalance: " << maxwt[j] / avgwt << std::endl;
374  }
375  }
376  }
377 
378  delete [] countPerPart;
379  delete [] wtPerPart;
380  delete [] globalCountPerPart;
381  delete [] globalWtPerPart;
382  delete [] vwgts;
383 
385  if (me == 0) std::cout << "Redistributing matrix..." << std::endl;
386  SparseMatrix *redistribMatrix;
387  SparseMatrixAdapter adapterMatrix(origMatrix);
388  adapterMatrix.applyPartitioningSolution(*origMatrix, redistribMatrix,
389  problem.getSolution());
390  if (redistribMatrix->getGlobalNumRows() < 40) {
391  Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false));
392  redistribMatrix->describe(out, Teuchos::VERB_EXTREME);
393  }
394 
395  if (me == 0) std::cout << "Redistributing vectors..." << std::endl;
396  Vector *redistribVector;
397  MultiVectorAdapter adapterVector(origVector); //, weights, weightStrides);
398  adapterVector.applyPartitioningSolution(*origVector, redistribVector,
399  problem.getSolution());
400 
401  RCP<Vector> redistribProd;
402  redistribProd = Tpetra::createVector<z2TestScalar,z2TestLO,z2TestGO>(
403  redistribMatrix->getRangeMap());
404 
405  // Test redistributing an integer vector with the same solution.
406  // This test is mostly to make sure compilation always works.
407  RCP<IntVector> origIntVec;
408  IntVector *redistIntVec;
409  origIntVec = Tpetra::createVector<int,z2TestLO,z2TestGO>(
410  origMatrix->getRangeMap());
411  for (size_t i = 0; i < origIntVec->getLocalLength(); i++)
412  origIntVec->replaceLocalValue(i, me);
413 
414  IntVectorAdapter int_vec_adapter(origIntVec);
415  int_vec_adapter.applyPartitioningSolution(*origIntVec, redistIntVec,
416  problem.getSolution());
417  int origIntNorm = origIntVec->norm1();
418  int redistIntNorm = redistIntVec->norm1();
419  if (me == 0) std::cout << "IntegerVectorTest: " << origIntNorm << " == "
420  << redistIntNorm << " ?";
421  if (origIntNorm != redistIntNorm) {
422  if (me == 0) std::cout << " FAIL" << std::endl;
423  haveFailure = true;
424  }
425  else if (me == 0) std::cout << " OK" << std::endl;
426  delete redistIntVec;
427 
430 
431  if (me == 0) std::cout << "Matvec original..." << std::endl;
432  origMatrix->apply(*origVector, *origProd);
433  z2TestScalar origNorm = origProd->norm2();
434  if (me == 0)
435  std::cout << "Norm of Original matvec prod: " << origNorm << std::endl;
436 
437  if (me == 0) std::cout << "Matvec redistributed..." << std::endl;
438  redistribMatrix->apply(*redistribVector, *redistribProd);
439  z2TestScalar redistribNorm = redistribProd->norm2();
440  if (me == 0)
441  std::cout << "Norm of Redistributed matvec prod: " << redistribNorm << std::endl;
442 
443  if (redistribNorm > origNorm+epsilon || redistribNorm < origNorm-epsilon) {
444  testReturn = 1;
445  haveFailure = true;
446  }
447 
448  delete redistribVector;
449  delete redistribMatrix;
450 
451  if (me == 0) {
452  if (testReturn) {
453  std::cout << "Mat-Vec product changed; FAIL" << std::endl;
454  haveFailure = true;
455  }
456  if (!haveFailure)
457  std::cout << "PASS" << std::endl;
458  }
459 
460  return testReturn;
461 }
#define epsilon
Definition: Test_Sphynx.cpp:97
Vector::node_type Node
Definition: Test_Sphynx.cpp:86
zlno_t z2TestLO
Definition: Test_Sphynx.cpp:79
Tpetra::CrsGraph< z2TestLO, z2TestGO > SparseGraph
Definition: Test_Sphynx.cpp:84
Zoltan2::XpetraMultiVectorAdapter< IntVector > IntVectorAdapter
Definition: Test_Sphynx.cpp:95
#define NNZ_IDX
Definition: Test_Sphynx.cpp:98
Tpetra::CrsMatrix< z2TestScalar, z2TestLO, z2TestGO > SparseMatrix
Definition: Test_Sphynx.cpp:83
Zoltan2::XpetraMultiVectorAdapter< Vector > MultiVectorAdapter
Definition: Test_Sphynx.cpp:90
Zoltan2::XpetraCrsMatrixAdapter< SparseMatrix > SparseMatrixAdapter
Definition: Test_Sphynx.cpp:88
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > Vector
Definition: Test_Sphynx.cpp:85
zgno_t z2TestGO
Definition: Test_Sphynx.cpp:80
Tpetra::Vector< int, z2TestLO, z2TestGO > IntVector
Definition: Test_Sphynx.cpp:94
zscalar_t z2TestScalar
Definition: Test_Sphynx.cpp:81
Zoltan2::XpetraCrsGraphAdapter< SparseGraph > SparseGraphAdapter
Definition: Test_Sphynx.cpp:89
int main(int narg, char **arg)
common code used by tests
float zscalar_t
Tpetra::Map ::local_ordinal_type zlno_t
std::string testDataFilePath(".")
Tpetra::Map ::global_ordinal_type zgno_t
Defines XpetraCrsGraphAdapter class.
Defines the XpetraCrsMatrixAdapter class.
Defines the XpetraMultiVectorAdapter.
InputTraits< User >::part_t part_t
const PartitioningSolution< Adapter > & getSolution()
Provides access for Zoltan2 to Xpetra::CrsGraph data.
Provides access for Zoltan2 to Xpetra::CrsMatrix data.
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
Tpetra::CrsMatrix< z2TestScalar, z2TestLO, z2TestGO > SparseMatrix
Definition: coloring1.cpp:79
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > Vector
Definition: coloring1.cpp:80
zscalar_t z2TestScalar
Definition: coloring1.cpp:77
Tpetra::Vector< int, z2TestLO, z2TestGO > IntVector