376 |
ira |
1 |
#!/usr/bin/env python
|
|
|
2 |
|
|
|
3 |
__author__ = "Ira W. Snyder (devel@irasnyder.com)"
|
|
|
4 |
__copyright__ = "Copyright (c) 2006 Ira W. Snyder (devel@irasnyder.com)"
|
|
|
5 |
__license__ = "GNU GPL v2 (or, at your option, any later version)"
|
|
|
6 |
|
379 |
ira |
7 |
class Edge (object):
|
|
|
8 |
def __init__ (self, color='black', label=''):
|
|
|
9 |
self.color = color
|
|
|
10 |
self.label = label
|
|
|
11 |
|
376 |
ira |
12 |
class Graph:
|
|
|
13 |
"""Class that will handle weighted, undirected graphs. It can have
|
|
|
14 |
arbitrary data stored at each vertex. Note that the simple way
|
|
|
15 |
of creating a graph does not allow you to assign data, you must
|
|
|
16 |
do it manually."""
|
|
|
17 |
|
|
|
18 |
def __init__ (self, vertices=[], edges=[]):
|
|
|
19 |
"""Constructor"""
|
|
|
20 |
self.vertices = {}
|
|
|
21 |
self.edges = {}
|
|
|
22 |
|
|
|
23 |
for v in vertices:
|
|
|
24 |
self.add_vertex (v)
|
|
|
25 |
|
|
|
26 |
for e in edges:
|
|
|
27 |
(v1, v2) = e
|
|
|
28 |
self.add_edge (v1, v2)
|
|
|
29 |
|
|
|
30 |
def __get_key (self, v1, v2):
|
|
|
31 |
"""Create a key for this set of nodes"""
|
|
|
32 |
key = [v1, v2]
|
|
|
33 |
key.sort ()
|
|
|
34 |
return tuple (key)
|
|
|
35 |
|
|
|
36 |
def add_vertex (self, label, data=0):
|
|
|
37 |
"""Add a vertex to the graph"""
|
|
|
38 |
if self.has_vertex (label):
|
|
|
39 |
raise ValueError
|
|
|
40 |
|
|
|
41 |
# Create vertex and set the value
|
379 |
ira |
42 |
self.set_vertex_value (label, data)
|
376 |
ira |
43 |
|
379 |
ira |
44 |
def add_edge (self, v1, v2, color='black', label=''):
|
376 |
ira |
45 |
"""Add an edge from v1 to v2 (undirected)"""
|
|
|
46 |
|
|
|
47 |
key = self.__get_key (v1, v2)
|
|
|
48 |
|
|
|
49 |
if self.has_vertex (v1) and self.has_vertex (v2):
|
379 |
ira |
50 |
self.edges[key] = Edge (color, label)
|
376 |
ira |
51 |
else:
|
|
|
52 |
raise ValueError
|
|
|
53 |
|
|
|
54 |
def has_edge (self, v1, v2):
|
|
|
55 |
"""Check if an edge exists in this graph"""
|
|
|
56 |
|
|
|
57 |
key = self.__get_key (v1, v2)
|
|
|
58 |
|
|
|
59 |
if key in self.edges.keys():
|
|
|
60 |
return True
|
|
|
61 |
|
|
|
62 |
return False
|
|
|
63 |
|
|
|
64 |
def has_vertex (self, label):
|
|
|
65 |
"""Check if a vertex exists in this graph"""
|
|
|
66 |
return label in self.vertices.keys ()
|
|
|
67 |
|
|
|
68 |
def get_children (self, v):
|
|
|
69 |
"""Get a list of all children of v. In this graph, that
|
|
|
70 |
means any adjacent nodes."""
|
|
|
71 |
children = set()
|
|
|
72 |
|
|
|
73 |
# Check that the vertex exists
|
|
|
74 |
if not self.has_vertex (v):
|
|
|
75 |
raise ValueError
|
|
|
76 |
|
|
|
77 |
for k in self.edges.keys ():
|
|
|
78 |
if v in k:
|
|
|
79 |
for i in k:
|
|
|
80 |
if i != v:
|
|
|
81 |
children.add (i)
|
|
|
82 |
|
|
|
83 |
return list(children)
|
|
|
84 |
|
379 |
ira |
85 |
def set_vertex_value (self, v, data):
|
376 |
ira |
86 |
"""Store some data at a vertex"""
|
|
|
87 |
self.vertices[v] = data
|
|
|
88 |
|
379 |
ira |
89 |
def get_vertex_value (self, v):
|
376 |
ira |
90 |
"""Get the data at a vertex"""
|
|
|
91 |
return self.vertices[v]
|
|
|
92 |
|
379 |
ira |
93 |
def set_edge_color (self, v1, v2, color):
|
|
|
94 |
if not self.has_edge (v1, v2):
|
|
|
95 |
raise ValueError
|
376 |
ira |
96 |
|
379 |
ira |
97 |
key = self.__get_key (v1, v2)
|
|
|
98 |
self.edges[key].color = color
|
|
|
99 |
|
|
|
100 |
def get_edge_color (self, v1, v2):
|
|
|
101 |
if not self.has_edge (v1, v2):
|
|
|
102 |
raise ValueError
|
|
|
103 |
|
|
|
104 |
key = self.__get_key (v1, v2)
|
|
|
105 |
return self.edges[key].color
|
|
|
106 |
|
|
|
107 |
def get_edge_label (self, v1, v2):
|
|
|
108 |
if not self.has_edge (v1, v2):
|
|
|
109 |
raise ValueError
|
|
|
110 |
|
|
|
111 |
key = self.__get_key (v1, v2)
|
|
|
112 |
return self.edges[key].label
|
|
|
113 |
|
|
|
114 |
def set_edge_label (self, v1, v2, label):
|
|
|
115 |
if not self.has_edge (v1, v2):
|
|
|
116 |
raise ValueError
|
|
|
117 |
|
|
|
118 |
key = self.__get_key (v1, v2)
|
|
|
119 |
self.edges[key].label = label
|
|
|
120 |
|
|
|
121 |
|
376 |
ira |
122 |
################################################################################
|
|
|
123 |
### Tests are below this point ###
|
|
|
124 |
################################################################################
|
|
|
125 |
|
|
|
126 |
|
|
|
127 |
def run_test (graph, vertex, should_be, suite, test_num):
|
|
|
128 |
"""Run a test, check the result. Print the status."""
|
|
|
129 |
c = graph.get_children (vertex)
|
|
|
130 |
c.sort ()
|
|
|
131 |
|
|
|
132 |
if (c != should_be):
|
|
|
133 |
print 'Failed test #%d in suite: %s' % (test_num, suite)
|
|
|
134 |
|
|
|
135 |
def run_tests_1 ():
|
|
|
136 |
"""Run the first set of tests."""
|
|
|
137 |
SUITE = 'Tests 1'
|
|
|
138 |
|
|
|
139 |
vertices = range (11)
|
|
|
140 |
edges = ( [0, 1], [0, 9], [0, 8], [8, 10], [8, 7], [9, 6], [9, 5],
|
|
|
141 |
[6, 7], [1, 4], [1, 3], [1, 2], [2, 0] )
|
|
|
142 |
|
|
|
143 |
g = Graph (vertices, edges)
|
|
|
144 |
|
|
|
145 |
run_test (g, 0, [1, 2, 8, 9], SUITE, 0)
|
|
|
146 |
run_test (g, 1, [0, 2, 3, 4], SUITE, 1)
|
|
|
147 |
run_test (g, 2, [0, 1], SUITE, 2)
|
|
|
148 |
run_test (g, 3, [1], SUITE, 3)
|
|
|
149 |
run_test (g, 4, [1], SUITE, 4)
|
|
|
150 |
run_test (g, 5, [9], SUITE ,5)
|
|
|
151 |
run_test (g, 6, [7, 9], SUITE, 6)
|
|
|
152 |
run_test (g, 7, [6, 8], SUITE, 7)
|
|
|
153 |
run_test (g, 8, [0, 7, 10], SUITE, 8)
|
|
|
154 |
run_test (g, 9, [0, 5, 6], SUITE, 9)
|
|
|
155 |
run_test (g, 10, [8], SUITE, 10)
|
|
|
156 |
|
|
|
157 |
def run_tests_2 ():
|
|
|
158 |
"""Run the second set of tests."""
|
|
|
159 |
SUITE = 'Tests 2'
|
|
|
160 |
|
|
|
161 |
vertices = ['a', 'b', 'c', 'd', 'e']
|
|
|
162 |
edges = ( ['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'a'], ['b', 'c'],
|
|
|
163 |
['b', 'e'], ['e', 'b'], ['e', 'c'], ['e', 'd'],
|
|
|
164 |
['d', 'a'], ['d', 'c'], ['d', 'e'], ['c', 'a'],
|
|
|
165 |
['c', 'b'], ['c', 'd'], ['c', 'e'] )
|
|
|
166 |
|
|
|
167 |
g = Graph (vertices, edges)
|
|
|
168 |
|
|
|
169 |
run_test (g, 'a', ['b', 'c', 'd'], SUITE, 0)
|
|
|
170 |
run_test (g, 'b', ['a', 'c', 'e'], SUITE, 1)
|
|
|
171 |
run_test (g, 'c', ['a', 'b', 'd', 'e'], SUITE, 2)
|
|
|
172 |
run_test (g, 'd', ['a', 'c', 'e'], SUITE, 3)
|
|
|
173 |
run_test (g, 'e', ['b', 'c', 'd'], SUITE, 4)
|
|
|
174 |
|
|
|
175 |
def main ():
|
|
|
176 |
"""Main function."""
|
|
|
177 |
|
|
|
178 |
print 'Running self tests. Any failures will be reported below'
|
|
|
179 |
|
|
|
180 |
run_tests_1 ()
|
|
|
181 |
run_tests_2 ()
|
|
|
182 |
|
|
|
183 |
|
|
|
184 |
if __name__ == '__main__':
|
|
|
185 |
main ()
|
|
|
186 |
|