Zoltan2
Loading...
Searching...
No Matches
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
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
25using 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
46
47typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
48typedef Tpetra::CrsGraph<z2TestLO, z2TestGO> SparseGraph;
49typedef Tpetra::Vector<z2TestScalar, z2TestLO, z2TestGO> VectorT;
50typedef VectorT::node_type Node;
51
55
56
57// Integer vector
58typedef Tpetra::Vector<int, z2TestLO, z2TestGO> IntVector;
60
61#define epsilon 0.00000001
62#define NNZ_IDX 1
63
65int 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}
VectorT::node_type Node
#define epsilon
zlno_t z2TestLO
Tpetra::CrsGraph< z2TestLO, z2TestGO > SparseGraph
Zoltan2::XpetraMultiVectorAdapter< IntVector > IntVectorAdapter
#define NNZ_IDX
Tpetra::CrsMatrix< z2TestScalar, z2TestLO, z2TestGO > SparseMatrix
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > VectorT
Zoltan2::XpetraCrsMatrixAdapter< SparseMatrix > SparseMatrixAdapter
Zoltan2::XpetraMultiVectorAdapter< VectorT > MultiVectorAdapter
zgno_t z2TestGO
Tpetra::Vector< int, z2TestLO, z2TestGO > IntVector
zscalar_t z2TestScalar
Zoltan2::XpetraCrsGraphAdapter< SparseGraph > SparseGraphAdapter
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.
int main()
typename InputTraits< User >::part_t part_t
void solve(bool updateInputData=true)
Direct the problem to create a solution.
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:44
zscalar_t z2TestScalar
Definition coloring1.cpp:42
Tpetra::Vector< int, z2TestLO, z2TestGO > IntVector