rgraph 0.0.13 → 0.0.14
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.
- checksums.yaml +4 -4
- data/lib/rgraph/graph.rb +50 -33
- data/lib/rgraph/node.rb +4 -0
- data/lib/rgraph/version.rb +1 -1
- data/spec/rgraph/graph_spec.rb +31 -20
- data/spec/rgraph/node_spec.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c4d3fdd3c5cedd1f8ea3f6f12ac4cfc35ced188
|
4
|
+
data.tar.gz: b9ee2affd0263db5ec94a3bf395d5569ee8ece85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7723113a6c7b319dd3dadae64511d8d0c623832f588ce40f418da526df01a81cb052d509fd89550638ad2554c89cc64e02632cda004f73892d88410601e7e158
|
7
|
+
data.tar.gz: 86883eca3a63e40d83d3cd1c2e2eb326347e8585a39b75bd555f31c56d44e2ca152da0aab91097e0dcc540b903efe656b745eb422c33e62a5410c6780924f92b
|
data/lib/rgraph/graph.rb
CHANGED
@@ -52,30 +52,26 @@ class Graph
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def cumulative_degree
|
55
|
-
|
56
|
-
out = []
|
57
|
-
|
58
|
-
0.upto(degrees.max - 1) do |i|
|
59
|
-
out[i] = cached_degrees.select{|degree| degree > i}.count
|
60
|
-
end
|
55
|
+
out = (0..(degrees.max - 1)).map { |i| degrees.select{|degree| degree > i}.count }
|
61
56
|
out.map{|a| a / out.max.to_f}
|
62
57
|
end
|
63
58
|
|
64
59
|
def idistance
|
65
|
-
dist =
|
60
|
+
dist = matrix(@nodes.size, 0)
|
66
61
|
|
67
|
-
@nodes.sort{|a,b| a.id <=> b.id}
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
62
|
+
sorted = @nodes.sort { |a,b| a.id <=> b.id}
|
63
|
+
|
64
|
+
sorted.each_with_index do |n1, i|
|
65
|
+
sorted.each_with_index do |n2, j|
|
66
|
+
next if i == j
|
67
|
+
dist[i][j] = n1.has_neighbour?(n2) ? link_between(n1, n2).weight.to_i : @infinity
|
72
68
|
end
|
73
69
|
end
|
74
70
|
dist
|
75
71
|
end
|
76
72
|
|
77
73
|
def distances
|
78
|
-
@path =
|
74
|
+
@path = matrix(@nodes.size, [nil])
|
79
75
|
|
80
76
|
@distance = idistance
|
81
77
|
@distance.each_index do |k|
|
@@ -84,7 +80,10 @@ class Graph
|
|
84
80
|
new_dist = @distance[i][k] + @distance[k][j]
|
85
81
|
if @distance[i][j] > new_dist
|
86
82
|
@distance[i][j] = new_dist
|
87
|
-
@path[i][j] = k
|
83
|
+
@path[i][j] = [k]
|
84
|
+
end
|
85
|
+
if @distance[i][j] == new_dist && !(@path[i][j].include? k) && ! [i,j].include?(k)
|
86
|
+
@path[i][j] << k
|
88
87
|
end
|
89
88
|
end
|
90
89
|
end
|
@@ -99,41 +98,51 @@ class Graph
|
|
99
98
|
fdistance.inject(:+) / fdistance.count.to_f
|
100
99
|
end
|
101
100
|
|
102
|
-
def shortest_paths
|
103
|
-
|
101
|
+
def shortest_paths(args = {})
|
102
|
+
multiples = args[:multiples] || false
|
103
|
+
@shortest_paths = []
|
104
104
|
|
105
|
-
distances
|
105
|
+
distances
|
106
106
|
|
107
107
|
0.upto(@nodes.size - 1).each do |i|
|
108
|
-
i.upto(@nodes.size - 1).each do |j|
|
109
|
-
|
110
|
-
sp = shortest_path(i, j)
|
111
|
-
tmp << sp unless sp.empty?
|
108
|
+
(i + 1).upto(@nodes.size - 1).each do |j|
|
109
|
+
@shortest_paths += shortest_path(i, j, multiples)
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
115
|
-
@shortest_paths
|
113
|
+
@shortest_paths
|
116
114
|
end
|
117
115
|
|
118
|
-
def shortest_path(i, j)
|
116
|
+
def shortest_path(i, j, multiples = false)
|
119
117
|
|
120
118
|
return [] if @distance[i][j] == @infinity
|
121
119
|
|
122
|
-
|
120
|
+
path = @path[i][j].count == 1 || multiples ? @path[i][j] : [@path[i][j].first]
|
121
|
+
out = []
|
123
122
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
123
|
+
path.each do |k|
|
124
|
+
|
125
|
+
case k
|
126
|
+
when @infinity
|
127
|
+
out << []
|
128
|
+
when nil
|
129
|
+
out << [i,j]
|
130
|
+
else
|
131
|
+
i_k = shortest_path(i, k)
|
132
|
+
k_j = shortest_path(k, j)
|
133
|
+
|
134
|
+
i_k.each do |ik|
|
135
|
+
k_j.each do |kj|
|
136
|
+
out << ik[0..-2] + [k] + kj[1..-1]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
132
140
|
end
|
141
|
+
out
|
133
142
|
end
|
134
143
|
|
135
144
|
def between(i)
|
136
|
-
shortest_paths
|
145
|
+
shortest_paths(multiples: true)
|
137
146
|
|
138
147
|
n = @shortest_paths.select{|c| c[1..-2].include?(i)}.size.to_f
|
139
148
|
m = @shortest_paths.size.to_f
|
@@ -249,8 +258,16 @@ class Graph
|
|
249
258
|
end
|
250
259
|
end
|
251
260
|
|
261
|
+
def link_between(n1, n2)
|
262
|
+
@links.select{ |l| (l.source == n1 && l.target == n2) || (l.source == n2 && l.target == n1) }.first
|
263
|
+
end
|
264
|
+
|
252
265
|
def possible_connections(node)
|
253
266
|
total = node.neighbours.count
|
254
267
|
total * (total - 1) / 2
|
255
268
|
end
|
269
|
+
|
270
|
+
def matrix(size, value)
|
271
|
+
Array.new(size) { Array.new(size, value) }
|
272
|
+
end
|
256
273
|
end
|
data/lib/rgraph/node.rb
CHANGED
data/lib/rgraph/version.rb
CHANGED
data/spec/rgraph/graph_spec.rb
CHANGED
@@ -125,6 +125,17 @@ describe Graph do
|
|
125
125
|
end
|
126
126
|
describe "Paths' metrics" do
|
127
127
|
subject { Graph.new('spec/fixtures/small_graph.csv') }
|
128
|
+
|
129
|
+
it "calculates a simple shortest path" do
|
130
|
+
g = Graph.new_from_string("source,target\n1,2")
|
131
|
+
expect(g.shortest_paths).to eq([[0, 1]])
|
132
|
+
end
|
133
|
+
|
134
|
+
it "doesn't return empty paths" do
|
135
|
+
g = Graph.new_from_string("source,target\n1,2\n3,4")
|
136
|
+
expect(g.shortest_paths).to eq([[0,1],[2,3]])
|
137
|
+
end
|
138
|
+
|
128
139
|
it "calculates the shortest paths" do
|
129
140
|
expect(subject.shortest_paths.sort).to eq(
|
130
141
|
[[0, 1],
|
@@ -142,36 +153,39 @@ describe Graph do
|
|
142
153
|
[3, 4], [3, 5],
|
143
154
|
[4, 3, 5]].sort)
|
144
155
|
end
|
145
|
-
it "
|
146
|
-
g = Graph.new_from_string("source,target\n1,2\
|
147
|
-
expect(g.shortest_paths).to eq(
|
156
|
+
it "returns multiples short paths when asked" do
|
157
|
+
g = Graph.new_from_string("source,target\n1,2\n2,3\n1,4\n4,3")
|
158
|
+
expect(g.shortest_paths.count).to eq(6)
|
159
|
+
expect(g.shortest_paths(multiples: true).count).to eq(8)
|
148
160
|
end
|
149
|
-
|
150
161
|
it "calculates the betweenness of a single node" do
|
151
|
-
expect(subject.between(0)).to eq(0 /
|
152
|
-
expect(subject.between(1)).to eq(2 /
|
153
|
-
expect(subject.between(2)).to eq(2 /
|
154
|
-
expect(subject.between(3)).to eq(
|
155
|
-
expect(subject.between(4)).to eq(
|
156
|
-
expect(subject.between(5)).to eq(0 /
|
162
|
+
expect(subject.between(0)).to eq(0 / 18.0)
|
163
|
+
expect(subject.between(1)).to eq(2 / 18.0)
|
164
|
+
expect(subject.between(2)).to eq(2 / 18.0)
|
165
|
+
expect(subject.between(3)).to eq(6 / 18.0)
|
166
|
+
expect(subject.between(4)).to eq(4 / 18.0)
|
167
|
+
expect(subject.between(5)).to eq(0 / 18.0)
|
157
168
|
end
|
158
169
|
it "calculates all betweenness" do
|
159
170
|
expect(subject.betweenness).to eq(
|
160
|
-
[0 /
|
161
|
-
2 /
|
162
|
-
2 /
|
163
|
-
|
164
|
-
|
165
|
-
0 /
|
171
|
+
[0 / 18.0,
|
172
|
+
2 / 18.0,
|
173
|
+
2 / 18.0,
|
174
|
+
6 / 18.0,
|
175
|
+
4 / 18.0,
|
176
|
+
0 / 18.0])
|
166
177
|
end
|
167
178
|
it "calculates all betweenness normalized" do
|
168
179
|
expect(subject.betweenness(normalized: true)).to eq(
|
169
|
-
[0.0, 0
|
180
|
+
[0.0, 1 / 3.0, 1 / 3.0, 1.0, 2 / 3.0, 0.0])
|
170
181
|
end
|
171
182
|
it "works with holes" do
|
172
183
|
g = Graph.new_from_string("source,target\n1,2\n3,4")
|
173
184
|
expect(g.betweenness.inject(:+)).to eq(0)
|
174
185
|
end
|
186
|
+
it "calculates cumulative betweenness" do
|
187
|
+
expect(subject.betweenness(cumulative: true)).to eq([[6, 0.0], [4, 1 / 3.0], [2, 2 / 3.0], [1, 1.0]])
|
188
|
+
end
|
175
189
|
it "calculates diameter" do
|
176
190
|
expect(subject.diameter).to eq(3)
|
177
191
|
end
|
@@ -185,9 +199,6 @@ describe Graph do
|
|
185
199
|
g = Graph.new_from_string("source,target\n1,2\n3,4")
|
186
200
|
expect(g.components).to eq([g.nodes[0..1], g.nodes[2..3]])
|
187
201
|
end
|
188
|
-
it "calculates cumulative betweenness" do
|
189
|
-
expect(subject.betweenness(cumulative: true)).to eq([[6, 0.0], [4, 0.5], [1, 1.0]])
|
190
|
-
end
|
191
202
|
it "calculates clustering of a single node" do
|
192
203
|
nodes = subject.nodes.sort{|a,b| a.id <=> b.id}
|
193
204
|
|
data/spec/rgraph/node_spec.rb
CHANGED
@@ -11,4 +11,13 @@ describe Node do
|
|
11
11
|
describe "#degree" do
|
12
12
|
its(:degree) { should eq 0}
|
13
13
|
end
|
14
|
+
|
15
|
+
describe "#has_neighbour" do
|
16
|
+
it "recognizes its neighbour" do
|
17
|
+
n1 = Node.new(id: 1)
|
18
|
+
n2 = Node.new(id: 1)
|
19
|
+
n1.neighbours << n2
|
20
|
+
expect(n1.has_neighbour?(n2)).to be_true
|
21
|
+
end
|
22
|
+
end
|
14
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Aride Moulin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|