Reference documentation for deal.II version 8.5.1
graph_coloring.h
1 
2 // ---------------------------------------------------------------------
3 //
4 // Copyright (C) 2013 - 2016 by the deal.II authors
5 //
6 // This file is part of the deal.II library.
7 //
8 // The deal.II library is free software; you can use it, redistribute
9 // it, and/or modify it under the terms of the GNU Lesser General
10 // Public License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 // The full text of the license can be found in the file LICENSE at
13 // the top level of the deal.II distribution.
14 //
15 // ---------------------------------------------------------------------
16 
17 #ifndef dealii__graph_coloring_h
18 #define dealii__graph_coloring_h
19 
20 
21 #include <deal.II/base/config.h>
22 #include <deal.II/base/thread_management.h>
23 #include <deal.II/base/std_cxx11/function.h>
24 #include <boost/unordered_map.hpp>
25 #include <boost/unordered_set.hpp>
26 
27 #include <set>
28 #include <vector>
29 
30 
31 DEAL_II_NAMESPACE_OPEN
32 
36 namespace GraphColoring
37 {
38  namespace internal
39  {
49  inline
50  bool
51  have_nonempty_intersection (const std::vector<types::global_dof_index> &indices1,
52  const std::vector<types::global_dof_index> &indices2)
53  {
54  // we assume that both arrays are sorted, so we can walk
55  // them in lockstep and see if we encounter an index that's
56  // in both arrays. once we reach the end of either array,
57  // we know that there is no intersection
58  std::vector<types::global_dof_index>::const_iterator
59  p = indices1.begin(),
60  q = indices2.begin();
61  while ((p != indices1.end()) && (q != indices2.end()))
62  {
63  if (*p < *q)
64  ++p;
65  else if (*p > *q)
66  ++q;
67  else
68  // conflict found!
69  return true;
70  }
71 
72  // no conflict found!
73  return false;
74  }
75 
76 
107  template <typename Iterator>
108  std::vector<std::vector<Iterator> >
109  create_partitioning(const Iterator &begin,
110  const typename identity<Iterator>::type &end,
111  const std_cxx11::function<std::vector<types::global_dof_index> (const Iterator &)> &get_conflict_indices)
112  {
113  // Number of iterators.
114  unsigned int n_iterators = 0;
115 
116  // Create a map from conflict indices to iterators
117  boost::unordered_map<types::global_dof_index,std::vector<Iterator> > indices_to_iterators;
118  for (Iterator it=begin; it!=end; ++it)
119  {
120  const std::vector<types::global_dof_index> conflict_indices = get_conflict_indices(it);
121  const unsigned int n_conflict_indices = conflict_indices.size();
122  for (unsigned int i=0; i<n_conflict_indices; ++i)
123  indices_to_iterators[conflict_indices[i]].push_back(it);
124  ++n_iterators;
125  }
126 
127  // create the very first zone which contains only the first
128  // iterator. then create the other zones. keep track of all the
129  // iterators that have already been assigned to a zone
130  std::vector<std::vector<Iterator> > zones(1,std::vector<Iterator> (1,begin));
131  std::set<Iterator> used_it;
132  used_it.insert(begin);
133  while (used_it.size()!=n_iterators)
134  {
135  // loop over the elements of the previous zone. for each element of
136  // the previous zone, get the conflict indices and from there get
137  // those iterators that are conflicting with the current element
138  typename std::vector<Iterator>::iterator previous_zone_it(zones.back().begin());
139  typename std::vector<Iterator>::iterator previous_zone_end(zones.back().end());
140  std::vector<Iterator> new_zone;
141  for (; previous_zone_it!=previous_zone_end; ++previous_zone_it)
142  {
143  const std::vector<types::global_dof_index>
144  conflict_indices = get_conflict_indices(*previous_zone_it);
145 
146  const unsigned int n_conflict_indices(conflict_indices.size());
147  for (unsigned int i=0; i<n_conflict_indices; ++i)
148  {
149  const std::vector<Iterator> &conflicting_elements
150  = indices_to_iterators[conflict_indices[i]];
151  for (unsigned int j=0; j<conflicting_elements.size(); ++j)
152  {
153  // check that the iterator conflicting with the current one is not
154  // associated to a zone yet and if so, assign it to the current
155  // zone. mark it as used
156  //
157  // we can shortcut this test if the conflicting iterator is the
158  // current iterator
159  if ((conflicting_elements[j] != *previous_zone_it)
160  &&
161  (used_it.count(conflicting_elements[j])==0))
162  {
163  new_zone.push_back(conflicting_elements[j]);
164  used_it.insert(conflicting_elements[j]);
165  }
166  }
167  }
168  }
169 
170  // If there are iterators in the new zone, then the zone is added to the
171  // partition. Otherwise, the graph is disconnected and we need to find
172  // an iterator on the other part of the graph. start the whole process again
173  // with the first iterator that hasn't been assigned to a zone yet
174  if (new_zone.size()!=0)
175  zones.push_back(new_zone);
176  else
177  for (Iterator it=begin; it!=end; ++it)
178  if (used_it.count(it)==0)
179  {
180  zones.push_back(std::vector<Iterator> (1,it));
181  used_it.insert(it);
182  break;
183  }
184  }
185 
186  return zones;
187  }
188 
189 
190 
210  template <typename Iterator>
211  void
212  make_dsatur_coloring(std::vector<Iterator> &partition,
213  const std_cxx11::function<std::vector<types::global_dof_index> (const Iterator &)> &get_conflict_indices,
214  std::vector<std::vector<Iterator> > &partition_coloring)
215  {
216  partition_coloring.clear ();
217 
218  // Number of zones composing the partitioning.
219  const unsigned int partition_size(partition.size());
220  std::vector<unsigned int> sorted_vertices(partition_size);
221  std::vector<int> degrees(partition_size);
222  std::vector<std::vector<types::global_dof_index> > conflict_indices(partition_size);
223  std::vector<std::vector<unsigned int> > graph(partition_size);
224 
225  // Get the conflict indices associated to each iterator. The conflict_indices have to
226  // be sorted so we can more easily find conflicts later on
227  for (unsigned int i=0; i<partition_size; ++i)
228  {
229  conflict_indices[i] = get_conflict_indices(partition[i]);
230  std::sort(conflict_indices[i].begin(), conflict_indices[i].end());
231  }
232 
233  // Compute the degree of each vertex of the graph using the
234  // intersection of the conflict indices.
235  for (unsigned int i=0; i<partition_size; ++i)
236  for (unsigned int j=i+1; j<partition_size; ++j)
237  // If the two iterators share indices then we increase the degree of the
238  // vertices and create an ''edge'' in the graph.
239  if (have_nonempty_intersection (conflict_indices[i], conflict_indices[j]))
240  {
241  ++degrees[i];
242  ++degrees[j];
243  graph[i].push_back(j);
244  graph[j].push_back(i);
245  }
246 
247  // Sort the vertices by decreasing degree.
248  std::vector<int>::iterator degrees_it;
249  for (unsigned int i=0; i<partition_size; ++i)
250  {
251  // Find the largest element.
252  degrees_it = std::max_element(degrees.begin(),degrees.end());
253  sorted_vertices[i] = degrees_it-degrees.begin();
254  // Put the largest element to -1 so it cannot be chosen again.
255  *degrees_it = -1;
256  }
257 
258  // Color the graph.
259  std::vector<boost::unordered_set<unsigned int> > colors_used;
260  for (unsigned int i=0; i<partition_size; ++i)
261  {
262  const unsigned int current_vertex(sorted_vertices[i]);
263  bool new_color(true);
264  // Try to use an existing color, i.e., try to find a color which is not
265  // associated to one of the vertices linked to current_vertex.
266  // Loop over the color.
267  for (unsigned int j=0; j<partition_coloring.size(); ++j)
268  {
269  // Loop on the vertices linked to current_vertex. If one vertex linked
270  // to current_vertex is already using the color j, this color cannot
271  // be used anymore.
272  bool unused_color(true);
273  for (unsigned int k=0; k<graph[current_vertex].size(); ++k)
274  if (colors_used[j].count(graph[current_vertex][k])==1)
275  {
276  unused_color = false;
277  break;
278  }
279  if (unused_color)
280  {
281  partition_coloring[j].push_back(partition[current_vertex]);
282  colors_used[j].insert(current_vertex);
283  new_color = false;
284  break;
285  }
286  }
287  // Add a new color.
288  if (new_color)
289  {
290  partition_coloring.push_back(std::vector<Iterator> (1,
291  partition[current_vertex]));
292  boost::unordered_set<unsigned int> tmp;
293  tmp.insert(current_vertex);
294  colors_used.push_back(tmp);
295  }
296  }
297  }
298 
299 
300 
310  template <typename Iterator>
311  std::vector<std::vector<Iterator> >
312  gather_colors(const std::vector<std::vector<std::vector<Iterator> > > &partition_coloring)
313  {
314  std::vector<std::vector<Iterator> > coloring;
315 
316  // Count the number of iterators in each color.
317  const unsigned int partition_size(partition_coloring.size());
318  std::vector<std::vector<unsigned int> > colors_counter(partition_size);
319  for (unsigned int i=0; i<partition_size; ++i)
320  {
321  const unsigned int n_colors(partition_coloring[i].size());
322  colors_counter[i].resize(n_colors);
323  for (unsigned int j=0; j<n_colors; ++j)
324  colors_counter[i][j] = partition_coloring[i][j].size();
325  }
326 
327  // Find the partition with the largest number of colors for the even partition.
328  unsigned int i_color(0);
329  unsigned int max_even_n_colors(0);
330  const unsigned int colors_size(colors_counter.size());
331  for (unsigned int i=0; i<colors_size; i+=2)
332  {
333  if (max_even_n_colors<colors_counter[i].size())
334  {
335  max_even_n_colors = colors_counter[i].size();
336  i_color = i;
337  }
338  }
339  coloring.resize(max_even_n_colors);
340  for (unsigned int j=0; j<colors_counter[i_color].size(); ++j)
341  coloring[j] = partition_coloring[i_color][j];
342 
343  for (unsigned int i=0; i<partition_size; i+=2)
344  {
345  if (i!=i_color)
346  {
347  boost::unordered_set<unsigned int> used_k;
348  for (unsigned int j=0; j<colors_counter[i].size(); ++j)
349  {
350  // Find the color in the current partition with the largest number of
351  // iterators.
352  std::vector<unsigned int>::iterator it;
353  it = std::max_element(colors_counter[i].begin(),colors_counter[i].end());
354  unsigned int min_iterators (static_cast<unsigned int>(-1));
355  unsigned int pos(0);
356  // Find the color of coloring with the least number of colors among
357  // the colors that have not been used yet.
358  for (unsigned int k=0; k<max_even_n_colors; ++k)
359  if (used_k.count(k)==0)
360  if (colors_counter[i_color][k]<min_iterators)
361  {
362  min_iterators = colors_counter[i_color][k];
363  pos = k;
364  }
365  colors_counter[i_color][pos] += *it;
366  // Concatenate the current color with the existing coloring.
367  coloring[pos].insert(coloring[pos].end(),
368  partition_coloring[i][it-colors_counter[i].begin()].begin(),
369  partition_coloring[i][it-colors_counter[i].begin()].end());
370  used_k.insert(pos);
371  // Put the number of iterators to the current color to zero.
372  *it = 0;
373  }
374  }
375  }
376 
377  // If there is more than one partition, do the same thing that we did for the even partitions
378  // to the odd partitions
379  if (partition_size>1)
380  {
381  unsigned int max_odd_n_colors(0);
382  for (unsigned int i=1; i<partition_size; i+=2)
383  {
384  if (max_odd_n_colors<colors_counter[i].size())
385  {
386  max_odd_n_colors = colors_counter[i].size();
387  i_color = i;
388  }
389  }
390  coloring.resize(max_even_n_colors+max_odd_n_colors);
391  for (unsigned int j=0; j<colors_counter[i_color].size(); ++j)
392  coloring[max_even_n_colors+j] = partition_coloring[i_color][j];
393 
394  for (unsigned int i=1; i<partition_size; i+=2)
395  {
396  if (i!=i_color)
397  {
398  boost::unordered_set<unsigned int> used_k;
399  for (unsigned int j=0; j<colors_counter[i].size(); ++j)
400  {
401  // Find the color in the current partition with the largest number of
402  // iterators.
403  std::vector<unsigned int>::iterator it;
404  it = std::max_element(colors_counter[i].begin(),colors_counter[i].end());
405  unsigned int min_iterators(static_cast<unsigned int>(-1));
406  unsigned int pos(0);
407  // Find the color of coloring with the least number of colors among
408  // the colors that have not been used yet.
409  for (unsigned int k=0; k<max_odd_n_colors; ++k)
410  if (used_k.count(k)==0)
411  if (colors_counter[i_color][k]<min_iterators)
412  {
413  min_iterators = colors_counter[i_color][k];
414  pos = k;
415  }
416  colors_counter[i_color][pos] += *it;
417  // Concatenate the current color with the existing coloring.
418  coloring[max_even_n_colors+pos].insert(coloring[max_even_n_colors+pos].end(),
419  partition_coloring[i][it-colors_counter[i].begin()].begin(),
420  partition_coloring[i][it-colors_counter[i].begin()].end());
421  used_k.insert(pos);
422  // Put the number of iterators to the current color to zero.
423  *it = 0;
424  }
425  }
426  }
427  }
428 
429  return coloring;
430  }
431  }
432 
433 
513  template <typename Iterator>
514  std::vector<std::vector<Iterator> >
515  make_graph_coloring(const Iterator &begin,
516  const typename identity<Iterator>::type &end,
517  const std_cxx11::function<std::vector<types::global_dof_index> (const typename identity<Iterator>::type &)> &get_conflict_indices)
518  {
519  Assert (begin != end, ExcMessage ("GraphColoring is not prepared to deal with empty ranges!"));
520 
521  // Create the partitioning.
522  std::vector<std::vector<Iterator> >
523  partitioning = internal::create_partitioning (begin,
524  end,
525  get_conflict_indices);
526 
527  // Color the iterators within each partition.
528  // Run the coloring algorithm on each zone in parallel
529  const unsigned int partitioning_size(partitioning.size());
530  std::vector<std::vector<std::vector<Iterator> > >
531  partition_coloring(partitioning_size);
532 
533  Threads::TaskGroup<> tasks;
534  for (unsigned int i=0; i<partitioning_size; ++i)
535  tasks += Threads::new_task (&internal::make_dsatur_coloring<Iterator>,
536  partitioning[i],
537  get_conflict_indices,
538  partition_coloring[i]);
539  tasks.join_all();
540 
541  // Gather the colors together.
542  return internal::gather_colors(partition_coloring);
543  }
544 
545 } // End graph_coloring namespace
546 
547 DEAL_II_NAMESPACE_CLOSE
548 
549 
550 //---------------------------- graph_coloring.h ---------------------------
551 // end of #ifndef dealii__graph_coloring_h
552 #endif
553 //---------------------------- graph_coloring.h ---------------------------
std::vector< std::vector< Iterator > > make_graph_coloring(const Iterator &begin, const typename identity< Iterator >::type &end, const std_cxx11::function< std::vector< types::global_dof_index >(const typename identity< Iterator >::type &)> &get_conflict_indices)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:313
Task< RT > new_task(const std_cxx11::function< RT()> &function)