Zoltan2
Loading...
Searching...
No Matches
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>
23
24using 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
43
44typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
45typedef Tpetra::Vector<z2TestScalar, z2TestLO, z2TestGO> Vector;
46typedef Vector::node_type Node;
47
48typedef Tpetra::Import<z2TestLO, z2TestGO> Import;
49
51
52int 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
76int 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
112int 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
125int 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
164int 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*>::host_mirror_type idx("idx",1);
382 typename Kokkos::View<zscalar_t*>::host_mirror_type 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
Defines the ColoringProblem class.
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 the XpetraCrsMatrixAdapter class.
int main()
ColoringProblem sets up coloring problems for the user.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
ColoringSolution< Adapter > * getSolution()
Get the solution to the problem.
The class containing coloring solution.
int * getColors()
Get (local) color array by raw pointer (no RCP).
size_t getColorsSize()
Get (local) size of color array.
int getNumColors()
Get local number of colors. This is computed from the coloring each time, as this is cheap.
A class that computes and returns quality metrics.
void printMetrics(std::ostream &os) const
Print all metrics.
PartitioningProblem sets up partitioning problems for the user.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
Provides access for Zoltan2 to Xpetra::CrsMatrix data.
size_t getLocalNumRows() const
Returns the number of rows on this process.
Vector::node_type Node
Definition coloring1.cpp:46
zlno_t z2TestLO
Definition coloring1.cpp:40
Tpetra::Import< z2TestLO, z2TestGO > Import
Definition coloring1.cpp:48
int validateDistributedDistance2Coloring(RCP< SparseMatrix > A, int *color)
int validateDistributedColoring(RCP< SparseMatrix > A, int *color)
Definition coloring1.cpp:76
Tpetra::CrsMatrix< z2TestScalar, z2TestLO, z2TestGO > SparseMatrix
Definition coloring1.cpp:44
Zoltan2::XpetraCrsMatrixAdapter< SparseMatrix > SparseMatrixAdapter
Definition coloring1.cpp:50
Tpetra::Vector< z2TestScalar, z2TestLO, z2TestGO > Vector
Definition coloring1.cpp:45
zgno_t z2TestGO
Definition coloring1.cpp:41
int validateColoring(RCP< SparseMatrix > A, int *color)
Definition coloring1.cpp:52
zscalar_t z2TestScalar
Definition coloring1.cpp:42
int checkBalance(zlno_t n, int *color)
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t