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