iconofthestoneage-doodl 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/lib/app/selfrunning.rb +185 -0
  2. data/lib/app/simple_app.rb +49 -0
  3. data/lib/app/simple_controller.rb +584 -0
  4. data/lib/app/simple_model.rb +292 -0
  5. data/lib/app/simple_view.rb +148 -0
  6. data/lib/breadth_first_search.rb +69 -0
  7. data/lib/connected_components.rb +29 -0
  8. data/lib/depth_first_search.rb +73 -0
  9. data/lib/edge.rb +57 -0
  10. data/lib/graph.rb +365 -0
  11. data/lib/graph_canvas.rb +187 -0
  12. data/lib/graph_generator.rb +121 -0
  13. data/lib/jruby/renderer.rb +413 -0
  14. data/lib/layout/collapse_layout.rb +23 -0
  15. data/lib/layout/fr_layout.rb +105 -0
  16. data/lib/layout/isom_layout.rb +77 -0
  17. data/lib/layout/kk_layout.rb +203 -0
  18. data/lib/layout/layout.rb +240 -0
  19. data/lib/layout/morph_layout.rb +65 -0
  20. data/lib/node.rb +57 -0
  21. data/lib/shortest_path/all_pair.rb +35 -0
  22. data/lib/shortest_path/bellman_ford.rb +60 -0
  23. data/lib/shortest_path/dijkstra.rb +74 -0
  24. data/lib/shortest_path/floyd_warshall.rb +68 -0
  25. data/lib/shortest_path/johnson_all_pair.rb +64 -0
  26. data/lib/shortest_path/single_source.rb +32 -0
  27. data/spec/breadth_first_search_spec.rb +145 -0
  28. data/spec/connected_components_spec.rb +50 -0
  29. data/spec/depth_first_search_spec.rb +89 -0
  30. data/spec/edge_spec.rb +58 -0
  31. data/spec/graph_generator_spec.rb +277 -0
  32. data/spec/graph_spec.rb +269 -0
  33. data/spec/jruby/renderer_spec.rb +214 -0
  34. data/spec/layout/layout_spec.rb +146 -0
  35. data/spec/node_spec.rb +179 -0
  36. data/spec/rspec_helper.rb +9 -0
  37. data/spec/rspec_suite.rb +12 -0
  38. data/spec/shortest_path/bellman_ford_spec.rb +101 -0
  39. data/spec/shortest_path/dijkstra_spec.rb +133 -0
  40. data/spec/shortest_path/floyd_warshall_spec.rb +84 -0
  41. data/spec/shortest_path/johnson_all_pair_spec.rb +90 -0
  42. metadata +43 -2
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require "depth_first_search"
4
+
5
+ module Doodl
6
+ class ConnectedComponents
7
+
8
+ attr_reader :component
9
+
10
+ def initialize(graph, start_node = nil)
11
+ @component = {}
12
+ @component_count = 0
13
+ @dfs = DepthFirstSearch.new(graph, start_node, self)
14
+ end
15
+
16
+ def num_connected_components
17
+ @component_count
18
+ end
19
+
20
+ def start_node(graph, node)
21
+ @component_count += 1
22
+ end
23
+
24
+ def discover(graph, node)
25
+ @component[node] = @component_count
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ module Doodl
4
+
5
+ class DepthFirstSearch
6
+
7
+ attr_reader :dist, :prev, :list
8
+
9
+ def initialize(graph, start_node = nil, visitor = nil, radius = nil)
10
+ @graph, @start_node, @visitor, @radius = graph, start_node, visitor, radius
11
+ @color, @prev, @dist = {}, {}, {}
12
+ @time = 0
13
+ @list = []
14
+ init_maps
15
+ main_algorithm
16
+ end
17
+
18
+ private
19
+
20
+ def init_maps
21
+ @graph.each_node do |node|
22
+ visit(:init, @graph, node)
23
+ @color[node] = :white
24
+ @prev[node] = node
25
+ end
26
+ end
27
+
28
+ def main_algorithm
29
+ if (@start_node)
30
+ visit(:start_node, @graph, @start_node)
31
+ dfs(@start_node)
32
+ end
33
+ @graph.each_node do |node|
34
+ if @color[node] == :white
35
+ visit(:start_node, @graph, node)
36
+ dfs(node)
37
+ end
38
+ end
39
+ end
40
+
41
+ def dfs(node)
42
+ @color[node] = :gray
43
+ visit(:discover, @graph, node)
44
+ @list << node
45
+ @dist[node] = @time
46
+ @time += 1
47
+ if (@radius == nil or @time <= @radius)
48
+ @graph.each_adjacent(node) do |adj_node, edge|
49
+ visit(:examine, @graph, edge)
50
+ if (@color[adj_node] == :white)
51
+ @prev[adj_node] = node
52
+ visit(:tree_edge, @graph, edge)
53
+ dfs(adj_node)
54
+ elsif (@color[adj_node] == :gray)
55
+ visit(:back_edge, @graph, edge)
56
+ elsif (@color[adj_node] == :black)
57
+ visit(:forward_edge, @graph, edge)
58
+ end
59
+ end
60
+ @color[node] = :black
61
+ visit(:finish, @graph, node)
62
+ end
63
+ end
64
+
65
+ def visit(position, *arg)
66
+ if @visitor.respond_to?(position)
67
+ @visitor.send(position, *arg)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ module Doodl
4
+
5
+ class Edge
6
+ attr_reader :source, :target
7
+
8
+ def initialize(source, target)
9
+ @source = source
10
+ @target = target
11
+ end
12
+
13
+ def to_s
14
+ "(#{@source}, #{@target})"
15
+ end
16
+
17
+ def reflexive?
18
+ @source == @target
19
+ end
20
+ end
21
+
22
+ class DirectedEdge < Edge
23
+
24
+ def ==(obj)
25
+ obj.respond_to?(:source) and
26
+ obj.respond_to?(:target) and
27
+ obj.source == self.source and
28
+ obj.target == self.target
29
+ end
30
+
31
+ def directed?
32
+ true
33
+ end
34
+
35
+ end
36
+
37
+ class UndirectedEdge < Edge
38
+
39
+ def ==(obj)
40
+ (obj.respond_to?(:source) and obj.respond_to?(:target)) and
41
+ ((obj.source == self.source and obj.target == self.target) or
42
+ (obj.source == self.target and obj.target == self.source))
43
+ end
44
+
45
+ def eql?(obj)
46
+ (obj.respond_to?(:source) and obj.respond_to?(:target)) and
47
+ ((obj.source == self.source and obj.target == self.target) or
48
+ (obj.source == self.target and obj.target == self.source))
49
+ end
50
+
51
+ def directed?
52
+ false
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,365 @@
1
+ # encoding: utf-8
2
+
3
+ require "node"
4
+ require "edge"
5
+ require "graph_generator"
6
+
7
+ require "forwardable"
8
+ require "observer"
9
+
10
+ module Doodl
11
+
12
+ class Graph
13
+ extend Forwardable
14
+ include Observable
15
+ include GraphGenerator
16
+
17
+ attr_reader :nodes
18
+
19
+ def initialize
20
+ @nodes = []
21
+ @node_data = Hash.new
22
+ @edge_data = Hash.new
23
+ end
24
+
25
+ def directed?
26
+ raise NotImplementedError
27
+ end
28
+ #Convinience
29
+ def contains_node?(node)
30
+ @nodes.include?(node)
31
+ end
32
+
33
+ def contains_edge?(edge)
34
+ raise NotImplementedError
35
+ end
36
+
37
+ def get_edge(source, target)
38
+ raise NotImplementedError
39
+ end
40
+
41
+ #Attachable User Data
42
+ def attach_node_data(key, hash = Hash.new)
43
+ @node_data[key] = hash
44
+ end
45
+
46
+ def detach_node_data(key)
47
+ @node_data.delete(key)
48
+ end
49
+
50
+ def attach_edge_data(key, hash = Hash.new)
51
+ @edge_data[key] = hash
52
+ end
53
+
54
+ def detach_edge_data(key)
55
+ @edge_data.delete(key)
56
+ end
57
+
58
+ def_delegator(:@node_data, :keys, :node_data_keys)
59
+
60
+ def_delegator(:@node_data, :[], :node_data)
61
+
62
+ def_delegator(:@node_data, :has_key?, :has_node_data_key?)
63
+
64
+ def_delegator(:@edge_data, :keys, :edge_data_keys)
65
+
66
+ def_delegator(:@edge_data, :[], :edge_data)
67
+
68
+ def_delegator(:@edge_data, :has_key?, :has_edge_data_key?)
69
+
70
+ #Mutable Graph
71
+ private
72
+ def gen_node
73
+ raise NotImplementedError
74
+ end
75
+
76
+ def gen_edge(source, target)
77
+ raise NotImplementedError
78
+ end
79
+
80
+ public
81
+ def add_node(update = false)
82
+ node = self.gen_node
83
+ @nodes << node
84
+ changed if update
85
+ notify_observers(self)
86
+ return node
87
+ end
88
+
89
+ def add_edge(source, target)
90
+ raise NotImplementedError
91
+ end
92
+
93
+ def del_node(node, update = false)
94
+ raise NotImplementedError
95
+ end
96
+
97
+ def del_edge(edge, update = false)
98
+ raise NotImplementedError
99
+ end
100
+
101
+ #Node List Graph
102
+ def_delegator(:@nodes, :each, :each_node)
103
+
104
+ def_delegator(:@nodes, :each_with_index, :each_node_with_index)
105
+
106
+ def each_node_passing(condition)
107
+ if block_given?
108
+ each_node do |node|
109
+ yield(node) if (condition.call(node))
110
+ end
111
+ else
112
+ raise ArgumentError, "No block given."
113
+ end
114
+ end
115
+
116
+ def_delegator(:@nodes, :size, :num_nodes)
117
+
118
+ #Edge List Graph
119
+ def each_edge
120
+ raise NotImplementedError
121
+ end
122
+
123
+ def num_edges
124
+ @nodes.inject(0) { |memo, node| memo + node.out_degree }
125
+ end
126
+
127
+ def source(edge)
128
+ edge.source
129
+ end
130
+
131
+ def target(edge)
132
+ edge.target
133
+ end
134
+
135
+ #Incidence
136
+ def out_degree(node)
137
+ node.degree
138
+ end
139
+
140
+ def each_adjacent_edge(node)
141
+ raise NotImplementedError
142
+ end
143
+
144
+ #Adjacent Graph
145
+ def each_adjacent_node(node)
146
+ raise NotImplementedError
147
+ end
148
+
149
+ def to_s
150
+ nodes = @nodes.inject("") { |memo, o| memo << o.to_s << ", " }
151
+ edges = ""
152
+ self.each_edge { |e| edges << e.to_s << ", "}
153
+ str = ""
154
+ str << "Graph Type: #{self.class.name}\n"
155
+ str << "Nodes: [#{nodes.chomp(", ")}]\n"
156
+ str << "Edges: [#{edges.chomp(", ")}]\n"
157
+ str << "Attached Node Data Keys: #{@node_data.keys.inspect}\n" if @node_data
158
+ str << "Attached Edge Data Keys: #{@edge_data.keys.inspect}\n" if @edge_data
159
+ end
160
+
161
+ end
162
+
163
+ class DirectedGraph < Graph
164
+
165
+ def directed?
166
+ true
167
+ end
168
+
169
+ def includes_edge?(edge)
170
+ raise ArgumentError unless edge.respond_to?(:source) and edge.respond_to?(:target)
171
+ contains_node?(edge.source) and contains_node?(edge.target) and edge.source.includes_out_edge?(edge)
172
+ end
173
+
174
+
175
+ def gen_node
176
+ DirectedNode.new
177
+ end
178
+
179
+ def gen_edge(source, target)
180
+ DirectedEdge.new(source, target)
181
+ end
182
+
183
+ def get_edge(source, target)
184
+ raise ArgumentError, "Source and Target must be member of Graph" unless (@nodes.include?(source) and @nodes.include?(target))
185
+ source.get_edge(target)
186
+ end
187
+
188
+ def del_node(node, update = false)
189
+ each_edge do |edge|
190
+ if (edge.source == node or edge.target == node)
191
+ source = edge.source
192
+ source.del_out_edge(edge)
193
+ end
194
+ end
195
+ @nodes.delete(node)
196
+ changed if update
197
+ notify_observers(self)
198
+ end
199
+
200
+ def add_edge(source, target, update = false)
201
+ raise ArgumentError, "Source/Target must be member of graph" unless (@nodes.include?(source) and @nodes.include?(target))
202
+ edge = DirectedEdge.new(source, target)
203
+ raise ArgumentError if source.includes_out_edge?(edge)
204
+ source.add_out_edge(edge)
205
+ changed if update
206
+ notify_observers(self)
207
+ return edge
208
+ end
209
+
210
+ def del_edge(edge, update = false)
211
+ edge.source.del_out_edge(edge)
212
+ changed if update
213
+ notify_observers(self)
214
+ end
215
+
216
+ def each_edge
217
+ each_node do |source|
218
+ source.each_out_edge { |edge| yield(edge) }
219
+ end
220
+ end
221
+
222
+ #Incidence
223
+ def out_degree(node)
224
+ node.out_degree
225
+ end
226
+
227
+ def each_adjacent_edge(node)
228
+ node.each_out_edge { |edge| yield(edge) }
229
+ end
230
+
231
+ def each_adjacent_node(node)
232
+ each_adjacent_edge(node) { |edge| yield(target(edge)) }
233
+ end
234
+
235
+ def each_adjacent(node)
236
+ each_adjacent_edge(node) { |edge| yield(target(edge), edge) }
237
+ end
238
+
239
+ end
240
+
241
+ class SimpleBidirectionalGraph < DirectedGraph
242
+
243
+ def gen_node
244
+ SimpleBidirectionalNode.new
245
+ end
246
+
247
+ def add_edge(source, target, update = false)
248
+ raise ArgumentError unless (@nodes.include?(source) and @nodes.include?(target))
249
+ edge = DirectedEdge.new(source, target)
250
+ raise ArgumentError if (source.includes_out_edge(edge) or target.includes_in_edge?(edge))
251
+ source.add_out_edge(edge)
252
+ target.add_in_edge(edge)
253
+ changed if update
254
+ notify_observers(self)
255
+ return edge
256
+ end
257
+
258
+ def each_in_edge(node)
259
+ node.each_in_edge do |edge|
260
+ yield(edge)
261
+ end
262
+ end
263
+
264
+ end
265
+
266
+ class UndirectedGraph < Graph
267
+
268
+ def directed?
269
+ false
270
+ end
271
+
272
+ def includes_edge?(edge)
273
+ edge.source.includes_edge?(edge)
274
+ end
275
+
276
+
277
+ def gen_node
278
+ UndirectedNode.new
279
+ end
280
+
281
+ def get_edge(source, target)
282
+ raise ArgumentError, "Source and Target must be member of Graph" unless
283
+ (@nodes.include?(source) and @nodes.include?(target))
284
+ source.get_edge(target)
285
+ end
286
+
287
+ def gen_edge(source, target)
288
+ UndirectedEdge.new(source, target)
289
+ end
290
+
291
+ def del_node(node, update = false)
292
+ each_edge do |edge|
293
+ if (edge.source == node or edge.target == node)
294
+ edge.source.del_edge(edge)
295
+ edge.target.del_edge(edge)
296
+ end
297
+ end
298
+ @nodes.delete(node)
299
+ changed if update
300
+ notify_observers(self)
301
+ end
302
+
303
+ def add_edge(source, target, update = false)
304
+ raise ArgumentError unless (@nodes.include?(source) and @nodes.include?(target))
305
+ edge = UndirectedEdge.new(source, target)
306
+ raise ArgumentError if (source.includes_edge?(edge) or target.includes_edge?(edge))
307
+ source.add_edge(edge)
308
+ target.add_edge(edge)
309
+ changed if update
310
+ notify_observers(self)
311
+ return edge
312
+ end
313
+
314
+ def del_edge(edge, update = false)
315
+ edge.source.del_edge(edge)
316
+ edge.target.del_edge(edge)
317
+ changed if update
318
+ notify_observers(self)
319
+ end
320
+
321
+ def each_edge
322
+ result = []
323
+ each_node do |source|
324
+ each_adjacent_edge(source) do |edge|
325
+ result << edge
326
+ end
327
+ end
328
+ result.uniq.each { |edge| yield(edge) }
329
+ end
330
+
331
+ def each_adjacent_edge(node)
332
+ node.each_edge { |edge| yield(edge) }
333
+ end
334
+
335
+ def each_adjacent_node(node)
336
+ each_adjacent_edge(node) do |edge|
337
+ if target(edge) == node
338
+ yield(source(edge))
339
+ else
340
+ yield(target(edge))
341
+ end
342
+ end
343
+ end
344
+
345
+ def each_adjacent(node)
346
+ each_adjacent_edge(node) do |edge|
347
+ if target(edge) == node
348
+ yield(source(edge), edge)
349
+ else
350
+ yield(target(edge), edge)
351
+ end
352
+ end
353
+ end
354
+
355
+ def num_edges
356
+ num = 0
357
+ each_node do |node|
358
+ num += node.degree
359
+ end
360
+ return num / 2
361
+ end
362
+
363
+ end
364
+
365
+ end