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
8 class ColorerTest {
9 public:
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 
205 private:
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 
224  Tpetra::global_size_t dummy =
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 
239 int 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