schwz  Generated automatically from develop
partition_tools.hpp (5a15602)
1 /*******************************<SCHWARZ LIB LICENSE>***********************
2 Copyright (c) 2019, the SCHWARZ LIB authors
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ******************************<SCHWARZ LIB LICENSE>*************************/
32 
33 #ifndef partition_tools_hpp
34 #define partition_tools_hpp
35 
36 
37 #include <memory>
38 #include <vector>
39 
40 #if SCHW_HAVE_METIS
41 #include <metis.h>
42 #endif
43 
44 
45 #include <ginkgo/ginkgo.hpp>
46 #include <settings.hpp>
47 
48 
49 namespace schwz {
55 namespace PartitionTools {
56 
57 
58 template <typename ValueType, typename IndexType>
59 void PartitionRegular(
60  const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>>
61  &global_matrix,
62  const unsigned int &n_partitions,
63  std::vector<unsigned int> &partition_indices)
64 {
65  // TODO: Move the regular partitioning here from initialization
66 }
67 
68 
69 template <typename ValueType, typename IndexType>
70 void PartitionRegular2D(
71  const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>>
72  &global_matrix,
73  bool write_debug_out, const unsigned int &n_partitions,
74  std::vector<unsigned int> &partition_indices)
75 {
76  auto n = global_matrix->get_size()[0];
77  int sq_n = static_cast<int>(std::sqrt(n));
78  int sq_partn = static_cast<int>(std::sqrt(n_partitions));
79  auto offset1 = 0;
80  auto offset2 = 0;
81  int subd = 0;
82  for (auto j1 = 0; j1 < sq_partn; ++j1) {
83  offset2 = j1 * sq_partn * std::pow(sq_n / sq_partn, 2);
84  for (auto j2 = 0; j2 < sq_partn; ++j2) {
85  auto my_id = sq_partn * j1 + j2;
86  offset1 = (j2)*sq_n / sq_partn;
87  for (auto i1 = 0; i1 < sq_n / sq_partn; ++i1) {
88  for (auto i2 = 0; i2 < sq_n / sq_partn; ++i2) {
89  partition_indices[offset2 + offset1 + (i1 * sq_n) + i2] =
90  my_id;
91  }
92  }
93  }
94  }
95 
96  if (write_debug_out) {
97  std::ofstream file;
98  std::string filename = "part_indices.csv";
99  file.open(filename);
100  file << "idx,subd\n";
101  for (auto i = 0; i < partition_indices.size(); ++i) {
102  file << i << "," << partition_indices[i] << "\n";
103  }
104  file.close();
105  }
106 }
107 
108 
109 template <typename ValueType, typename IndexType>
110 void PartitionMetis(
111  const Settings &settings,
112  const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>>
113  &global_matrix,
114  const std::vector<unsigned int> &cell_weights,
115  const unsigned int &n_partitions,
116  std::vector<unsigned int> &partition_indices)
117 {
118 #if SCHW_HAVE_METIS
119  // generate the data structures for
120  // METIS. Note that this is particularly
121  // simple, since METIS wants exactly our
122  // compressed row storage format. we only
123  // have to set up a few auxiliary arrays
124  idx_t n = static_cast<idx_t>(global_matrix->get_size()[0]);
125  idx_t ncon = 1; // number of balancing constraints (should be >0)
126  idx_t nparts =
127  static_cast<idx_t>(n_partitions); // number of subdomains to create
128  idx_t dummy; // the numbers of edges cut by the
129  // resulting partition
130 
131  // We can not partition n items into more than n parts. METIS will
132  // generate non-sensical output (everything is owned by a single
133  // process) and complain with a message (but won't return an error
134  // code!):
135  // ***Cannot bisect a graph with 0 vertices!
136  // ***You are trying to partition a graph into too many parts!
137  nparts = std::min(n, nparts);
138 
139  // use default options for METIS
140  idx_t options[METIS_NOPTIONS];
141  SCHWARZ_ASSERT_NO_METIS_ERRORS(METIS_SetDefaultOptions(options));
142  // options[METIS_OPTION_SEED] = 0;
143  // options[METIS_OPTION_NUMBERING] = 0;
144  if (settings.metis_objtype == "edgecut") {
145  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
146  } else if (settings.metis_objtype == "totalvol") {
147  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
148  }
149 
150  // // one more nuisance: we have to copy our own data to arrays that
151  // store
152  // // signed integers :-(
153  std::vector<idx_t> int_rowstart(n + 1);
154  std::vector<idx_t> int_colnums(global_matrix->get_num_stored_elements());
155  // TODO: need to remove this ? OPT
156  for (auto i = 0; i < n + 1; ++i) {
157  int_rowstart[i] = static_cast<idx_t>(global_matrix->get_row_ptrs()[i]);
158  }
159  for (gko::size_type i = 0; i < global_matrix->get_num_stored_elements();
160  ++i) {
161  int_colnums[i] = static_cast<idx_t>(global_matrix->get_col_idxs()[i]);
162  }
163 
164  std::vector<idx_t> int_partition_indices(global_matrix->get_size()[0]);
165 
166  // Setup cell weighting option
167  std::vector<idx_t> int_cell_weights;
168  if (cell_weights.size() > 0) {
169  SCHWARZ_ASSERT_EQ(cell_weights.size(), global_matrix->get_size()[0]);
170  int_cell_weights.resize(cell_weights.size());
171  std::copy(cell_weights.begin(), cell_weights.end(),
172  int_cell_weights.begin());
173  }
174  // Set a pointer to the optional cell weighting information.
175  // METIS expects a null pointer if there are no weights to be
176  // considered.
177  idx_t *const p_int_cell_weights =
178  (cell_weights.size() > 0 ? int_cell_weights.data() : nullptr);
179 
180 
181  // Use recursive if the number of partitions is less than or equal to 8
182  if (nparts <= 8) {
183  SCHWARZ_ASSERT_NO_METIS_ERRORS(METIS_PartGraphRecursive(
184  &n, &ncon, int_rowstart.data(), int_colnums.data(),
185  // p_int_cell_weights, nullptr, nullptr, &nparts, nullptr, nullptr,
186  nullptr, nullptr, nullptr, &nparts, nullptr, nullptr, options,
187  &dummy, int_partition_indices.data()));
188  }
189  // Otherwise use kway
190  else {
191  SCHWARZ_ASSERT_NO_METIS_ERRORS(METIS_PartGraphKway(
192  &n, &ncon, int_rowstart.data(), int_colnums.data(),
193  // p_int_cell_weights, nullptr, nullptr, &nparts, nullptr, nullptr,
194  nullptr, nullptr, nullptr, &nparts, nullptr, nullptr, options,
195  &dummy, int_partition_indices.data()));
196  }
197 
198  // now copy back generated indices into the output array
199  std::copy(int_partition_indices.begin(), int_partition_indices.end(),
200  partition_indices.begin());
201 #endif
202 }
203 
204 
205 #define DECLARE_FUNCTION(ValueType, IndexType) \
206  void PartitionMetis( \
207  const Settings &, \
208  const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &, \
209  const std::vector<unsigned int> &, const unsigned int &, \
210  std::vector<unsigned int> &)
211 INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_FUNCTION);
212 #undef DECLARE_FUNCTION
213 
214 #define DECLARE_FUNCTION(ValueType, IndexType) \
215  void PartitionRegular( \
216  const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &, \
217  const unsigned int &, std::vector<unsigned int> &)
218 INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(DECLARE_FUNCTION);
219 #undef DECLARE_FUNCTION
220 
221 } // namespace PartitionTools
222 } // namespace schwz
223 
224 #endif // partition_tool_hpp
std::string metis_objtype
This setting defines the objective type for the metis partitioning.
Definition: settings.hpp:181
The struct that contains the solver settings and the parameters to be set by the user.
Definition: settings.hpp:77
The Schwarz wrappers namespace.
Definition: comm_helpers.hpp:49