Zoltan2
TpetraCrsColorer.cpp
Go to the documentation of this file.
1
2#include "Tpetra_Core.hpp"
3#include "Kokkos_Random.hpp"
6
7// Class to test the Colorer utility
9public:
10 using map_t = Tpetra::Map<>;
11 using gno_t = typename map_t::global_ordinal_type;
12 using graph_t = Tpetra::CrsGraph<>;
13 using matrix_t = Tpetra::CrsMatrix<zscalar_t>;
14 using multivector_t = Tpetra::MultiVector<zscalar_t>;
15 using execution_space_t = typename matrix_t::device_type::execution_space;
16
18 // Construct the test:
19 // Read or generate a matrix (JBlock) with default range and domain maps
20 // Construct identical matrix (JCyclic) with cyclic range and domain maps
21
22 ColorerTest(Teuchos::RCP<const Teuchos::Comm<int> > &comm,
23 int narg, char**arg)
24 : symmetric(false)
25 {
26 int me = comm->getRank();
27 int np = comm->getSize();
28
29 // Process command line arguments
30 bool distributeInput = true;
31 std::string filename = "";
32 size_t xdim = 10, ydim = 11, zdim = 12;
33
34 Teuchos::CommandLineProcessor cmdp(false, false);
35 cmdp.setOption("file", &filename,
36 "Name of the Matrix Market file to use");
37 cmdp.setOption("xdim", &xdim,
38 "Number of nodes in x-direction for generated matrix");
39 cmdp.setOption("ydim", &ydim,
40 "Number of nodes in y-direction for generated matrix");
41 cmdp.setOption("zdim", &zdim,
42 "Number of nodes in z-direction for generated matrix");
43 cmdp.setOption("distribute", "no-distribute", &distributeInput,
44 "Should Zoltan2 distribute the matrix as it is read?");
45 cmdp.setOption("symmetric", "non-symmetric", &symmetric,
46 "Is the matrix symmetric?");
47 cmdp.parse(narg, arg);
48
49 // Get and store a matrix
50 if (filename != "") {
51 // Read from a file
52 UserInputForTests uinput(".", filename, comm, true, distributeInput);
53 JBlock = uinput.getUITpetraCrsMatrix();
54 }
55 else {
56 // Generate a matrix
57 UserInputForTests uinput(xdim, ydim, zdim, string("Laplace3D"), comm,
58 true, distributeInput);
59 JBlock = uinput.getUITpetraCrsMatrix();
60 }
61
62 // Build same matrix with cyclic domain and range maps
63 // To make range and domain maps differ for square matrices,
64 // keep some processors empty in the cyclic maps
65
66 size_t nIndices = std::max(JBlock->getGlobalNumCols(),
67 JBlock->getGlobalNumRows());
68 Teuchos::Array<gno_t> indices(nIndices);
69
70 Teuchos::RCP<const map_t> vMapCyclic =
71 getCyclicMap(JBlock->getGlobalNumCols(), indices, np-1, comm);
72 Teuchos::RCP<const map_t> wMapCyclic =
73 getCyclicMap(JBlock->getGlobalNumRows(), indices, np-2, comm);
74
75 // Fill JBlock with random numbers for a better test.
76 JBlock->resumeFill();
77
78 using IST = typename Kokkos::Details::ArithTraits<zscalar_t>::val_type;
79 using pool_type =
80 Kokkos::Random_XorShift64_Pool<execution_space_t>;
81 pool_type rand_pool(static_cast<uint64_t>(me));
82
83 Kokkos::fill_random(JBlock->getLocalMatrixDevice().values, rand_pool,
84 static_cast<IST>(1.), static_cast<IST>(9999.));
85 JBlock->fillComplete();
86
87
88 // Make JCyclic: same matrix with different Domain and Range maps
89 RCP<const graph_t> block_graph = JBlock->getCrsGraph();
90 RCP<graph_t> cyclic_graph = rcp(new graph_t(*block_graph));
91 cyclic_graph->resumeFill();
92 cyclic_graph->fillComplete(vMapCyclic, wMapCyclic);
93 JCyclic = rcp(new matrix_t(cyclic_graph));
94 JCyclic->resumeFill();
95 TEUCHOS_ASSERT(block_graph->getNodeNumRows() == cyclic_graph->getNodeNumRows());
96 {
97 auto val_s = JBlock->getLocalMatrixHost().values;
98 auto val_d = JCyclic->getLocalMatrixHost().values;
99 TEUCHOS_ASSERT(val_s.extent(0) == val_d.extent(0));
100 Kokkos::deep_copy(val_d, val_s);
101 }
102 JCyclic->fillComplete();
103 }
104
106 bool run(const char* testname, Teuchos::ParameterList &params) {
107
108 bool ok = true;
109
110 params.set("symmetric", symmetric);
111
112 // test with default maps
113 ok = buildAndCheckSeedMatrix(testname, params, true);
114
115 // test with cyclic maps
116 ok &= buildAndCheckSeedMatrix(testname, params, false);
117
118 return ok;
119 }
120
123 const char *testname,
124 Teuchos::ParameterList &params,
125 const bool useBlock
126 )
127 {
128 int ierr = 0;
129
130 // Pick matrix depending on useBlock flag
131 Teuchos::RCP<matrix_t> J = (useBlock ? JBlock : JCyclic);
132 int me = J->getRowMap()->getComm()->getRank();
133
134 std::cout << "Running " << testname << " with "
135 << (useBlock ? "Block maps" : "Cyclic maps")
136 << std::endl;
137
138 // Create a colorer
140 colorer.computeColoring(params);
141
142 // Check coloring
143 if (!colorer.checkColoring()) {
144 std::cout << testname << " with "
145 << (useBlock ? "Block maps" : "Cyclic maps")
146 << " FAILED: invalid coloring returned"
147 << std::endl;
148 return false;
149 }
150
151 // Compute seed matrix V -- the application wants this matrix
152 // Dense matrix of 0/1 indicating the compression via coloring
153
154 const int numColors = colorer.getNumColors();
155
156 // Compute the seed matrix; applications want this seed matrix
157
158 multivector_t V(J->getDomainMap(), numColors);
159 colorer.computeSeedMatrix(V);
160
161 // To test the result...
162 // Compute the compressed matrix W
163 multivector_t W(J->getRangeMap(), numColors);
164
165 J->apply(V, W);
166
167 // Reconstruct matrix from compression vector
168 Teuchos::RCP<matrix_t> Jp = rcp(new matrix_t(*J, Teuchos::Copy));
169 Jp->resumeFill();
170 Jp->setAllToScalar(static_cast<zscalar_t>(-1.));
171 Jp->fillComplete();
172
173 colorer.reconstructMatrix(W, *Jp);
174
175 // Check that values of J = values of Jp
176 auto J_local_matrix = J->getLocalMatrixDevice();
177 auto Jp_local_matrix = Jp->getLocalMatrixDevice();
178 const size_t num_local_nz = J->getNodeNumEntries();
179
180 Kokkos::parallel_reduce(
181 "TpetraCrsColorer::testReconstructedMatrix()",
182 Kokkos::RangePolicy<execution_space_t>(0, num_local_nz),
183 KOKKOS_LAMBDA(const size_t nz, int &errorcnt) {
184 if (J_local_matrix.values(nz) != Jp_local_matrix.values(nz)) {
185 printf("Error in nonzero comparison %zu: %g != %g",
186 nz, J_local_matrix.values(nz), Jp_local_matrix.values(nz));
187 errorcnt++;
188 }
189 },
190 ierr);
191
192
193 if (ierr > 0) {
194 if (me == 0) {
195 std::cout << testname << " FAILED with "
196 << (useBlock ? "Block maps" : "Cyclic maps")
197 << std::endl;
198 params.print();
199 }
200 }
201
202 return (ierr == 0);
203 }
204
205private:
206
208 // Return a map that is cyclic (like dealing rows to processors)
209 Teuchos::RCP<const map_t> getCyclicMap(
210 size_t nIndices,
211 Teuchos::Array<gno_t> &indices,
212 int mapNumProc,
213 const Teuchos::RCP<const Teuchos::Comm<int> > &comm)
214 {
215 size_t cnt = 0;
216 int me = comm->getRank();
217 int np = comm->getSize();
218 if (mapNumProc > np) mapNumProc = np; // corner case: bad input
219 if (mapNumProc <= 0) mapNumProc = 1; // corner case: np is too small
220
221 for (size_t i = 0; i < nIndices; i++)
222 if (me == int(i % np)) indices[cnt++] = i;
223
225 Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
226
227 return rcp(new map_t(dummy, indices(0,cnt), 0, comm));
228 }
229
231 // Input matrix -- built in Constructor
232 bool symmetric; // User can specify whether matrix is symmetric
233 Teuchos::RCP<matrix_t> JBlock; // has Trilinos default domain and range maps
234 Teuchos::RCP<matrix_t> JCyclic; // has cyclic domain and range maps
235};
236
237
239int main(int narg, char **arg)
240{
241 Tpetra::ScopeGuard scope(&narg, &arg);
242 Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
243 bool ok = true;
244 int ierr = 0;
245
246 ColorerTest testColorer(comm, narg, arg);
247
248 // Set parameters and compute coloring
249 {
250 Teuchos::ParameterList coloring_params;
251 std::string matrixType = "Jacobian";
252 bool symmetrize = true; // Zoltan's TRANSPOSE symmetrization, if needed
253
254 coloring_params.set("MatrixType", matrixType);
255 coloring_params.set("symmetrize", symmetrize);
256
257 testColorer.run("Test One", coloring_params);
258 if (!ok) ierr++;
259 }
260
261 {
262 Teuchos::ParameterList coloring_params;
263 std::string matrixType = "Jacobian";
264 bool symmetrize = false; // colorer's BIPARTITE symmetrization, if needed
265
266 coloring_params.set("MatrixType", matrixType);
267 coloring_params.set("symmetrize", symmetrize);
268
269 testColorer.run("Test Two", coloring_params);
270 if (!ok) ierr++;
271 }
272
273 {
274 Teuchos::ParameterList coloring_params;
275 std::string matrixType = "Jacobian";
276
277 coloring_params.set("MatrixType", matrixType);
278
279 testColorer.run("Test Three", coloring_params);
280 if (!ok) ierr++;
281 }
282
283 if (ierr == 0)
284 std::cout << "TEST PASSED" << std::endl;
285
286//Through cmake...
287//Test cases -- UserInputForTests can generate Galeri or read files:
288//- tri-diagonal matrix -- can check the number of colors
289//- galeri matrix
290//- read from file: symmetric matrix and non-symmetric matrix
291
292//Through code ...
293//Test with fitted and non-fitted maps
294//Call regular and fitted versions of functions
295
296//Through code ...
297//Test both with and without Symmetrize --
298//test both to exercise both sets of callbacks in Zoltan
299// --matrixType = Jacobian/Hessian
300// --symmetric, --no-symmetric
301// --symmetrize, --no-symmetrize
302
303//Through cmake
304//Test both with and without distributeInput
305// --distribute, --no-distribute
306
307}
int main(int narg, char **arg)
common code used by tests
float zscalar_t
ColorerTest(Teuchos::RCP< const Teuchos::Comm< int > > &comm, int narg, char **arg)
bool run(const char *testname, Teuchos::ParameterList &params)
Tpetra::CrsMatrix< zscalar_t > matrix_t
typename map_t::global_ordinal_type gno_t
bool buildAndCheckSeedMatrix(const char *testname, Teuchos::ParameterList &params, const bool useBlock)
Tpetra::MultiVector< zscalar_t > multivector_t
typename matrix_t::device_type::execution_space execution_space_t
Tpetra::CrsGraph<> graph_t
Tpetra::Map<> map_t
RCP< tcrsMatrix_t > getUITpetraCrsMatrix()
Tpetra::global_size_t global_size_t