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