Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
coloring1.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 
10 #include <iostream>
11 #include <fstream>
12 #include <limits>
13 #include <vector>
14 #include <Teuchos_RCP.hpp>
15 #include <Teuchos_ParameterList.hpp>
16 #include <Teuchos_CommandLineProcessor.hpp>
17 #include <Tpetra_CrsMatrix.hpp>
18 #include <Tpetra_Vector.hpp>
19 #include <MatrixMarket_Tpetra.hpp>
21 #include <Zoltan2_TestHelpers.hpp>
23 
24 using Teuchos::RCP;
25 
27 // Program to demonstrate use of Zoltan2 to color a TPetra matrix
28 // (read from a MatrixMarket file or generated by Galeri::Xpetra).
29 // We assume the matrix is structurally symmetric.
30 // Usage:
31 // a.out [--inputFile=filename] [--outputFile=outfile] [--verbose]
32 // [--x=#] [--y=#] [--z=#] [--matrix={Laplace1D,Laplace2D,Laplace3D}
34 
36 // Eventually want to use Teuchos unit tests to vary z2TestLO and
37 // GO. For now, we set them at compile time based on whether Tpetra
38 // is built with explicit instantiation on. (in Zoltan2_TestHelpers.hpp)
39 
40 typedef zlno_t z2TestLO;
41 typedef zgno_t z2TestGO;
43 
44 typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
45 typedef Tpetra::Vector<z2TestScalar, z2TestLO, z2TestGO> Vector;
46 typedef Vector::node_type Node;
47 
48 typedef Tpetra::Import<z2TestLO, z2TestGO> Import;
49 
51 
52 int validateColoring(RCP<SparseMatrix> A, int *color)
53 // returns 0 if coloring is valid, nonzero if invalid
54 {
55  if (A->getRowMap()->getComm()->getRank() == 0)
56  std::cout << "validate coloring: local graph, distance-one" << std::endl;
57  int nconflicts = 0;
58  typename tcrsMatrix_t::local_inds_host_view_type indices;
59  typename tcrsMatrix_t::values_host_view_type values;
60  // Count conflicts in the graph.
61  // Loop over local rows, treat local column indices as edges.
62  zlno_t n = A->getLocalNumRows();
63  for (zlno_t i=0; i<n; i++) {
64  A->getLocalRowView(i, indices, values);
65  for (zlno_t j=0; j<static_cast<zlno_t>(indices.extent(0)); j++) {
66  if ((indices[j]<n) && (indices[j]!=i) && (color[i]==color[indices[j]])){
67  nconflicts++;
68  //std::cout << "Debug: found conflict (" << i << ", " << indices[j] << ")" << std::endl;
69  }
70  }
71  }
72 
73  return nconflicts;
74 }
75 
76 int validateDistributedColoring(RCP<SparseMatrix> A, int *color){
77  if (A->getRowMap()->getComm()->getRank() == 0)
78  std::cout << "validate coloring: distributed, distance-one" << std::endl;
79  int nconflicts = 0;
80  RCP<const SparseMatrix::map_type> rowMap = A->getRowMap();
81  RCP<const SparseMatrix::map_type> colMap = A->getColMap();
82  Vector R = Vector(rowMap);
83  //put colors in the scalar entries of R
84  for(size_t i = 0; i < A->getLocalNumRows(); i++){
85  R.replaceLocalValue(i, color[i]);
86  }
87 
88  Vector C = Vector(colMap);
89  Import imp = Import(rowMap, colMap);
90  C.doImport(R, imp, Tpetra::REPLACE);
91 
92  typename tcrsMatrix_t::local_inds_host_view_type indices;
93  typename tcrsMatrix_t::values_host_view_type values;
94 
95  //count conflicts in the graph
96  //loop over local rows, treat local column indices as edges
97  size_t n = A->getLocalNumRows();
98  auto colorData = C.getData();
99  for(size_t i = 0; i < n; i++){
100  A->getLocalRowView(i, indices, values);
101  for(size_t j = 0; j < indices.extent(0); j++){
102  if(values[j] == 0) continue; //this catches removed entries.
103  if( (rowMap->getGlobalElement(i) != colMap->getGlobalElement(indices[j])) && (color[i] == colorData[indices[j]]) ){
104  nconflicts++;
105  }
106  }
107  }
108 
109  return nconflicts;
110 }
111 
112 int validateDistributedDistance2Coloring(RCP<SparseMatrix> A, int* color){
113 
114  if (A->getRowMap()->getComm()->getRank() == 0)
115  std::cout << "validate coloring: distributed, distance-two" << std::endl;
116 
117  //To check distance-2 conflicts, we square the input matrix and check
118  //for distance-1 conflicts on the squared matrix.
119  RCP<SparseMatrix> S = rcp(new SparseMatrix(A->getRowMap(), 0));
120  Tpetra::MatrixMatrix::Multiply(*A, true, *A, false, *S);
121 
122  return validateDistributedColoring(S,color);
123 }
124 
125 int checkBalance(zlno_t n, int *color)
126 // Check size of color classes
127 {
128  // Find max color
129  int maxColor = 0;
130  for (zlno_t i=0; i<n; i++) {
131  if (color[i] > maxColor) maxColor = color[i];
132  }
133 
134  // Compute color class sizes
135  Teuchos::Array<int> colorCount(maxColor+1);
136  for (zlno_t i=0; i<n; i++) {
137  colorCount[color[i]]++;
138  }
139 
140  // Find min and max, excluding color 0.
141  int smallest = 1;
142  int largest = 1;
143  zlno_t small = colorCount[1];
144  zlno_t large = colorCount[1];
145  for (int i=1; i<=maxColor; i++){
146  if (colorCount[i] < small){
147  small = colorCount[i];
148  smallest = i;
149  }
150  if (colorCount[i] > large){
151  large = colorCount[i];
152  largest = i;
153  }
154  }
155 
156  //std::cout << "Color size[0:2] = " << colorCount[0] << ", " << colorCount[1] << ", " << colorCount[2] << std::endl;
157  std::cout << "Largest color class = " << largest << " with " << colorCount[largest] << " vertices." << std::endl;
158  std::cout << "Smallest color class = " << smallest << " with " << colorCount[smallest] << " vertices." << std::endl;
159 
160  return 0;
161 }
162 
164 int main(int narg, char** arg)
165 {
166  std::string inputFile = ""; // Matrix Market file to read
167  std::string outputFile = ""; // Output file to write
168  std::string colorAlg = "SerialGreedy"; // Default algorithm is the serial greedy
169  bool verbose = false; // Verbosity of output
170  bool timing = false; // If true, report coloring times.
171  int testReturn = 0;
172  bool recolorDegrees = false;
173  std::string prepartition = ""; // Call Zoltan2 partitioning to better distribute
174  // the graph before coloring
175  bool prepartition_rows = false; // True if we're prepartitioning wrt rows
176  bool prepartition_nonzeros = false; // True if prepartitioning wrt matrix nonzeros
177 
178  int localColors = 0;
179  int totalColors = 0;
181  Tpetra::ScopeGuard tscope(&narg, &arg);
182  Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
183  int me = comm->getRank();
184  int serialThreshold = 0;
185  // Read run-time options.
186  Teuchos::CommandLineProcessor cmdp (false, false);
187  cmdp.setOption("colorMethod", &colorAlg,
188  "Coloring algorithms supported: SerialGreedy, D1, D1-2GL, D2, PD2");
189  cmdp.setOption("inputFile", &inputFile,
190  "Name of a Matrix Market file in the data directory; "
191  "if not specified, a matrix will be generated by Galeri.");
192  cmdp.setOption("outputFile", &outputFile,
193  "Name of file to write the coloring");
194  cmdp.setOption("verbose", "quiet", &verbose,
195  "Print messages and results.");
196  cmdp.setOption("prepartition", &prepartition,
197  "Partition the input graph for better initial distribution;"
198  "valid values are rows and nonzeros");
199  cmdp.setOption("serialThreshold", &serialThreshold,
200  "number of vertices to recolor in serial");
201  cmdp.setOption("recolorDegrees","recolorRandom",&recolorDegrees,
202  "recolor based on vertex degrees or random numbers");
203  cmdp.setOption("timing", "notimes", &timing,
204  "report how long coloring takes");
205  std::cout << "Starting everything" << std::endl;
206 
208  // Even with cmdp option "true", I get errors for having these
209  // arguments on the command line. (On redsky build)
210  // KDDKDD Should just be warnings, right? Code should still work with these
211  // KDDKDD params in the create-a-matrix file. Better to have them where
212  // KDDKDD they are used.
213  int xdim=10;
214  int ydim=10;
215  int zdim=10;
216  std::string matrixType("Laplace3D");
217 
218  cmdp.setOption("x", &xdim,
219  "number of gridpoints in X dimension for "
220  "mesh used to generate matrix.");
221  cmdp.setOption("y", &ydim,
222  "number of gridpoints in Y dimension for "
223  "mesh used to generate matrix.");
224  cmdp.setOption("z", &zdim,
225  "number of gridpoints in Z dimension for "
226  "mesh used to generate matrix.");
227  cmdp.setOption("matrix", &matrixType,
228  "Matrix type: Laplace1D, Laplace2D, or Laplace3D");
229 
231  // Coloring options to test.
233  std::string colorMethod("FirstFit");
234  //int balanceColors = 0;
235  cmdp.setOption("color_choice", &colorMethod,
236  "Color choice method: FirstFit, LeastUsed, Random, RandomFast");
237  // cmdp.setOption("balance_colors", &balanceColors,
238  // "Balance the size of color classes: 0/1 for false/true");
239 
241  cmdp.parse(narg, arg);
242 
243  if(prepartition != ""){
244  if(prepartition == "rows") prepartition_rows = true;
245  else if (prepartition == "nonzeros") prepartition_nonzeros = true;
246  else {
247  std::cout << "Invalid value of prepartition option " << prepartition
248  << std::endl;
249  std::cout << "No prepartitioning will be done" <<std::endl;
250  }
251  }
252 
253  RCP<UserInputForTests> uinput;
254 
255  if (inputFile != ""){ // Input file specified; read a matrix
256  uinput = rcp(new UserInputForTests(testDataFilePath, inputFile, comm, true));
257  }
258  else // Let Galeri generate a matrix
259 
260  uinput = rcp(new UserInputForTests(xdim, ydim, zdim, matrixType, comm, true, true));
261 
262  RCP<SparseMatrix> Matrix = uinput->getUITpetraCrsMatrix();
263 
264  if (me == 0)
265  std::cout << "NumRows = " << Matrix->getGlobalNumRows() << std::endl
266  << "NumNonzeros = " << Matrix->getGlobalNumEntries() << std::endl
267  << "NumProcs = " << comm->getSize() << std::endl;
268  if(prepartition_rows || prepartition_nonzeros){
269  std::cout<<comm->getRank() <<": Starting to pre-partition, creating adapter\n";
270  //compute new partition of matrix
271  std::unique_ptr<SparseMatrixAdapter> zadapter;
272  if(prepartition_nonzeros){
273  zadapter = std::unique_ptr<SparseMatrixAdapter>(new SparseMatrixAdapter(Matrix, 1));
274  zadapter->setRowWeightIsNumberOfNonZeros(0);
275  } else {
276  zadapter = std::unique_ptr<SparseMatrixAdapter>(new SparseMatrixAdapter(Matrix));
277  }
278 
279  std::cout<<comm->getRank()<<": created adapter, creating PartitioningProblem\n";
280  Teuchos::ParameterList zparams;
281  zparams.set("algorithm","parmetis");
282  zparams.set("imbalance_tolerance", 1.05);
283  zparams.set("partitioning_approach","partition");
285  zproblem(zadapter.get(), &zparams);
286  std::cout<<comm->getRank()<<": created PartitioningProblem, starting to solve\n";
287  zproblem.solve();
288  std::cout<<comm->getRank()<<": solved Partitioning Problem\n";
289  //print partition characteristics before and after
290  std::cout<<comm->getRank()<<": applying partition\n";
292  quality_t evalbef(zadapter.get(), &zparams, comm, NULL);
293  if(me == 0){
294  std::cout<<"BEFORE PREPARTITION: Partition statistics:" << std::endl;
295  evalbef.printMetrics(std::cout);
296  }
297 
298  quality_t evalaft(zadapter.get(), &zparams, comm, &zproblem.getSolution());
299  if(me == 0){
300  std::cout<<"AFTER PREPARTITION: Partition statistics:"<<std::endl;
301  evalaft.printMetrics(std::cout);
302  }
303  std::cout<<comm->getRank()<<": done evaluating, migrating matrix to use new partitioning\n";
304  //Migrate matrix to the new partition
305  RCP<SparseMatrix> newMatrix;
306  zadapter->applyPartitioningSolution(*Matrix, newMatrix, zproblem.getSolution());
307 
308  std::cout<<comm->getRank()<<": done applying, replacing old matrix with new one\n";
309  Matrix = newMatrix;
310  std::cout<<comm->getRank()<<": done replacing, finished partitioning\n";
311  }
313  Teuchos::ParameterList params;
314  params.set("color_choice", colorMethod);
315  params.set("color_method", colorAlg);
316  params.set("verbose", verbose);
317  params.set("timing", timing);
318  params.set("serial_threshold",serialThreshold);
319  params.set("recolor_degrees",recolorDegrees);
320 
321  //params.set("balance_colors", balanceColors); // TODO
322 
324  SparseMatrixAdapter adapter(Matrix);
325 
327  try
328  {
329  Zoltan2::ColoringProblem<SparseMatrixAdapter> problem(&adapter, &params);
330  std::cout << "Going to color " << colorAlg << std::endl;
331  problem.solve();
332 
334  size_t checkLength;
335  int *checkColoring = nullptr;
336 
338 
339  std::cout << "Going to get results" << std::endl;
340  // Check that the solution is really a coloring
341  checkLength = soln->getColorsSize();
342  if(checkLength > 0){
343  checkColoring = soln->getColors();
344  localColors = soln->getNumColors();
345  }
346 
347  //count the number of colors used globally
348  Teuchos::reduceAll<int,int>(*comm, Teuchos::REDUCE_MAX, 1, &localColors, &totalColors);
349  if (outputFile != "") {
350  std::ofstream colorFile;
351 
352  // Write coloring to file,
353  // each process writes local coloring to a separate file
354  //std::string fname = outputFile + "." + me;
355  std::stringstream fname;
356  fname << outputFile << "." << comm->getSize() << "." << me;
357  colorFile.open(fname.str().c_str());
358  for (size_t i=0; i<checkLength; i++){
359  colorFile << " " << checkColoring[i] << std::endl;
360  }
361  colorFile.close();
362  }
363 
364  // Print # of colors on each proc.
365  std::cout << "No. of colors on proc " << me << " : " << localColors << std::endl;
366 
367  std::cout << "Going to validate the soln" << std::endl;
368  auto rowInds = Matrix->getRowMap()->getMyGlobalIndices();
369  Matrix->resumeFill();
370 
371  //We use a squared matrix to validated distance-2 colorings.
372  //If any diagonals are present in the input matrix before we
373  //square the matrix, the resultant matrix may have both distance-1
374  //and distance-2 paths. By removing the diagonals before squaring,
375  //we ensure that our distance-2 validation only checks distance-2
376  //paths. This makes it suitable for validating partial distance-2 colorings.
377 
378  std::cout<<"Got row indices, replacing diagonals\n";
379  //loop through all rows
380  for(size_t i = 0; i < rowInds.size(); i++){
381  typename Kokkos::View<zgno_t*>::HostMirror idx("idx",1);
382  typename Kokkos::View<zscalar_t*>::HostMirror val("val",1);
383  Kokkos::deep_copy(idx,rowInds[i]);
384  Kokkos::deep_copy(val, 0.);
385  //get the entries in the current row
386  size_t numEntries = Matrix->getNumEntriesInGlobalRow(rowInds[i]);
387  typename tcrsMatrix_t::nonconst_global_inds_host_view_type inds("Indices", numEntries);
388  typename tcrsMatrix_t::nonconst_values_host_view_type vals("Values", numEntries);
389  Matrix->getGlobalRowCopy(rowInds[i], inds, vals, numEntries);
390  //check to see if this row has a diagonal
391  bool hasDiagonal = false;
392  for(size_t j = 0; j < inds.extent(0); j++){
393  if(inds[j] == rowInds[i]) hasDiagonal = true;
394  }
395  //replace the diagonal if it exists.
396  if(hasDiagonal) {
397  if(Matrix->replaceGlobalValues(rowInds[i],idx,val) == Teuchos::OrdinalTraits<zlno_t>::invalid()){
398  std::cout<<"Either !isFillActive() or inds.extent != vals.extent()\n";
399  }
400  //else {
401  // std::cout<<"*******DIAGONAL REPLACED*********\n";
402  //}
403  }
404  }
405  Matrix->fillComplete();
406  // Verify that checkColoring is a coloring
407  if(colorAlg == "D2"){
408  testReturn = validateDistributedColoring(Matrix,checkColoring);
409  testReturn += validateDistributedDistance2Coloring(Matrix, checkColoring);
410  } else if (colorAlg == "PD2"){
411  testReturn = validateDistributedDistance2Coloring(Matrix, checkColoring);
412  }else if(colorAlg == "D1-2GL" || colorAlg == "D1"){
413  testReturn = validateDistributedColoring(Matrix, checkColoring);
414  } else if (checkLength > 0){
415  testReturn = validateColoring(Matrix, checkColoring);
416  }
417 
418  // Check balance (not part of pass/fail for now)
419  if(checkLength > 0) checkBalance((zlno_t)checkLength, checkColoring);
420 
421  } catch (std::exception &e){
422  std::cout << "Exception caught in coloring" << std::endl;
423  std::cout << e.what() << std::endl;
424  std::cout << "FAIL" << std::endl;
425  return 0;
426  }
427 
428  int numGlobalConflicts = 0;
429  Teuchos::reduceAll<int, int>(*comm, Teuchos::REDUCE_MAX, 1, &testReturn, &numGlobalConflicts);
430 
431  if (me == 0) {
432  if (numGlobalConflicts > 0){
433  std::cout <<"Number of conflicts found = "<<numGlobalConflicts<<std::endl;
434  std::cout << "Solution is not a valid coloring; FAIL" << std::endl;
435  }else{
436  std::cout << "Used " <<totalColors<<" colors\n";
437  std::cout << "PASS" << std::endl;
438  }
439  }
440 
441 }
442 
zgno_t z2TestGO
Definition: coloring1.cpp:41
int * getColors()
Get (local) color array by raw pointer (no RCP).
ColoringProblem sets up coloring problems for the user.
Defines the ColoringProblem class.
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
void solve(bool updateInputData=true)
Direct the problem to create a solution.
Tpetra::Import< z2TestLO, z2TestGO > Import
Definition: coloring1.cpp:48
ColoringSolution< Adapter > * getSolution()
Get the solution to the problem.
int getNumColors()
Get local number of colors. This is computed from the coloring each time, as this is cheap...
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t
int main(int narg, char **arg)
Definition: coloring1.cpp:164
common code used by tests
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > Vector
Definition: coloring1.cpp:45
list fname
Begin.
Definition: validXML.py:19
Defines the XpetraCrsMatrixAdapter class.
int validateColoring(RCP< SparseMatrix > A, int *color)
Definition: coloring1.cpp:52
int validateDistributedColoring(RCP< SparseMatrix > A, int *color)
Definition: coloring1.cpp:76
Tpetra::Map::local_ordinal_type zlno_t
PartitioningProblem sets up partitioning problems for the user.
int validateDistributedDistance2Coloring(RCP< SparseMatrix > A, int *color)
Definition: coloring1.cpp:112
Zoltan2::XpetraCrsMatrixAdapter< SparseMatrix > SparseMatrixAdapter
Definition: coloring1.cpp:50
A class that computes and returns quality metrics.
zscalar_t z2TestScalar
Definition: coloring1.cpp:42
float zscalar_t
size_t getColorsSize()
Get (local) size of color array.
Tpetra::Map::global_ordinal_type zgno_t
void solve(bool updateInputData=true)
Direct the problem to create a solution.
Vector::node_type Node
Definition: coloring1.cpp:46
The class containing coloring solution.
int checkBalance(zlno_t n, int *color)
Definition: coloring1.cpp:125
std::string testDataFilePath(".")