iMSTK
Interactive Medical Simulation Toolkit
imstkGraph.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkGraph.h"
8 #include "imstkLogger.h"
9 #include "imstkParallelUtils.h"
10 
11 #include <numeric>
12 #include <iostream>
13 
14 namespace imstk
15 {
16 void
17 Graph::addEdge(const size_t v, const size_t w)
18 {
19  if (v < m_adjList.size() && w < m_adjList.size())
20  {
21  m_adjList[v].insert(w);
22  m_adjList[w].insert(v);
23  }
24  else
25  {
26  LOG(WARNING) << "Vertex id exceeds the graph size: cannot add edge!" << std::endl;
27  }
28 }
29 
30 void
31 Graph::getEdges(const size_t v, edgeType& edges) const
32 {
33  edges = m_adjList[v];
34 }
35 
36 void
37 Graph::print() const
38 {
39  std::cout << "Graph: " << "\nTotal nodes: " << m_adjList.size() << "\nAdjacency:" << std::endl;
40 
41  for (size_t i = 0; i < m_adjList.size(); i++)
42  {
43  std::cout << "\t[" << i << "] : ";
44 
45  for (auto v : m_adjList[i])
46  {
47  std::cout << v << " ";
48  }
49  std::cout << std::endl;
50  }
51 }
52 
53 Graph::graphColorsType
54 Graph::doColoring(ColoringMethod method /*=ColoringMethod::WelshPowell*/, bool print /*= false*/) const
55 {
56  return method == ColoringMethod::WelshPowell ?
57  doColoringWelshPowell(print) :
58  doColoringGreedy(print);
59 }
60 
61 Graph::graphColorsType
62 Graph::doColoringWelshPowell(bool print /*= false*/) const
63 {
64  const auto numNodes = m_adjList.size();
65 
66  using ColorType = unsigned short;
67  const ColorType INVALID = std::numeric_limits<unsigned short>::max();
68  // Must initialize colors to inf number
69  std::vector<ColorType> colors(numNodes, INVALID);
70 
71  // Count the number of neighbors for each node
72  std::vector<size_t> neighborCounts(numNodes);
73  ParallelUtils::parallelFor(numNodes,
74  [&](const size_t idx)
75  {
76  neighborCounts[idx] = m_adjList[idx].size();
77  });
78 
79  std::vector<size_t> coloringOrder(numNodes);
80  std::iota(coloringOrder.begin(), coloringOrder.end(), static_cast<size_t>(0));
81 
82  // Node with largest number of neighbors is processed first
83  tbb::parallel_sort(coloringOrder.begin(), coloringOrder.end(),
84  [&](const size_t idx0, const size_t idx1) {
85  return neighborCounts[idx0] > neighborCounts[idx1];
86  });
87 
88  ColorType color = 0;
89  while (coloringOrder.size() > 0)
90  {
91  colors[coloringOrder[0]] = color;
92 
93  // Cannot run in parallel
94  for (size_t i = 1; i < coloringOrder.size(); ++i)
95  {
96  const auto u = coloringOrder[i];
97  bool bOK = true;
98  for (const auto v : m_adjList[u])
99  {
100  // Check if any neighbor node has the same color as the first processing node
101  if (colors[v] == color)
102  {
103  bOK = false;
104  break;
105  }
106  }
107  if (bOK)
108  {
109  colors[u] = color;
110  }
111  }
112 
113  // Done with the current color
114  ++color;
115 
116  // Remove colorized nodes
117  size_t writeIdx = 0;
118  for (size_t readIdx = 1; readIdx < coloringOrder.size(); ++readIdx)
119  {
120  // if (!coloredNodes[readIdx])
121  if (colors[coloringOrder[readIdx]] == INVALID)
122  {
123  coloringOrder[writeIdx++] = coloringOrder[readIdx];
124  }
125  }
126  coloringOrder.resize(writeIdx);
127  }
128 
129  // print the result
130  if (print)
131  {
132  std::map<size_t, size_t> verticesPerColor;
133  std::cout << "Num. of nodes: " << numNodes << " | Num. of colors: " << color << std::endl;
134  for (size_t i = 0; i < numNodes; ++i)
135  {
136  // std::cout << "V " << i << "-C " << colors[i] << " | " << std::endl;;
137  verticesPerColor[colors[i]]++;
138  }
139  std::cout << std::endl;
140  std::cout << "Vertices per color: " << std::endl;
141  for (const auto& kv : verticesPerColor)
142  {
143  std::cout << "C: " << kv.first << " - " << kv.second << std::endl;
144  }
145  std::cout << std::endl;
146  }
147 
148  return std::make_pair(colors, color);
149 }
150 
151 std::pair<std::vector<unsigned short>, unsigned short>
152 Graph::doColoringGreedy(bool print /*= false*/) const
153 {
154  const auto numNodes = m_adjList.size();
155  std::vector<unsigned short> colors(numNodes, std::numeric_limits<unsigned short>::max());
156  std::vector<bool> available(numNodes, false);
157 
158  colors[0] = 0;
159  unsigned short numColors = 0;
160 
161  // Assign colors to remaining V-1 vertices
162  for (size_t u = 1; u < numNodes; ++u)
163  {
164  // Process all adjacent vertices and flag their colors
165  // as unavailable
166  for (const auto& i : m_adjList[u])
167  {
168  if (colors[i] != std::numeric_limits<unsigned short>::max())
169  {
170  available[colors[i]] = true;
171  }
172  }
173 
174  // Find the first available color
175  unsigned short cr;
176  for (cr = 0; cr < numNodes; cr++)
177  {
178  if (!available[cr])
179  {
180  break;
181  }
182  }
183  colors[u] = cr; // Assign the found color
184  if (cr + 1 > numColors)
185  {
186  numColors = cr + 1;
187  }
188 
189  // Reset the values back to false for the next iteration
190  for (const auto& i : m_adjList[u])
191  {
192  if (colors[i] != std::numeric_limits<unsigned short>::max())
193  {
194  available[colors[i]] = false;
195  }
196  }
197  }
198 
199  // print the result
200  if (print)
201  {
202  std::map<size_t, size_t> verticesPerColor;
203  std::cout << "Num. of nodes: " << numNodes << " | Num. of colors: " << numColors << std::endl;
204  for (size_t i = 0; i < numNodes; ++i)
205  {
206  std::cout << "V " << i << "-C " << colors[i] << " | ";
207  verticesPerColor[colors[i]]++;
208  }
209  std::cout << std::endl;
210  std::cout << "Vertices per color: " << std::endl;
211  for (const auto& kv : verticesPerColor)
212  {
213  std::cout << "C: " << kv.first << " - " << kv.second << std::endl;
214  }
215  std::cout << std::endl;
216  }
217 
218  return std::make_pair(colors, numColors);
219 }
220 } // namespace imstk
void print() const
print adjacency list representation of graph
Definition: imstkGraph.cpp:37
Compound Geometry.
void getEdges(const size_t v, edgeType &edges) const
Get edges surrounding a node.
Definition: imstkGraph.cpp:31
graphColorsType doColoringWelshPowell(bool print=false) const
Colorize using Welsh-Powell algorithm and print the assignment of colors.
Definition: imstkGraph.cpp:62
graphColorsType doColoring(ColoringMethod method=ColoringMethod::WelshPowell, bool print=false) const
Colorize using the given method and prints the assignment of colors.
Definition: imstkGraph.cpp:54
void addEdge(const size_t v, const size_t w)
Add edge to the graph.
Definition: imstkGraph.cpp:17
graphColorsType doColoringGreedy(bool print=false) const
Colorize using greedy algorithm and print the assignment of colors.
Definition: imstkGraph.cpp:152
std::vector< edgeType > m_adjList
A array of std::vectors to represent adjacency list.
Definition: imstkGraph.h:77