-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGraphGenerator.py
More file actions
301 lines (202 loc) · 6.11 KB
/
GraphGenerator.py
File metadata and controls
301 lines (202 loc) · 6.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import operator
import pickle
class GraphGenerator(object):
"""
Generate optimized graphs given a relation defined by an array of floating point values.
The generator produces a graph of as few components as possible with the edges minimized
according to some specified comparison and set of constraints.
"""
def __init__(self):
"""
Initialize the GraphGenerator
input: object to process input array for use in constructing the graph object
constructor: object to convert processed input array into NetworkX graph object
optimizer: object to optimize the graph object
combiner: object to consolidate components of the final graph
output: object to process final graph for output in different formats
"""
self.graph = nx.Graph(state="empty")
self.input = Input()
self.constructor = Constructor(self.graph)
self.optimizer = Optimizer(self.graph)
#self.combiner = Combiner(self.graph)
self.output = Output(self.graph)
#self.comparator = None
# End def __init__
def generateGraph(self, edgeWeightArray, weightLimit):
"""
Generate an optimized graph
"""
#self.comparator = comparator
weightedAdjacencyMatrix = self.input.processInput(edgeWeightArray)
self.constructor.constructGraph(weightedAdjacencyMatrix, weightLimit)
self.optimizer.optimizeComponents()
#self.output
#self.finalGraph = self.combiner.combineComponents(optimizedGraph)
# Ende def generateGraph
def registerConstraints(self, *constraintsList):
"""
Constraint objects for optimization are registered with the optimizer object
"""
for constraint in constraintsList:
print "I am here"
constraint.graph = self.graph
self.optimizer.addConstraint(constraint)
def outputGraph(self, outputOption, fileName):
"""
Output the optimized graph in the specified format
"""
# TODO: make the magic numbers defined constants
if outputOption == 1:
self.output.dotFile(fileName)
elif outputOption == 2:
self.output.pickleFile(fileName)
elif outputOption == 3:
self.output.imageFile(fileName)
else:
print "Error"
# raise an exception
# End def outputGraph
def getGraphObject(self):
"""
Returns the final NetworkX graph object
"""
return self.output.getNXObject()
# End def getGraphObject
# End Class GraphGenerator
class Input(object):
"""
Processes the input for the GraphGenerator.
"""
def __init__(self):
"""
Initialize the Input object
"""
# End def __init__
def processInput(self, edgeWeightsArray):
"""
Takes an array argument and processes it for use in genrating a graph object.
"""
# Use numpy's upper triangle function with k=1 to make diagonal and below zeros
return np.triu(edgeWeightsArray, k=1)
# End Class Input
class Constructor(object):
"""
Constructs and initial graph from the input supplied by the Input object.
"""
def __init__(self, graph):
"""
Initialize the Constructor object
"""
self.graph = graph
# End def __init__
# TO DO: make weight comparison abstract to handle either > or <
def constructGraph(self, weightedAdjacencyMatrix, weightLimit):
"""
Build a NetworkX graph object from a weighted adjacency matrix
"""
numberVertices = weightedAdjacencyMatrix.shape[0]
self.graph.add_nodes_from( range(numberVertices) )
for i in xrange(numberVertices):
for j in xrange(numberVertices):
if weightedAdjacencyMatrix[i][j] > weightLimit:
self.graph.add_edge( i, j, weight=weightedAdjacencyMatrix[i][j] )
self.graph.graph['state'] = "constructed(initial)"
# End def constructGraph
# End Class Constructor
class Optimizer(object):
"""
Optimizes the initial graph by successive component-wise optimization of the initial
graph created by the Constructor object.
"""
def __init__(self, graph):
"""
Initialize the Optimizer object
"""
self.constraintsList = []
self.graph = graph
# End def __init__
def addConstraint(self, constraint):
"""
Registers a constraint to be used in optimization
"""
self.constraintsList.append(constraint)
# End def addConstraint
def optimizeComponents(self):
"""
Optimizes the graph with the registered constraints
"""
print "In Optimize Graph"
print nx.info(self.graph)
componentsList = nx.connected_component_subgraphs(self.graph)
for constraint in self.constraintsList:
constraint.checkPriorViolations()
for component in componentsList:
edgeList = component.edges(data=True)
# TO DO: Need to make this work both in order and reverse
edgeList.sort( key=operator.itemgetter(2) )
for edge in edgeList:
self.graph.remove_edge(edge[0], edge[1])
for constraint in self.constraintsList:
if constraint.checkConstraint():
self.graph.add_edge(edge[0], edge[1], weight=edge[2])
# End def optimizeGraph
# End Class Optimizer
class Combiner(object):
"""
Attempts to insert edges where needed and possible to the optmized graph from the Optimizer
object to reduce the number of components in the final graph.
"""
def __init__(self, graph):
"""
Initialize the Combiner object
"""
self.graph = graph
# End def __init__
# End Class Combiner
class Output(object):
"""
Formats the final graph from the Combiner object for output in any of several formats.
Desired Formats:
1. DOT File
2. Pickled NetworkX Graph object
3. Image file format (PNG, JPEG)
Future:
1. GML
2. GraphML
"""
def __init__(self, graph):
"""
Initialize the Output object
"""
self.graph = graph
# End def __init__
def dotFile(self, fileName):
"""
Generate a DOT file of the final graph
"""
nx.write_dot(self.graph, fileName)
# End def dotFile
def pickleFile(self, fileName):
"""
Generate a pickleFile of the final graph
"""
nx.write_pickle(self.graph, fileName)
# End def pickleFile
def imageFile(self, fileName):
"""
Generate an image file in the specified type of the final graph
"""
nx.draw_networkx(self.graph)
plt.savefig(fileName + ".png")
# End def imageFile
def getNXObject(self):
"""
Returns a NetworkX graph Object of the final graph
"""
return self.graph
# End def getNXObject
# End Class Output