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.
- data/lib/app/selfrunning.rb +185 -0
- data/lib/app/simple_app.rb +49 -0
- data/lib/app/simple_controller.rb +584 -0
- data/lib/app/simple_model.rb +292 -0
- data/lib/app/simple_view.rb +148 -0
- data/lib/breadth_first_search.rb +69 -0
- data/lib/connected_components.rb +29 -0
- data/lib/depth_first_search.rb +73 -0
- data/lib/edge.rb +57 -0
- data/lib/graph.rb +365 -0
- data/lib/graph_canvas.rb +187 -0
- data/lib/graph_generator.rb +121 -0
- data/lib/jruby/renderer.rb +413 -0
- data/lib/layout/collapse_layout.rb +23 -0
- data/lib/layout/fr_layout.rb +105 -0
- data/lib/layout/isom_layout.rb +77 -0
- data/lib/layout/kk_layout.rb +203 -0
- data/lib/layout/layout.rb +240 -0
- data/lib/layout/morph_layout.rb +65 -0
- data/lib/node.rb +57 -0
- data/lib/shortest_path/all_pair.rb +35 -0
- data/lib/shortest_path/bellman_ford.rb +60 -0
- data/lib/shortest_path/dijkstra.rb +74 -0
- data/lib/shortest_path/floyd_warshall.rb +68 -0
- data/lib/shortest_path/johnson_all_pair.rb +64 -0
- data/lib/shortest_path/single_source.rb +32 -0
- data/spec/breadth_first_search_spec.rb +145 -0
- data/spec/connected_components_spec.rb +50 -0
- data/spec/depth_first_search_spec.rb +89 -0
- data/spec/edge_spec.rb +58 -0
- data/spec/graph_generator_spec.rb +277 -0
- data/spec/graph_spec.rb +269 -0
- data/spec/jruby/renderer_spec.rb +214 -0
- data/spec/layout/layout_spec.rb +146 -0
- data/spec/node_spec.rb +179 -0
- data/spec/rspec_helper.rb +9 -0
- data/spec/rspec_suite.rb +12 -0
- data/spec/shortest_path/bellman_ford_spec.rb +101 -0
- data/spec/shortest_path/dijkstra_spec.rb +133 -0
- data/spec/shortest_path/floyd_warshall_spec.rb +84 -0
- data/spec/shortest_path/johnson_all_pair_spec.rb +90 -0
- metadata +43 -2
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'layout/layout'
|
4
|
+
|
5
|
+
module Doodl
|
6
|
+
class MorphLayout < Layout
|
7
|
+
|
8
|
+
def initialize(view, layout = RandomLayout)
|
9
|
+
super(view)
|
10
|
+
@target_layout_class = layout
|
11
|
+
@steps = 45
|
12
|
+
@motion = :retard
|
13
|
+
end
|
14
|
+
|
15
|
+
def init(graph)
|
16
|
+
if graph.node_data(:layout)
|
17
|
+
@source = graph.node_data(:layout).clone
|
18
|
+
else
|
19
|
+
sl = RandomLayout.new(@view)
|
20
|
+
sl.graph = graph
|
21
|
+
sl.layout
|
22
|
+
@source = sl.locations.clone
|
23
|
+
end
|
24
|
+
tl = @target_layout_class.new(@view)
|
25
|
+
tl.graph = graph
|
26
|
+
tl.layout
|
27
|
+
@target = tl.locations.clone
|
28
|
+
@locations = graph.node_data(:layout)
|
29
|
+
end
|
30
|
+
|
31
|
+
def dolayout(graph)
|
32
|
+
(1..@steps).each do |step|
|
33
|
+
graph.each_node do |node|
|
34
|
+
@locations[node] = @target[node] + (@source[node]-@target[node]) * dist(step)
|
35
|
+
end
|
36
|
+
changed
|
37
|
+
notify_observers(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def dist(step)
|
42
|
+
if @motion == :accelerate
|
43
|
+
accelerate(step)
|
44
|
+
elsif @motion == :retard
|
45
|
+
retard(step)
|
46
|
+
else
|
47
|
+
smooth(step)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def smooth(step)
|
52
|
+
(0.5 * Math.cos((step / @steps.to_f) * Math::PI)) + 0.5
|
53
|
+
end
|
54
|
+
|
55
|
+
def accelerate(step)
|
56
|
+
Math.cos((step / @steps.to_f) * Math::PI/2)
|
57
|
+
end
|
58
|
+
|
59
|
+
def retard(step)
|
60
|
+
1 - Math.sin((step / @steps.to_f) * Math::PI/2)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/node.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Doodl
|
6
|
+
|
7
|
+
class Node
|
8
|
+
end
|
9
|
+
|
10
|
+
class UndirectedNode < Node
|
11
|
+
extend Forwardable
|
12
|
+
def initialize
|
13
|
+
@edges = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegator(:@edges, :include?, :includes_edge?)
|
17
|
+
def_delegator(:@edges, :<<, :add_edge)
|
18
|
+
def_delegator(:@edges, :delete, :del_edge)
|
19
|
+
def_delegator(:@edges, :each, :each_edge)
|
20
|
+
def_delegator(:@edges, :size, :degree)
|
21
|
+
|
22
|
+
def get_edge(target)
|
23
|
+
@edges.select { |edge| edge.target == target or edge.source == target}.first
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class DirectedNode < Node
|
29
|
+
extend Forwardable
|
30
|
+
def initialize
|
31
|
+
@out_edges = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def_delegator(:@out_edges, :include?, :includes_out_edge?)
|
35
|
+
def_delegator(:@out_edges, :<<, :add_out_edge)
|
36
|
+
def_delegator(:@out_edges, :delete, :del_out_edge)
|
37
|
+
def_delegator(:@out_edges, :each, :each_out_edge)
|
38
|
+
def_delegator(:@out_edges, :size, :out_degree)
|
39
|
+
|
40
|
+
def get_edge(target)
|
41
|
+
@out_edges.select { |edge| edge.target == target}.first
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SimpleBidirectionalNode < DirectedNode
|
46
|
+
def initialize
|
47
|
+
super
|
48
|
+
@in_edges = []
|
49
|
+
end
|
50
|
+
def_delegator(:@in_edges, :include?, :includes_in_edge?)
|
51
|
+
def_delegator(:@in_edges, :<<, :add_in_edge)
|
52
|
+
def_delegator(:@in_edges, :delete, :del_in_edge)
|
53
|
+
def_delegator(:@in_edges, :each, :each_in_edge)
|
54
|
+
def_delegator(:@in_edges, :size, :in_degree)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Doodl
|
4
|
+
|
5
|
+
module AllPairShortestPaths
|
6
|
+
|
7
|
+
def node_path(source, target)
|
8
|
+
path = []
|
9
|
+
if @dist[[source, target]] != INFINITY
|
10
|
+
while target != source
|
11
|
+
path.unshift target
|
12
|
+
target = @prev[[source, target]]
|
13
|
+
end
|
14
|
+
path.unshift source
|
15
|
+
end
|
16
|
+
return path
|
17
|
+
end
|
18
|
+
|
19
|
+
def edge_path(source, target)
|
20
|
+
path = []
|
21
|
+
if @dist[[source, target]] != INFINITY
|
22
|
+
while target != source
|
23
|
+
path.unshift @graph.get_edge(@prev[[source, target]], target)
|
24
|
+
target = @prev[[source, target]]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return path
|
28
|
+
end
|
29
|
+
|
30
|
+
def diameter
|
31
|
+
@dist.values.select{ |x| x < INFINITY }.max
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shortest_path/single_source"
|
4
|
+
require "facets/infinity"
|
5
|
+
require "graph"
|
6
|
+
|
7
|
+
module Doodl
|
8
|
+
class BellmanFord
|
9
|
+
include SingleSourceShortestPath
|
10
|
+
|
11
|
+
attr_reader :dist, :prev
|
12
|
+
def initialize(graph, source, weight = nil)
|
13
|
+
raise ArgumentError unless graph.is_a?(Graph)
|
14
|
+
raise ArgumentError unless graph.contains_node?(source)
|
15
|
+
@dist, @prev = {}, {}
|
16
|
+
@graph, @source, = graph, source
|
17
|
+
if weight
|
18
|
+
@weight = weight
|
19
|
+
else
|
20
|
+
@weight = Hash.new(1)
|
21
|
+
end
|
22
|
+
init_maps
|
23
|
+
main_algorithm
|
24
|
+
check_for_negative_cyles
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def check_for_negative_cyles
|
30
|
+
@graph.each_edge do |e|
|
31
|
+
if @dist[e.source] < INFINITY and @dist[e.target] > (@dist[e.source] + @weight[e])
|
32
|
+
raise ArgumentError, "Graph has negative weight cycles"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def main_algorithm
|
38
|
+
(1..@graph.num_nodes-1).each do
|
39
|
+
@graph.each_edge do |e|
|
40
|
+
if @dist[e.source] < INFINITY and @dist[e.target] > (@dist[e.source] + @weight[e])
|
41
|
+
@dist[e.target] = @dist[e.source] + @weight[e]
|
42
|
+
@prev[e.target] = e.source
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def init_maps
|
49
|
+
@graph.each_node do |node|
|
50
|
+
@prev[node] = nil
|
51
|
+
if node == @source
|
52
|
+
@dist[node] = 0
|
53
|
+
else
|
54
|
+
@dist[node] = INFINITY
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "graph"
|
4
|
+
require "shortest_path/single_source"
|
5
|
+
require "facets/infinity"
|
6
|
+
require "facets/pqueue"
|
7
|
+
|
8
|
+
module Doodl
|
9
|
+
|
10
|
+
class DijkstraShortestPath
|
11
|
+
include SingleSourceShortestPath
|
12
|
+
|
13
|
+
attr_reader :dist, :prev
|
14
|
+
|
15
|
+
def initialize(graph, source, weight_key = nil)
|
16
|
+
raise ArgumentError unless graph.is_a?(Graph)
|
17
|
+
raise ArgumentError unless graph.contains_node?(source)
|
18
|
+
raise ArgumentError if (weight_key and not graph.has_edge_data_key?(weight_key))
|
19
|
+
|
20
|
+
@graph, @source, @weight_key = graph, source, weight_key
|
21
|
+
@dist, @color, @prev = {}, {}, {}
|
22
|
+
@queue = PQueue.new { |x, y| @dist[x] < @dist[y] }
|
23
|
+
@weight = @graph.edge_data(@weight_key)
|
24
|
+
|
25
|
+
init_maps
|
26
|
+
main_algorithm
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def init_maps
|
32
|
+
@graph.each_node do |node|
|
33
|
+
@dist[node] = INFINITY
|
34
|
+
@prev[node] = nil
|
35
|
+
@color[node] = :white
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def main_algorithm
|
40
|
+
@color[@source] = :gray
|
41
|
+
@dist[@source] = 0
|
42
|
+
@queue << @source
|
43
|
+
while @queue.size != 0
|
44
|
+
u = @queue.pop
|
45
|
+
@graph.each_adjacent_edge(u) do |edge|
|
46
|
+
if (u == edge.source)
|
47
|
+
v = edge.target
|
48
|
+
else
|
49
|
+
v = edge.source
|
50
|
+
end
|
51
|
+
if (weight(edge) + @dist[u] < @dist[v])
|
52
|
+
@dist[v] = weight(edge) + @dist[u]
|
53
|
+
@prev[v] = u
|
54
|
+
if @color[v] == :white
|
55
|
+
@color[v] = :grey
|
56
|
+
@queue << v
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
@color[u] = :black
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def weight(edge)
|
65
|
+
if (@weight)
|
66
|
+
@weight[edge]
|
67
|
+
else
|
68
|
+
1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shortest_path/all_pair"
|
4
|
+
|
5
|
+
require "facets/infinity"
|
6
|
+
require "graph"
|
7
|
+
|
8
|
+
module Doodl
|
9
|
+
|
10
|
+
class FloydWarshall
|
11
|
+
include AllPairShortestPaths
|
12
|
+
|
13
|
+
attr_reader :dist, :prev
|
14
|
+
|
15
|
+
def initialize(graph, weight_key = nil)
|
16
|
+
raise ArgumentError unless graph.is_a?(Graph)
|
17
|
+
raise ArgumentError if (weight_key and not graph.has_edge_data_key?(weight_key))
|
18
|
+
|
19
|
+
@graph, @weight_key = graph, weight_key
|
20
|
+
@dist, @prev = {}, {}
|
21
|
+
init_distance
|
22
|
+
main_algorithm
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def main_algorithm
|
28
|
+
@graph.each_node do |k|
|
29
|
+
@graph.each_node do |i|
|
30
|
+
@graph.each_node do |j|
|
31
|
+
if (@dist[[i,k]] < INFINITY and @dist[[k,j]] < INFINITY)
|
32
|
+
if (@dist[[i,k]] + @dist[[k,j]]) < @dist[[i,j]]
|
33
|
+
@dist[[i,j]] = @dist[[i,k]] + @dist[[k,j]]
|
34
|
+
@prev[[i,j]] = k
|
35
|
+
# @dist[[i, j]] = [@dist[[i,j]], @dist[[i,k]] + @dist[[k,j]]].min
|
36
|
+
else
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def init_distance
|
47
|
+
@graph.each_node do |n|
|
48
|
+
@graph.each_node do |m|
|
49
|
+
edge = @graph.get_edge(n, m)
|
50
|
+
if edge
|
51
|
+
@dist[[n, m]] = weight(edge)
|
52
|
+
@prev[[n, m]] = n
|
53
|
+
elsif n==m
|
54
|
+
@dist[[n,m]] = 0
|
55
|
+
else
|
56
|
+
@dist[[n, m]] = INFINITY
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def weight(edge)
|
63
|
+
1
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shortest_path/all_pair"
|
4
|
+
require "shortest_path/bellman_ford"
|
5
|
+
require "shortest_path/dijkstra"
|
6
|
+
|
7
|
+
module Doodl
|
8
|
+
|
9
|
+
class JohnsonAllPairShortestPaths
|
10
|
+
include AllPairShortestPaths
|
11
|
+
|
12
|
+
attr_reader :dist, :prev
|
13
|
+
|
14
|
+
def initialize(graph, weight = nil)
|
15
|
+
raise ArgumentError unless graph.is_a?(Graph)
|
16
|
+
|
17
|
+
@graph = graph
|
18
|
+
@prev, @dist = {}, {}
|
19
|
+
if weight
|
20
|
+
@weight = weight
|
21
|
+
else
|
22
|
+
@weight = Hash.new(1)
|
23
|
+
end
|
24
|
+
@extra_node = @graph.add_node
|
25
|
+
add_edges_to_extra_node
|
26
|
+
re_weight
|
27
|
+
find_shortest_paths
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def add_edges_to_extra_node
|
34
|
+
@graph.each_node do |node|
|
35
|
+
if node != @extra_node
|
36
|
+
edge = @graph.add_edge(@extra_node, node)
|
37
|
+
@weight[edge] = 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def re_weight
|
43
|
+
@bf_weight = @graph.attach_edge_data(self)
|
44
|
+
bf = BellmanFord.new(@graph, @extra_node, @weight)
|
45
|
+
@graph.del_node(@extra_node)
|
46
|
+
@graph.each_edge do |edge|
|
47
|
+
@bf_weight[edge] = @weight[edge] + bf.dist[edge.source] - bf.dist[edge.target]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_shortest_paths
|
52
|
+
@graph.each_node do |source|
|
53
|
+
dsp = DijkstraShortestPath.new(@graph, source, self)
|
54
|
+
@graph.each_node do |target|
|
55
|
+
@dist[[source, target]] = dsp.dist[target]
|
56
|
+
@prev[[source, target]] = dsp.prev[target]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@graph.detach_edge_data(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Doodl
|
4
|
+
|
5
|
+
module SingleSourceShortestPath
|
6
|
+
|
7
|
+
def node_path_to(node)
|
8
|
+
path = []
|
9
|
+
if @dist[node] != INFINITY
|
10
|
+
while node != @source
|
11
|
+
path.unshift node
|
12
|
+
node = @prev[node]
|
13
|
+
end
|
14
|
+
path.unshift @source
|
15
|
+
end
|
16
|
+
return path
|
17
|
+
end
|
18
|
+
|
19
|
+
def edge_path_to(node)
|
20
|
+
path = []
|
21
|
+
if @dist[node] != INFINITY
|
22
|
+
while node != @source
|
23
|
+
path.unshift @graph.get_edge(@prev[node], node)
|
24
|
+
node = @prev[node]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return path
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|