Wildmeshing Toolkit
Scheduler.cpp
Go to the documentation of this file.
1 #include "Scheduler.hpp"
2 
5 #include <wmtk/simplex/link.hpp>
7 #include <wmtk/utils/Logger.hpp>
9 
10 #include <polysolve/Utils.hpp>
11 
12 #ifdef __GNUC__
13 #pragma GCC diagnostic push
14 #pragma GCC diagnostic ignored "-Wredundant-decls"
15 #endif
16 #include <tbb/parallel_for.h>
17 #ifdef __GNUC__
18 #pragma GCC diagnostic pop
19 #endif
20 
21 // #include <tbb/task_arena.h>
22 #include <atomic>
23 
24 
25 #include <algorithm>
26 #include <random>
27 
28 namespace wmtk {
29 
30 Scheduler::Scheduler() = default;
31 Scheduler::~Scheduler() = default;
32 
34 {
35  SchedulerStats res;
36  std::vector<simplex::Simplex> simplices;
37  // op.reserve_enough_simplices();
38 
39  const auto type = op.primitive_type();
40  {
41  POLYSOLVE_SCOPED_STOPWATCH("Collecting primitives", res.collecting_time, logger());
42 
43  const auto tups = op.mesh().get_all(type);
44  simplices =
46  }
47 
48  logger().debug("Executing on {} simplices", simplices.size());
49  std::vector<std::pair<int64_t, double>> order;
50 
51  {
52  POLYSOLVE_SCOPED_STOPWATCH("Sorting", res.sorting_time, logger());
53  if (op.use_random_priority()) {
54  std::mt19937 gen(utils::get_random_seed());
55 
56  std::shuffle(simplices.begin(), simplices.end(), gen);
57  } else {
58  order.reserve(simplices.size());
59  for (int64_t i = 0; i < simplices.size(); ++i) {
60  order.emplace_back(i, op.priority(simplices[i]));
61  }
62 
63  std::stable_sort(order.begin(), order.end(), [](const auto& s_a, const auto& s_b) {
64  return s_a.second < s_b.second;
65  });
66  }
67  }
68 
69 
70  {
71  POLYSOLVE_SCOPED_STOPWATCH("Executing operation", res.executing_time, logger());
72 
73  size_t total_simplices = simplices.size();
74 
75  if (op.use_random_priority()) {
76  for (const auto& s : simplices) {
77  log(res, total_simplices);
78  auto mods = op(s);
79  if (mods.empty())
80  res.fail();
81  else
82  res.succeed();
83  }
84  } else {
85  for (const auto& o : order) {
86  log(res, total_simplices);
87  auto mods = op(simplices[o.first]);
88  if (mods.empty())
89  res.fail();
90  else
91  res.succeed();
92  }
93  }
94  if (m_update_frequency) {
95  res.print_update_log(total_simplices);
96  }
97  }
98 
99  // logger().debug(
100  // "Ran {} ops, {} succeeded, {} failed",
101  // res.number_of_performed_operations(),
102  // res.number_of_successful_operations(),
103  // res.number_of_failed_operations());
104 
105  m_stats += res;
106 
107  return res;
108 }
109 
112  const TypedAttributeHandle<char>& flag_handle)
113 {
114  std::vector<simplex::Simplex> simplices;
115  const auto type = op.primitive_type();
116 
117  auto flag_accessor = op.mesh().create_accessor(flag_handle);
118  auto tups = op.mesh().get_all(type);
119 
120  SchedulerStats res;
121  int64_t success = -1;
122  std::vector<std::pair<int64_t, double>> order;
123 
124  for (const auto& t : tups) {
125  flag_accessor.scalar_attribute(t) = char(1);
126  }
127 
128  do {
129  SchedulerStats internal_stats;
130  // op.reserve_enough_simplices();
131 
132  {
133  POLYSOLVE_SCOPED_STOPWATCH(
134  "Collecting primitives",
135  internal_stats.collecting_time,
136  logger());
137 
138  tups = op.mesh().get_all(type);
139  const auto n_primitives = tups.size();
140  tups.erase(
141  std::remove_if(
142  tups.begin(),
143  tups.end(),
144  [&](const Tuple& t) { return flag_accessor.scalar_attribute(t) == char(0); }),
145  tups.end());
146  for (const auto& t : tups) {
147  flag_accessor.scalar_attribute(t) = char(0);
148  }
149 
150  logger().debug("Processing {}/{}", tups.size(), n_primitives);
151 
153  op.mesh(),
154  tups,
155  type);
156  }
157 
158  {
159  POLYSOLVE_SCOPED_STOPWATCH("Sorting", internal_stats.sorting_time, logger());
160  if (op.use_random_priority()) {
161  std::mt19937 gen(utils::get_random_seed());
162 
163  std::shuffle(simplices.begin(), simplices.end(), gen);
164  } else {
165  order.clear();
166  order.reserve(simplices.size());
167  for (int64_t i = 0; i < simplices.size(); ++i) {
168  order.emplace_back(i, op.priority(simplices[i]));
169  }
170 
171  std::stable_sort(order.begin(), order.end(), [](const auto& s_a, const auto& s_b) {
172  return s_a.second < s_b.second;
173  });
174  }
175  }
176 
177  {
178  size_t total_simplices = order.size();
179  POLYSOLVE_SCOPED_STOPWATCH(
180  "Executing operation",
181  internal_stats.executing_time,
182  logger());
183 
184  if (op.use_random_priority()) {
185  for (const auto& s : simplices) {
186  log(internal_stats, total_simplices);
187  auto mods = op(s);
188  // assert(wmtk::multimesh::utils::check_child_maps_valid(op.mesh()));
189  if (mods.empty()) {
190  res.fail();
191  } else {
192  res.succeed();
193  }
194  }
195  } else {
196  for (const auto& o : order) {
197  log(internal_stats, total_simplices);
198  auto mods = op(simplices[o.first]);
199  // assert(wmtk::multimesh::utils::check_child_maps_valid(op.mesh()));
200  if (mods.empty()) {
201  internal_stats.fail();
202  } else {
203  internal_stats.succeed();
204  }
205  }
206  }
207  }
208 
209  success = internal_stats.number_of_successful_operations();
210  res += internal_stats;
211  res.sub_stats.push_back(internal_stats);
212  m_stats += internal_stats;
213  m_stats.sub_stats.push_back(internal_stats);
214  } while (success > 0);
215 
216  // // reset flag to 1, not necessaty
217  // auto tups = op.mesh().get_all(type);
218  // for (const auto& t : tups) {
219  // flag_accessor.scalar_attribute(t) = char(1);
220  // }
221 
222  return res;
223 }
224 
225 int64_t first_available_color(std::vector<int64_t>& used_neighbor_coloring)
226 {
227  if (used_neighbor_coloring.size() == 0) return 0;
228 
229  std::sort(used_neighbor_coloring.begin(), used_neighbor_coloring.end());
230  int64_t color = 0;
231 
232  for (const auto c : used_neighbor_coloring) {
233  if (color < c) {
234  return color;
235  } else {
236  color = c + 1;
237  }
238  }
239  return color;
240 }
241 
244  const TypedAttributeHandle<int64_t>& color_handle)
245 {
246  // this only works on vertex operations
247  SchedulerStats res;
248  std::vector<std::vector<simplex::Simplex>> colored_simplices;
249  // op.reserve_enough_simplices();
250  auto color_accessor = op.mesh().create_accessor<int64_t>(color_handle);
251 
252  const auto type = op.primitive_type();
253  assert(type == PrimitiveType::Vertex);
254 
255  const auto tups = op.mesh().get_all(type);
256  int64_t color_max = -1;
257  {
258  POLYSOLVE_SCOPED_STOPWATCH("Collecting primitives", res.collecting_time, logger());
259 
260 
261  // reset all coloring as -1
262  // TODO: parallelfor
263  // for (const auto& v : tups) {
264  // color_accessor.scalar_attribute(v) = -1;
265  // }
266 
267  tbb::parallel_for(
268  tbb::blocked_range<int64_t>(0, tups.size()),
269  [&](tbb::blocked_range<int64_t> r) {
270  for (int64_t i = r.begin(); i < r.end(); ++i) {
271  color_accessor.scalar_attribute(tups[i]) = -1;
272  }
273  });
274 
275  // greedy coloring
276  std::vector<int64_t> used_colors;
277  for (const auto& v : tups) {
278  // get used colors in neighbors
279  used_colors.clear();
280  for (const auto& v_one_ring :
281  simplex::link(op.mesh(), simplex::Simplex::vertex(op.mesh(), v), false)
283  int64_t color = color_accessor.const_scalar_attribute(v_one_ring.tuple());
284  if (color > -1) {
285  used_colors.push_back(color);
286  }
287  }
288  int64_t c = first_available_color(used_colors);
289  color_accessor.scalar_attribute(v) = c;
290  color_max = std::max(color_max, c);
291 
292  // push into vectors
293  if (c + 1 > colored_simplices.size()) {
294  colored_simplices.push_back({simplex::Simplex::vertex(op.mesh(), v)});
295  } else {
296  colored_simplices[c].push_back(simplex::Simplex::vertex(op.mesh(), v));
297  }
298  }
299 
300  logger().info("Have {} colors among {} vertices", colored_simplices.size(), tups.size());
301 
302  // debug code
303 
304  {
305  for (const auto& v : tups) {
306  auto current_color = color_accessor.const_scalar_attribute(v);
307  if (current_color == -1) {
308  std::cout << "vertex not assigned color!!!" << std::endl;
309  }
310 
311  for (const auto& v_one_ring :
314  if (current_color ==
315  color_accessor.const_scalar_attribute(v_one_ring.tuple())) {
316  std::cout << "adjacent vertices have same color!!!" << std::endl;
317  }
318  }
319  }
320  }
321  }
322 
323  logger().debug("Executing on {} simplices", tups.size());
324 
325  {
326  POLYSOLVE_SCOPED_STOPWATCH("Sorting", res.sorting_time, logger());
327 
328  // do sth or nothing
329  }
330 
331 
332  {
333  POLYSOLVE_SCOPED_STOPWATCH("Executing operation", res.executing_time, logger());
334 
335  std::atomic_int suc_cnt = 0;
336  std::atomic_int fail_cnt = 0;
337 
338  for (int64_t i = 0; i < colored_simplices.size(); ++i) {
339  tbb::parallel_for(
340  tbb::blocked_range<int64_t>(0, colored_simplices[i].size()),
341  [&](tbb::blocked_range<int64_t> r) {
342  for (int64_t k = r.begin(); k < r.end(); ++k) {
343  auto mods = op(colored_simplices[i][k]);
344  if (mods.empty()) {
345  fail_cnt++;
346  } else {
347  suc_cnt++;
348  }
349  }
350  });
351 
352  // for (int64_t k = 0; k < colored_simplices[i].size(); ++k) {
353  // auto mods = op(colored_simplices[i][k]);
354  // if (mods.empty()) {
355  // fail_cnt++;
356  // } else {
357  // suc_cnt++;
358  // }
359  // }
360  }
361 
362  res.m_num_op_success = suc_cnt;
363  res.m_num_op_fail = fail_cnt;
364  }
365 
366  // logger().debug(
367  // "Ran {} ops, {} succeeded, {} failed",
368  // res.number_of_performed_operations(),
369  // res.number_of_successful_operations(),
370  // res.number_of_failed_operations());
371 
372  m_stats += res;
373 
374  return res;
375 }
376 
377 void Scheduler::log(size_t total)
378 {
379  log(m_stats, total);
380 }
381 void Scheduler::log(const SchedulerStats& stats, size_t total)
382 {
383  if (m_update_frequency) {
384  const size_t freq = m_update_frequency.value();
385  size_t count = stats.number_of_performed_operations();
386  if (count % freq == 0) {
387  stats.print_update_log(total);
388  }
389  count++;
390  }
391 }
392 
393 void Scheduler::set_update_frequency(std::optional<size_t>&& freq)
394 {
395  m_update_frequency = std::move(freq);
396 }
397 
398 
399 void SchedulerStats::print_update_log(size_t total, spdlog::level::level_enum level) const
400 {
401  logger().log(
402  level,
403  "{} success + {} fail = {} out of {}",
404  number_of_successful_operations(),
405  number_of_failed_operations(),
406  number_of_performed_operations(),
407  total);
408 }
409 
410 } // namespace wmtk
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition: Mesh.cpp:18
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
void log(const size_t total)
Definition: Scheduler.cpp:377
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition: Scheduler.cpp:33
SchedulerStats run_operation_on_all_coloring(operations::Operation &op, const TypedAttributeHandle< int64_t > &color_handle)
Definition: Scheduler.cpp:242
SchedulerStats m_stats
Definition: Scheduler.hpp:107
std::optional< size_t > m_update_frequency
Definition: Scheduler.hpp:108
std::vector< SchedulerStats > sub_stats
Definition: Scheduler.hpp:52
int64_t number_of_performed_operations() const
Returns the number of performed operations performed by the scheduler.
Definition: Scheduler.hpp:30
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
Definition: Scheduler.hpp:16
void print_update_log(size_t total, spdlog::level::level_enum=spdlog::level::info) const
Definition: Scheduler.cpp:399
Handle that represents attributes for some mesh.
const Mesh & mesh() const
Definition: Operation.hpp:45
virtual PrimitiveType primitive_type() const =0
virtual double priority(const simplex::Simplex &simplex) const
Definition: Operation.hpp:35
virtual bool use_random_priority() const
Definition: Operation.hpp:40
const std::vector< Simplex > & simplex_vector() const
Return const reference to the simplex vector.
static Simplex vertex(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:56
std::vector< Simplex > tuple_vector_to_homogeneous_simplex_vector(const Mesh &m, const std::vector< Tuple > &tups, PrimitiveType primitive)
SimplexCollection link(const Mesh &mesh, const simplex::Simplex &simplex, const bool sort_and_clean)
Definition: link.cpp:84
SimplexCollection k_ring(const Mesh &mesh, const Simplex &simplex, int64_t k)
Definition: k_ring.cpp:6
unsigned int get_random_seed()
Definition: random_seed.hpp:30
Definition: Accessor.hpp:6
spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:58
int64_t first_available_color(std::vector< int64_t > &used_neighbor_coloring)
Definition: Scheduler.cpp:225