1 /******************************************************************************
2
3 This source file is part of the Avogadro project.
4
5 Copyright 2011-2012 Kitware, Inc.
6
7 This source code is released under the New BSD License, (the "License").
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14
15 ******************************************************************************/
16
17 #include "graph.h"
18
19 #include <algorithm>
20 #include <cassert>
21
22 namespace Avogadro {
23 namespace Core {
24
Graph()25 Graph::Graph()
26 {
27 }
28
Graph(size_t n)29 Graph::Graph(size_t n) : m_adjacencyList(n)
30 {
31 }
32
~Graph()33 Graph::~Graph()
34 {
35 }
36
setSize(size_t n)37 void Graph::setSize(size_t n)
38 {
39 // If the graph is being made smaller we first need to remove all of the edges
40 // from the soon to be removed vertices.
41 for (size_t i = n; i < m_adjacencyList.size(); i++)
42 removeEdges(i);
43
44 m_adjacencyList.resize(n);
45 }
46
size() const47 size_t Graph::size() const
48 {
49 return m_adjacencyList.size();
50 }
51
isEmpty() const52 bool Graph::isEmpty() const
53 {
54 return m_adjacencyList.empty();
55 }
56
clear()57 void Graph::clear()
58 {
59 setSize(0);
60 }
61
addVertex()62 size_t Graph::addVertex()
63 {
64 setSize(size() + 1);
65 return size() - 1;
66 }
67
removeVertex(size_t index)68 void Graph::removeVertex(size_t index)
69 {
70 assert(index < size());
71
72 // Remove the edges to the vertex.
73 removeEdges(index);
74
75 // Remove vertex's adjacency list.
76 m_adjacencyList.erase(m_adjacencyList.begin() + index);
77 }
78
vertexCount() const79 size_t Graph::vertexCount() const
80 {
81 return m_adjacencyList.size();
82 }
83
addEdge(size_t a,size_t b)84 void Graph::addEdge(size_t a, size_t b)
85 {
86 assert(a < size());
87 assert(b < size());
88
89 std::vector<size_t>& neighborsA = m_adjacencyList[a];
90 std::vector<size_t>& neighborsB = m_adjacencyList[b];
91
92 // Ensure edge does not exist already.
93 if (std::find(neighborsA.begin(), neighborsA.end(), b) != neighborsA.end())
94 return;
95
96 // Add the edge to each verticies adjacency list.
97 neighborsA.push_back(b);
98 neighborsB.push_back(a);
99 }
100
removeEdge(size_t a,size_t b)101 void Graph::removeEdge(size_t a, size_t b)
102 {
103 assert(a < size());
104 assert(b < size());
105
106 std::vector<size_t>& neighborsA = m_adjacencyList[a];
107 std::vector<size_t>& neighborsB = m_adjacencyList[b];
108
109 std::vector<size_t>::iterator iter =
110 std::find(neighborsA.begin(), neighborsA.end(), b);
111
112 if (iter != neighborsA.end()) {
113 neighborsA.erase(iter);
114 neighborsB.erase(std::find(neighborsB.begin(), neighborsB.end(), a));
115 }
116 }
117
removeEdges()118 void Graph::removeEdges()
119 {
120 for (size_t i = 0; i < m_adjacencyList.size(); ++i)
121 m_adjacencyList[i].clear();
122 }
123
removeEdges(size_t index)124 void Graph::removeEdges(size_t index)
125 {
126 const std::vector<size_t>& nbrs = m_adjacencyList[index];
127
128 for (size_t i = 0; i < nbrs.size(); ++i) {
129 std::vector<size_t>& neighborsList = m_adjacencyList[nbrs[i]];
130
131 // Remove vertex from its neighbors' adjacency list.
132 neighborsList.erase(
133 std::find(neighborsList.begin(), neighborsList.end(), index));
134 }
135 }
136
edgeCount() const137 size_t Graph::edgeCount() const
138 {
139 size_t count = 0;
140
141 for (size_t i = 0; i < size(); ++i)
142 count += neighbors(i).size();
143
144 return count / 2;
145 }
146
neighbors(size_t index) const147 const std::vector<size_t>& Graph::neighbors(size_t index) const
148 {
149 assert(index < size());
150 return m_adjacencyList[index];
151 }
152
degree(size_t index) const153 size_t Graph::degree(size_t index) const
154 {
155 return neighbors(index).size();
156 }
157
containsEdge(size_t a,size_t b) const158 bool Graph::containsEdge(size_t a, size_t b) const
159 {
160 assert(a < size());
161 assert(b < size());
162
163 const std::vector<size_t>& neighborsA = neighbors(a);
164
165 return std::find(neighborsA.begin(), neighborsA.end(), b) != neighborsA.end();
166 }
167
connectedComponents() const168 std::vector<std::vector<size_t>> Graph::connectedComponents() const
169 {
170 std::vector<std::vector<size_t>> components;
171
172 // Position of next vertex to the root of the depth-first search.
173 size_t position = 0;
174
175 // The bitset containing each vertex that has been visited.
176 std::vector<bool> visited(size());
177
178 for (;;) {
179 std::vector<size_t> component(size());
180 std::vector<size_t> row;
181 row.push_back(position);
182
183 while (!row.empty()) {
184 std::vector<size_t> nextRow;
185
186 for (size_t i = 0; i < row.size(); i++) {
187 size_t vertex = row[i];
188
189 // Add vertex to the component.
190 component.push_back(vertex);
191
192 // Mark the vertex as visited.
193 visited[vertex] = true;
194
195 // Iterate through each neighbor.
196 const std::vector<size_t>& nbrs = m_adjacencyList[vertex];
197 for (size_t j = 0; j < nbrs.size(); ++j)
198 if (visited[nbrs[j]] == false)
199 nextRow.push_back(nbrs[j]);
200 }
201 row = nextRow;
202 }
203
204 // Add this component to the list of components.
205 components.push_back(component);
206
207 // Find the next unvisited vertex.
208 bool done = true;
209 for (size_t i = position + 1; i < size(); ++i) {
210 if (visited[i] == false) {
211 position = i;
212 done = false;
213 break;
214 }
215 }
216
217 if (done)
218 break;
219 }
220
221 return components;
222 }
223
224 } // end Core namespace
225 } // end Avogadro namespace
226