rgraph 0.0.15 → 0.1.1
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/.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
|