rgraph 0.0.15 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile +0 -1
- data/Rakefile +5 -2
- data/ext/fw/extconf.rb +5 -0
- data/ext/fw/fw.c +32 -0
- data/lib/rgraph/graph.rb +17 -34
- data/lib/rgraph/link.rb +8 -9
- data/lib/rgraph/node.rb +4 -5
- data/lib/rgraph/version.rb +1 -1
- data/rgraph.gemspec +10 -8
- data/spec/rgraph/graph_spec.rb +80 -53
- data/spec/rgraph/link_spec.rb +10 -8
- data/spec/rgraph/node_spec.rb +11 -9
- metadata +43 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2be82f7a8925ee33f06108c11c294e22f9afd4fd
|
4
|
+
data.tar.gz: 8123623213d0101ca164bb1e4225fc79f8f4a49c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a45882e191a2da840cc67a973a242159d9a1ce24187dcaa32a042ab87024e2cb85afd837d4e6ddbe48668064dd7ab1cb02874f4045b8d1c8bf991be4e77bb8a
|
7
|
+
data.tar.gz: 43da8cf461fb090a8e84947c4b58ae97df2955969b132383eb348f3079da102972ca4191ef5e5dca8ea5ac26455c15851678596db321e838e57d7ed13d86bdbd
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
|
+
require 'rake/extensiontask'
|
4
|
+
|
5
|
+
Rake::ExtensionTask.new('fw')
|
3
6
|
|
4
7
|
RSpec::Core::RakeTask.new
|
5
8
|
|
6
|
-
task :default => :spec
|
7
|
-
task :test => :spec
|
9
|
+
task :default => [:compile, :spec]
|
10
|
+
task :test => [:compile, :spec]
|
data/ext/fw/extconf.rb
ADDED
data/ext/fw/fw.c
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
static VALUE fw(VALUE arr1, VALUE path) {
|
4
|
+
int i, j, k;
|
5
|
+
float ij, ik, kj, new_distance;
|
6
|
+
int size;
|
7
|
+
|
8
|
+
size = RARRAY_LEN(arr1);
|
9
|
+
|
10
|
+
for(k = 0; k < size; k++) {
|
11
|
+
for (i = 0; i < size; i++){
|
12
|
+
for (j = 0; j < size; j++) {
|
13
|
+
ij = NUM2DBL(rb_ary_entry(rb_ary_entry(arr1, i), j));
|
14
|
+
ik = NUM2DBL(rb_ary_entry(rb_ary_entry(arr1, i), k));
|
15
|
+
kj = NUM2DBL(rb_ary_entry(rb_ary_entry(arr1, k), j));
|
16
|
+
new_distance = ik + kj;
|
17
|
+
if(ij > new_distance) {
|
18
|
+
rb_ary_store(rb_ary_entry(arr1, i), j, rb_float_new(new_distance));
|
19
|
+
rb_ary_store(rb_ary_entry(path, i), j, rb_ary_new3(1, rb_float_new(k)));
|
20
|
+
}
|
21
|
+
if((ij == new_distance) && !RTEST(rb_ary_includes(rb_ary_entry(rb_ary_entry(path, i), j), rb_float_new(k)))&& !(i == k || j == k)) {
|
22
|
+
rb_ary_push(rb_ary_entry(rb_ary_entry(path, i), j), rb_float_new(k));
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
return arr1;
|
28
|
+
}
|
29
|
+
|
30
|
+
void Init_fw() {
|
31
|
+
rb_define_method(rb_cArray, "fw!", fw, 1);
|
32
|
+
}
|
data/lib/rgraph/graph.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#encoding: utf-8
|
2
2
|
require 'csv'
|
3
|
+
require 'fw'
|
3
4
|
require_relative '../../lib/rgraph/link'
|
4
5
|
require_relative '../../lib/rgraph/node'
|
5
6
|
|
@@ -12,7 +13,7 @@ class Graph
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def initialize(csv)
|
15
|
-
@nodes =
|
16
|
+
@nodes = {}
|
16
17
|
@links = []
|
17
18
|
@distance = nil
|
18
19
|
@infinity = 100_000
|
@@ -36,7 +37,7 @@ class Graph
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def each_node(&block)
|
39
|
-
@nodes.
|
40
|
+
@nodes.each_value(&block)
|
40
41
|
end
|
41
42
|
|
42
43
|
def each_link(&block)
|
@@ -44,7 +45,7 @@ class Graph
|
|
44
45
|
end
|
45
46
|
|
46
47
|
def degrees
|
47
|
-
@nodes.map{|node| node.degree}
|
48
|
+
@nodes.values.map{|node| node.degree}
|
48
49
|
end
|
49
50
|
|
50
51
|
def average_degree
|
@@ -59,12 +60,10 @@ class Graph
|
|
59
60
|
def idistance
|
60
61
|
dist = matrix(@nodes.size, 0)
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
sorted.each_with_index do |n1, i|
|
65
|
-
sorted.each_with_index do |n2, j|
|
63
|
+
@nodes.values.each_with_index do |n1, i|
|
64
|
+
@nodes.values.each_with_index do |n2, j|
|
66
65
|
next if i == j
|
67
|
-
dist[i][j] = n1.has_neighbour?(n2) ? link_between(n1, n2)
|
66
|
+
dist[i][j] = n1.has_neighbour?(n2) ? link_between(n1, n2)[:weight].to_i : @infinity
|
68
67
|
end
|
69
68
|
end
|
70
69
|
dist
|
@@ -72,23 +71,7 @@ class Graph
|
|
72
71
|
|
73
72
|
def distances
|
74
73
|
@path = matrix(@nodes.size, [nil])
|
75
|
-
|
76
|
-
@distance = idistance
|
77
|
-
@distance.each_index do |k|
|
78
|
-
@distance.each_index do |i|
|
79
|
-
@distance.each_index do |j|
|
80
|
-
new_dist = @distance[i][k] + @distance[k][j]
|
81
|
-
if @distance[i][j] > new_dist
|
82
|
-
@distance[i][j] = new_dist
|
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
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
@distance
|
74
|
+
@distance = idistance.fw!(@path)
|
92
75
|
end
|
93
76
|
|
94
77
|
def mdistance
|
@@ -107,7 +90,7 @@ class Graph
|
|
107
90
|
distances
|
108
91
|
giant_component
|
109
92
|
|
110
|
-
nodes = giant ? @giant_component : @nodes
|
93
|
+
nodes = giant ? @giant_component : @nodes.values
|
111
94
|
|
112
95
|
0.upto(nodes.size - 1).each do |i|
|
113
96
|
(i + 1).upto(nodes.size - 1).each do |j|
|
@@ -119,7 +102,7 @@ class Graph
|
|
119
102
|
end
|
120
103
|
|
121
104
|
def shortest_path(i, j, multiples = false, giant = false)
|
122
|
-
nodes = giant ? @giant_component : @nodes
|
105
|
+
nodes = giant ? @giant_component : @nodes.values
|
123
106
|
|
124
107
|
return [] if @distance[i][j] == @infinity
|
125
108
|
|
@@ -204,7 +187,7 @@ class Graph
|
|
204
187
|
end
|
205
188
|
|
206
189
|
def clustering
|
207
|
-
nodes.map{ |node| single_clustering(node) }.inject(:+) / nodes.size.to_f
|
190
|
+
nodes.values.map{ |node| single_clustering(node) }.inject(:+) / nodes.size.to_f
|
208
191
|
end
|
209
192
|
|
210
193
|
def page_rank(d = 0.85, e = 0.01)
|
@@ -213,7 +196,7 @@ class Graph
|
|
213
196
|
#Initial values
|
214
197
|
@page_rank = Array.new(n, 1 / n.to_f)
|
215
198
|
|
216
|
-
|
199
|
+
loop do
|
217
200
|
return @page_rank if @page_rank.inject(:+) - step_page_rank(d, e).inject(:+) < e
|
218
201
|
end
|
219
202
|
end
|
@@ -225,7 +208,7 @@ class Graph
|
|
225
208
|
|
226
209
|
@distance.each do |d|
|
227
210
|
same = []
|
228
|
-
d.each_with_index { |dist, i| same << @nodes[i] if dist != @infinity}
|
211
|
+
d.each_with_index { |dist, i| same << @nodes.values[i] if dist != @infinity}
|
229
212
|
|
230
213
|
#its a new component
|
231
214
|
if @components.select{ |c| c.include?(same.first) }.size == 0
|
@@ -252,13 +235,13 @@ class Graph
|
|
252
235
|
n = @nodes.count
|
253
236
|
tmp = Array.new(n, 0)
|
254
237
|
|
255
|
-
@nodes.each_with_index do |node,i|
|
238
|
+
@nodes.values.each_with_index do |node,i|
|
256
239
|
#How much 'node' will give to its neighbours
|
257
240
|
to_neighbours = @page_rank[i] / node.neighbours.count
|
258
241
|
|
259
242
|
#Give 'to_neighbours' to each neighbour
|
260
243
|
node.neighbours.each do |ne|
|
261
|
-
j = @nodes.index(ne)
|
244
|
+
j = @nodes.values.index(ne)
|
262
245
|
tmp[j] += to_neighbours
|
263
246
|
end
|
264
247
|
end
|
@@ -268,12 +251,12 @@ class Graph
|
|
268
251
|
end
|
269
252
|
|
270
253
|
def get_node_by_id(node_id)
|
271
|
-
@nodes
|
254
|
+
@nodes[node_id]
|
272
255
|
end
|
273
256
|
|
274
257
|
def maybe_add_to_nodes(*nodes)
|
275
258
|
nodes.each do |node|
|
276
|
-
@nodes
|
259
|
+
@nodes[node[:id]] = node unless get_node_by_id(node[:id])
|
277
260
|
end
|
278
261
|
end
|
279
262
|
|
data/lib/rgraph/link.rb
CHANGED
@@ -1,25 +1,24 @@
|
|
1
1
|
class Link
|
2
2
|
attr_accessor :source, :target, :type
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
6
|
-
@source = @
|
7
|
-
@target = @
|
8
|
-
@type = @
|
4
|
+
def initialize(attributes)
|
5
|
+
@attributes = attributes
|
6
|
+
@source = @attributes.delete(:source)
|
7
|
+
@target = @attributes.delete(:target)
|
8
|
+
@type = @attributes.delete(:type) || 'undirected'
|
9
9
|
|
10
10
|
raise Exception.new("source cant be nil") unless @source
|
11
11
|
raise Exception.new("target cant be nil") unless @target
|
12
12
|
raise Exception.new("source must be of type Node") unless @source.is_a? Node
|
13
13
|
raise Exception.new("target must be of type Node") unless @target.is_a? Node
|
14
14
|
|
15
|
-
@
|
15
|
+
@attributes[:weight] ||= 1
|
16
16
|
|
17
17
|
@source.neighbours << @target
|
18
18
|
@target.neighbours << @source unless @type == 'directed'
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
@args[name]
|
21
|
+
def [](attribute)
|
22
|
+
@attributes[attribute]
|
24
23
|
end
|
25
24
|
end
|
data/lib/rgraph/node.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class Node
|
2
2
|
attr_accessor :neighbours
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(attributes)
|
5
|
+
@attributes = attributes
|
6
6
|
@neighbours = []
|
7
7
|
end
|
8
8
|
|
@@ -14,8 +14,7 @@ class Node
|
|
14
14
|
@neighbours.include?(node)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
@args[name]
|
17
|
+
def [](attribute)
|
18
|
+
@attributes[attribute]
|
20
19
|
end
|
21
20
|
end
|
data/lib/rgraph/version.rb
CHANGED
data/rgraph.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'rgraph/version'
|
@@ -6,19 +5,22 @@ require 'rgraph/version'
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
6
|
spec.name = "rgraph"
|
8
7
|
spec.version = Rgraph::VERSION
|
9
|
-
spec.authors = ["
|
10
|
-
spec.email = ["
|
8
|
+
spec.authors = ["Michel Boaventura"]
|
9
|
+
spec.email = ["michel@michelboaventura.com"]
|
11
10
|
spec.description = "Ruby's Graph Library"
|
12
11
|
spec.summary = "A Ruby's Graph Library"
|
13
|
-
spec.homepage = "http://github.com/
|
12
|
+
spec.homepage = "http://github.com/michelboaventura/rgraph"
|
14
13
|
spec.license = "MIT"
|
15
14
|
|
16
15
|
spec.files = `git ls-files`.split($/)
|
17
16
|
spec.test_files = spec.files.grep(%r{^spec/})
|
18
17
|
spec.require_paths = ["lib"]
|
19
18
|
|
20
|
-
spec.
|
21
|
-
|
22
|
-
spec.add_development_dependency "
|
23
|
-
spec.add_development_dependency "
|
19
|
+
spec.extensions = %w[ext/fw/extconf.rb]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7.3"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.3.2"
|
23
|
+
spec.add_development_dependency "rake-compiler", "~> 0.9.3"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.1.0"
|
25
|
+
spec.add_development_dependency "guard-rspec", "~> 4.3.1"
|
24
26
|
end
|
data/spec/rgraph/graph_spec.rb
CHANGED
@@ -11,8 +11,8 @@ describe Graph do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "creates all neighbours" do
|
14
|
-
nodes = subject.nodes[1..-1]
|
15
|
-
expect(subject.nodes.first.neighbours).to eq(nodes)
|
14
|
+
nodes = subject.nodes.values[1..-1]
|
15
|
+
expect(subject.nodes.values.first.neighbours).to eq(nodes)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "creates three links" do
|
@@ -20,9 +20,9 @@ describe Graph do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "gets all nodes one by one" do
|
23
|
-
nodes =
|
23
|
+
nodes = {}
|
24
24
|
subject.each_node do |node|
|
25
|
-
nodes
|
25
|
+
nodes[node[:id]] = node
|
26
26
|
end
|
27
27
|
expect(subject.nodes).to eq(nodes)
|
28
28
|
end
|
@@ -47,13 +47,13 @@ describe Graph do
|
|
47
47
|
|
48
48
|
it "understands directed graph" do
|
49
49
|
graph = Graph.new_from_string("source,target,type\n1,2,directed")
|
50
|
-
expect(graph.nodes.first.neighbours.count).to eq(1)
|
51
|
-
expect(graph.nodes.last.neighbours.count).to eq(0)
|
50
|
+
expect(graph.nodes.values.first.neighbours.count).to eq(1)
|
51
|
+
expect(graph.nodes.values.last.neighbours.count).to eq(0)
|
52
52
|
expect(graph.links.count).to eq(1)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
describe "
|
56
|
+
describe "Degree" do
|
57
57
|
subject { Graph.new('spec/fixtures/three_links.csv') }
|
58
58
|
|
59
59
|
it "sets default infinity to 100_000" do
|
@@ -77,22 +77,22 @@ describe Graph do
|
|
77
77
|
it "calculates the initial distance matrix" do
|
78
78
|
k = subject.infinity
|
79
79
|
expect(subject.idistance).to eq(
|
80
|
-
[[0,1,k,k,
|
81
|
-
[1,0,1,
|
82
|
-
[
|
83
|
-
[k,k,
|
84
|
-
[
|
85
|
-
[k,k,k,1,
|
80
|
+
[[0,1,1,k,k,k],
|
81
|
+
[1,0,1,1,k,k],
|
82
|
+
[1,1,0,k,1,k],
|
83
|
+
[k,1,k,0,1,k],
|
84
|
+
[k,k,1,1,0,1],
|
85
|
+
[k,k,k,k,1,0]])
|
86
86
|
end
|
87
87
|
|
88
88
|
it "calculates distances" do
|
89
89
|
expect(subject.distances).to eq(
|
90
|
-
[[0,1,2,2,
|
91
|
-
[1,0,1,2,
|
92
|
-
[
|
93
|
-
[2,2,
|
94
|
-
[
|
95
|
-
[3,3,2,1,
|
90
|
+
[[0,1,1,2,2,3],
|
91
|
+
[1,0,1,1,2,3],
|
92
|
+
[1,1,0,2,1,2],
|
93
|
+
[2,1,2,0,1,2],
|
94
|
+
[2,2,1,1,0,1],
|
95
|
+
[3,3,2,2,1,0]])
|
96
96
|
end
|
97
97
|
|
98
98
|
it "calculates the mean distance" do
|
@@ -139,25 +139,28 @@ describe Graph do
|
|
139
139
|
it "calculates the shortest paths" do
|
140
140
|
expect(subject.shortest_paths.sort).to eq(
|
141
141
|
[[0, 1],
|
142
|
-
[0, 1,
|
143
|
-
[0,
|
144
|
-
[0,
|
145
|
-
[0,
|
142
|
+
[0, 1, 3],
|
143
|
+
[0, 2],
|
144
|
+
[0, 2, 4],
|
145
|
+
[0, 2, 4, 5],
|
146
146
|
[1, 2],
|
147
|
-
[1, 2,
|
148
|
-
[1, 2,
|
149
|
-
[1,
|
150
|
-
[2, 1,
|
151
|
-
[2,
|
152
|
-
[2,
|
153
|
-
[3, 4],
|
154
|
-
[
|
147
|
+
[1, 2, 4],
|
148
|
+
[1, 2, 4, 5],
|
149
|
+
[1, 3],
|
150
|
+
[2, 1, 3],
|
151
|
+
[2, 4],
|
152
|
+
[2, 4, 5],
|
153
|
+
[3, 4],
|
154
|
+
[3, 4, 5],
|
155
|
+
[4, 5]].sort)
|
155
156
|
end
|
157
|
+
|
156
158
|
it "returns multiples short paths when asked" do
|
157
159
|
g = Graph.new_from_string("source,target\n1,2\n2,3\n1,4\n4,3")
|
158
160
|
expect(g.shortest_paths.count).to eq(6)
|
159
161
|
expect(g.shortest_paths(multiples: true).count).to eq(8)
|
160
162
|
end
|
163
|
+
|
161
164
|
it "calculates the betweenness of the giant component" do
|
162
165
|
g = Graph.new_from_string("source,target\n1,2\n2,3\n3,4\n5,6")
|
163
166
|
expect(g.between(0, giant: true)).to eq(0 / 6.0)
|
@@ -169,61 +172,82 @@ describe Graph do
|
|
169
172
|
expect(g.betweenness(giant: true)).to eq([0, 1 / 3.0, 1 / 3.0, 0, 0, 0])
|
170
173
|
end
|
171
174
|
|
175
|
+
#FIXME - should be 17!!!
|
172
176
|
it "calculates the betweenness of a single node" do
|
173
|
-
expect(subject.between(0)).to eq(0 /
|
174
|
-
expect(subject.between(1)).to eq(2 /
|
175
|
-
expect(subject.between(2)).to eq(
|
176
|
-
expect(subject.between(3)).to eq(
|
177
|
-
expect(subject.between(4)).to eq(
|
178
|
-
expect(subject.between(5)).to eq(0 /
|
177
|
+
expect(subject.between(0)).to eq(0 / 17.0)
|
178
|
+
expect(subject.between(1)).to eq(2 / 17.0)
|
179
|
+
expect(subject.between(2)).to eq(4 / 17.0)
|
180
|
+
expect(subject.between(3)).to eq(1 / 17.0)
|
181
|
+
expect(subject.between(4)).to eq(5 / 17.0)
|
182
|
+
expect(subject.between(5)).to eq(0 / 17.0)
|
179
183
|
end
|
184
|
+
|
180
185
|
it "calculates all betweenness" do
|
181
186
|
expect(subject.betweenness).to eq(
|
182
|
-
[0 /
|
183
|
-
2 /
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
0 /
|
187
|
+
[0 / 17.0,
|
188
|
+
2 / 17.0,
|
189
|
+
4 / 17.0,
|
190
|
+
1 / 17.0,
|
191
|
+
5 / 17.0,
|
192
|
+
0 / 17.0])
|
188
193
|
end
|
194
|
+
|
189
195
|
it "calculates all betweenness normalized" do
|
190
|
-
|
191
|
-
|
196
|
+
bts = subject.betweenness
|
197
|
+
min = bts.min
|
198
|
+
max = bts.max
|
199
|
+
|
200
|
+
bts.map!{|bt| (bt - min) / (max - min)}
|
201
|
+
|
202
|
+
expect(subject.betweenness(normalized: true)).to eq(bts)
|
192
203
|
end
|
204
|
+
|
193
205
|
it "works with holes" do
|
194
206
|
g = Graph.new_from_string("source,target\n1,2\n3,4")
|
195
207
|
expect(g.betweenness.inject(:+)).to eq(0)
|
196
208
|
end
|
209
|
+
|
197
210
|
it "calculates cumulative betweenness" do
|
198
|
-
|
211
|
+
bts = subject.betweenness(normalized: true)
|
212
|
+
|
213
|
+
bts = bts.uniq.sort.map{ |bt1| [bts.select{|bt2| bt2 >= bt1}.count, bt1] }
|
214
|
+
|
215
|
+
expect(subject.betweenness(cumulative: true)).to eq(bts)
|
199
216
|
end
|
217
|
+
|
200
218
|
it "calculates diameter" do
|
201
219
|
expect(subject.diameter).to eq(3)
|
202
220
|
end
|
221
|
+
|
203
222
|
it "calculates farness" do
|
204
|
-
expect(subject.farness).to eq([9,8,8,7,
|
223
|
+
expect(subject.farness).to eq([9,8,7,8,7,11])
|
205
224
|
end
|
225
|
+
|
206
226
|
it "calculates closeness" do
|
207
|
-
expect(subject.closeness).to eq([1/9.0,1/8.0,1/
|
227
|
+
expect(subject.closeness).to eq([1/9.0,1/8.0,1/7.0,1/8.0,1/7.0,1/11.0])
|
208
228
|
end
|
229
|
+
|
209
230
|
it "returns the graph's components" do
|
210
231
|
g = Graph.new_from_string("source,target\n1,2\n3,4")
|
211
|
-
expect(g.components).to eq([g.nodes[0..1], g.nodes[2..3]])
|
232
|
+
expect(g.components).to eq([g.nodes.values[0..1], g.nodes.values[2..3]])
|
212
233
|
end
|
234
|
+
|
213
235
|
it "sets the giant component" do
|
214
236
|
g = Graph.new_from_string("source,target\n1,2\n2,3\n4,5")
|
215
237
|
expect(g.giant_component.size).to eq(3)
|
216
238
|
end
|
239
|
+
|
217
240
|
it "calculates clustering of a single node" do
|
218
|
-
nodes = subject.nodes.
|
241
|
+
nodes = subject.nodes.values
|
219
242
|
|
220
243
|
expect(subject.single_clustering(nodes[0])).to eq(1.0/1.0)
|
221
244
|
expect(subject.single_clustering(nodes[1])).to eq(1.0/3.0)
|
222
|
-
expect(subject.single_clustering(nodes[2])).to eq(
|
223
|
-
expect(subject.single_clustering(nodes[3])).to eq(0.0/
|
224
|
-
expect(subject.single_clustering(nodes[4])).to eq(
|
245
|
+
expect(subject.single_clustering(nodes[2])).to eq(1.0/3.0)
|
246
|
+
expect(subject.single_clustering(nodes[3])).to eq(0.0/1.0)
|
247
|
+
expect(subject.single_clustering(nodes[4])).to eq(0.0/3.0)
|
225
248
|
expect(subject.single_clustering(nodes[5])).to eq(0.0/1.0)
|
226
249
|
end
|
250
|
+
|
227
251
|
it "calculates clustering of all nodes" do
|
228
252
|
expect(subject.clustering).to eq((1.0/1.0 + 2.0/3.0) / 6.0)
|
229
253
|
end
|
@@ -233,11 +257,13 @@ describe Graph do
|
|
233
257
|
pr = Graph.new_from_string("source,target,type\n1,2,directed").page_rank
|
234
258
|
expect(pr.first).to be < pr.last
|
235
259
|
end
|
260
|
+
|
236
261
|
it "calculates with three nodes within a line" do
|
237
262
|
pr = Graph.new_from_string("source,target,type\n1,2,directed\n2,3,directed").page_rank
|
238
263
|
expect(pr[0]).to be < pr[1]
|
239
264
|
expect(pr[1]).to be < pr[2]
|
240
265
|
end
|
266
|
+
|
241
267
|
it "calculates with two nodes pointing to the same" do
|
242
268
|
pr = Graph.new_from_string("source,target,type\n1,2,directed\n3,2,directed").page_rank
|
243
269
|
expect(pr[0]).to be < pr[1]
|
@@ -251,6 +277,7 @@ describe Graph do
|
|
251
277
|
expect(pr[1]).to eq(pr[2])
|
252
278
|
expect(pr.inject(:+)).to eq(1)
|
253
279
|
end
|
280
|
+
|
254
281
|
it "calculates with two subgraphs" do
|
255
282
|
pr = Graph.new_from_string("source,target,type\n1,2,directed\n3,4,directed\n3,1,directed").page_rank
|
256
283
|
expect(pr[0]).to be < pr[1]
|
data/spec/rgraph/link_spec.rb
CHANGED
@@ -5,10 +5,13 @@ require_relative '../../lib/rgraph/node'
|
|
5
5
|
describe Link do
|
6
6
|
describe "creates a link without a weight" do
|
7
7
|
subject { Link.new(source: Node.new(id: 1), target: Node.new(id: 2), years: [2011, 2012]) }
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
|
9
|
+
it "returns its attributes" do
|
10
|
+
expect(subject.source).to be_kind_of(Node)
|
11
|
+
expect(subject.target).to be_kind_of(Node)
|
12
|
+
expect(subject[:weight]).to eq(1)
|
13
|
+
expect(subject[:years]).to eq([2011,2012])
|
14
|
+
end
|
12
15
|
|
13
16
|
it "checks the creation of neighbours" do
|
14
17
|
expect(subject.source.neighbours).to eq([subject.target])
|
@@ -23,10 +26,9 @@ describe Link do
|
|
23
26
|
|
24
27
|
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
it "creates a link passing a weight" do
|
30
|
+
link = Link.new(source: Node.new(id: 00001), target: Node.new(id: 00002), weight: 4, years: [2011, 2012])
|
31
|
+
expect(link[:weight]).to eq(4)
|
30
32
|
end
|
31
33
|
|
32
34
|
it "doesn't create a link without source" do
|
data/spec/rgraph/node_spec.rb
CHANGED
@@ -2,22 +2,24 @@ require_relative '../../lib/rgraph/node'
|
|
2
2
|
|
3
3
|
describe Node do
|
4
4
|
subject { Node.new(name: "Lucas", id: '1', age: 20) }
|
5
|
-
describe "#new" do
|
6
|
-
its(:name) { should eq "Lucas" }
|
7
|
-
its(:id) { should eq '1' }
|
8
|
-
its(:age) { should eq 20 }
|
9
|
-
end
|
10
5
|
|
11
|
-
|
12
|
-
|
6
|
+
context "#new" do
|
7
|
+
it "returns its attributes" do
|
8
|
+
expect(subject[:name]).to eq("Lucas")
|
9
|
+
expect(subject[:id]).to eq('1')
|
10
|
+
expect(subject[:age]).to eq(20)
|
11
|
+
end
|
12
|
+
it "knows it degree" do
|
13
|
+
expect(subject.degree).to eq(0)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
|
-
|
17
|
+
context "#has_neighbour" do
|
16
18
|
it "recognizes its neighbour" do
|
17
19
|
n1 = Node.new(id: 1)
|
18
20
|
n2 = Node.new(id: 1)
|
19
21
|
n1.neighbours << n2
|
20
|
-
expect(n1.has_neighbour?(n2)).to
|
22
|
+
expect(n1.has_neighbour?(n2)).to be true
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
metadata
CHANGED
@@ -1,89 +1,104 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Lucas Aride Moulin
|
8
7
|
- Michel Boaventura
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-09-18 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
|
-
- - ~>
|
17
|
+
- - "~>"
|
19
18
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
19
|
+
version: 1.7.3
|
21
20
|
type: :development
|
22
21
|
prerelease: false
|
23
22
|
version_requirements: !ruby/object:Gem::Requirement
|
24
23
|
requirements:
|
25
|
-
- - ~>
|
24
|
+
- - "~>"
|
26
25
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
26
|
+
version: 1.7.3
|
28
27
|
- !ruby/object:Gem::Dependency
|
29
28
|
name: rake
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
|
-
- -
|
31
|
+
- - "~>"
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
33
|
+
version: 10.3.2
|
35
34
|
type: :development
|
36
35
|
prerelease: false
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
|
-
- -
|
38
|
+
- - "~>"
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
40
|
+
version: 10.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.3
|
42
55
|
- !ruby/object:Gem::Dependency
|
43
56
|
name: rspec
|
44
57
|
requirement: !ruby/object:Gem::Requirement
|
45
58
|
requirements:
|
46
|
-
- - ~>
|
59
|
+
- - "~>"
|
47
60
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
61
|
+
version: 3.1.0
|
49
62
|
type: :development
|
50
63
|
prerelease: false
|
51
64
|
version_requirements: !ruby/object:Gem::Requirement
|
52
65
|
requirements:
|
53
|
-
- - ~>
|
66
|
+
- - "~>"
|
54
67
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
68
|
+
version: 3.1.0
|
56
69
|
- !ruby/object:Gem::Dependency
|
57
70
|
name: guard-rspec
|
58
71
|
requirement: !ruby/object:Gem::Requirement
|
59
72
|
requirements:
|
60
|
-
- - ~>
|
73
|
+
- - "~>"
|
61
74
|
- !ruby/object:Gem::Version
|
62
|
-
version: 3.
|
75
|
+
version: 4.3.1
|
63
76
|
type: :development
|
64
77
|
prerelease: false
|
65
78
|
version_requirements: !ruby/object:Gem::Requirement
|
66
79
|
requirements:
|
67
|
-
- - ~>
|
80
|
+
- - "~>"
|
68
81
|
- !ruby/object:Gem::Version
|
69
|
-
version: 3.
|
82
|
+
version: 4.3.1
|
70
83
|
description: Ruby's Graph Library
|
71
84
|
email:
|
72
|
-
- aride.moulin@gmail.com
|
73
85
|
- michel@michelboaventura.com
|
74
86
|
executables: []
|
75
|
-
extensions:
|
87
|
+
extensions:
|
88
|
+
- ext/fw/extconf.rb
|
76
89
|
extra_rdoc_files: []
|
77
90
|
files:
|
78
|
-
- .gitignore
|
79
|
-
- .rspec
|
80
|
-
- .travis.yml
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
81
94
|
- Gemfile
|
82
95
|
- Guardfile
|
83
96
|
- LICENSE
|
84
97
|
- README.md
|
85
98
|
- Rakefile
|
86
99
|
- bin/guard
|
100
|
+
- ext/fw/extconf.rb
|
101
|
+
- ext/fw/fw.c
|
87
102
|
- lib/rgraph.rb
|
88
103
|
- lib/rgraph/graph.rb
|
89
104
|
- lib/rgraph/link.rb
|
@@ -100,7 +115,7 @@ files:
|
|
100
115
|
- spec/rgraph/node_spec.rb
|
101
116
|
- spec/rgraph/rgraph_spec.rb
|
102
117
|
- spec/spec_helper.rb
|
103
|
-
homepage: http://github.com/
|
118
|
+
homepage: http://github.com/michelboaventura/rgraph
|
104
119
|
licenses:
|
105
120
|
- MIT
|
106
121
|
metadata: {}
|
@@ -110,17 +125,17 @@ require_paths:
|
|
110
125
|
- lib
|
111
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
112
127
|
requirements:
|
113
|
-
- -
|
128
|
+
- - ">="
|
114
129
|
- !ruby/object:Gem::Version
|
115
130
|
version: '0'
|
116
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
132
|
requirements:
|
118
|
-
- -
|
133
|
+
- - ">="
|
119
134
|
- !ruby/object:Gem::Version
|
120
135
|
version: '0'
|
121
136
|
requirements: []
|
122
137
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.4.1
|
124
139
|
signing_key:
|
125
140
|
specification_version: 4
|
126
141
|
summary: A Ruby's Graph Library
|