find_communities 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f4baabfdcee6316ce51e6f68b4535e15ce0ecba2
4
+ data.tar.gz: 160f7bbd40b8bbde535ff26d11df977cf5c34f55
5
+ SHA512:
6
+ metadata.gz: bd8a31638591661e62877c976c3c4be5835efa0781582897c7df3352f91e33c48c936e7b2fd0357a9d6d09cf5a1a35e41be9169d2eb93a978d1ed8c437317683
7
+ data.tar.gz: 507a858459bc54620e901390dd892069ea838f81159f073483565af48f2824b36244c8b27fda1adaa8985f3bfa31d8ba8782a0ff33997f00ef4dd46630690212
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-version
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ script: rspec
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rspec'
6
+ gem 'rspec-retry'
7
+ gem 'pry'
8
+ gem 'pry-nav'
@@ -0,0 +1,82 @@
1
+ # find_communities-ruby
2
+
3
+ Ruby implementation of [Louvain community detection method](https://sites.google.com/site/findcommunities/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'find_communities-ruby'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install find_communities-ruby
18
+
19
+ ## Usage
20
+
21
+ $ community -l -1 karate.bin
22
+ 0 2
23
+ 1 0
24
+ 2 0
25
+ 3 0
26
+ 4 0
27
+ 5 1
28
+ 6 3
29
+ 7 3
30
+ 8 0
31
+ 9 5
32
+ 10 0
33
+ 11 1
34
+ 12 0
35
+ 13 0
36
+ 14 0
37
+ 15 2
38
+ 16 2
39
+ 17 3
40
+ 18 0
41
+ 19 2
42
+ 20 0
43
+ 21 2
44
+ 22 0
45
+ 23 2
46
+ 24 2
47
+ 25 4
48
+ 26 4
49
+ 27 2
50
+ 28 2
51
+ 29 4
52
+ 30 2
53
+ 31 5
54
+ 32 4
55
+ 33 2
56
+ 0 0
57
+ 1 1
58
+ 2 3
59
+ 3 1
60
+ 4 2
61
+ 5 3
62
+ 0 0
63
+ 1 1
64
+ 2 2
65
+ 3 3
66
+ 0.426969
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
75
+
76
+ ## CI
77
+
78
+ [![Build Status](https://secure.travis-ci.org/gkop/find_communities-ruby.png?branch=master)](http://travis-ci.org/gkop/find_communities-ruby)
79
+
80
+ ## License
81
+
82
+ Released under the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0-standalone.html).
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require File.dirname(__FILE__)+"/../lib/find_communities"
5
+
6
+ class CommunityMain < Thor
7
+ method_option :level, :aliases => "-l", :desc => "displays the graph of level k rather than the hierachical structure. if k=-1 then displays the hierarchical structure rather than the graph at a given level"
8
+ method_option :verbose, :aliases => "-v", :desc => "verbose mode: gives computation time, information about the hierarchy and modularity."
9
+
10
+ desc "community", "Decompose graph into communities"
11
+ argument :filename
12
+ def community
13
+ t0 = Time.now
14
+ verbose = options[:verbose]
15
+ puts "Begin: #{t0}" if verbose
16
+ precision = 0.000001
17
+ c = FindCommunities::Community.new(filename, -1, precision)
18
+ display_level = options[:level].to_i
19
+ level = 0
20
+ g = nil
21
+ improvement = true
22
+ mod = c.modularity
23
+
24
+ while improvement do
25
+ if verbose
26
+ puts "level #{level}:"
27
+ puts " start computation #{Time.now}"
28
+ puts " network size: #{c.g.nb_nodes} nodes, #{c.g.nb_links} links, #{c.g.total_weight} weight."
29
+ end
30
+ improvement = c.one_level
31
+ new_mod = c.modularity
32
+ level += 1
33
+ g.display if level == display_level && g
34
+ c.display_partition if display_level == -1
35
+ g = c.partition2graph_binary
36
+ c = FindCommunities::Community.new(g, -1, precision)
37
+
38
+ if verbose
39
+ puts " modularity increased from #{"%.6f" % mod} to #{"%.6f" % new_mod}"
40
+ puts " end computation #{Time.now}"
41
+ end
42
+ mod = new_mod
43
+ improvement = true if level == 1
44
+ end
45
+
46
+ if verbose
47
+ puts "End: #{Time.now}"
48
+ puts "Total duration: #{Time.now - t0} sec."
49
+ end
50
+ puts "%.6f" % new_mod
51
+ end
52
+
53
+ default_task :community
54
+ end
55
+
56
+ CommunityMain.start
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'find_communities/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "find_communities"
8
+ gem.version = FindCommunities::VERSION
9
+ gem.authors = ["Gabe Kopley"]
10
+ gem.email = ["gabe@coshx.com"]
11
+ gem.description = %q{Ruby implementation of Louvain community detection method}
12
+ gem.summary = %q{Ruby implementation of Louvain community detection method}
13
+ gem.homepage = "https://github.com/gkop/find_communities-ruby"
14
+ gem.license = "GPL"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ gem.add_dependency "bindata"
21
+ gem.add_dependency "thor"
22
+ end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) + '/find_communities/*.rb'].each {|f| require f }
@@ -0,0 +1,72 @@
1
+ module FindCommunities
2
+ class BinaryGraph
3
+ attr_accessor :degrees, :nb_nodes, :nb_links, :total_weight
4
+ attr_reader :links, :weights
5
+
6
+ def initialize(filename=nil, type=nil)
7
+ if filename
8
+ @record = BinaryGraphRecord.read(open(filename, "rb"))
9
+ @nb_nodes = @record["nb_nodes"]
10
+ @degrees = @record["degrees"]
11
+ @links = @record["links"]
12
+ @nb_links = @links.count
13
+ else
14
+ @nb_nodes = 0
15
+ @nb_links = 0
16
+ @links = []
17
+ end
18
+ @weights = []
19
+ @total_weight = nb_nodes.times.inject(0.0) {|sum, node|
20
+ sum + weighted_degree(node)
21
+ }
22
+ end
23
+
24
+ def nb_neighbors(node)
25
+ check_node(node)
26
+ node == 0 ? degrees[0] : degrees[node] - degrees[node-1]
27
+ end
28
+
29
+ def nb_selfloops(node)
30
+ check_node(node)
31
+ p = neighbors(node)
32
+ nb_neighbors(node).times do |i|
33
+ if p.first[i] == node
34
+ return weights.any? ? p.last[i] : 1.0
35
+ end
36
+ end
37
+ 0.0
38
+ end
39
+
40
+ def neighbors(node)
41
+ check_node(node)
42
+ if node == 0
43
+ [links, weights]
44
+ elsif weights.length > 0
45
+ [links[degrees[node-1], links.length],
46
+ weights[degrees[node-1], weights.length]]
47
+ else
48
+ [links[degrees[node-1], links.length], weights]
49
+ end
50
+ end
51
+
52
+ def weighted_degree(node)
53
+ check_node(node)
54
+ if weights.length == 0
55
+ nb_neighbors(node)
56
+ else
57
+ p = neighbors(node)
58
+ nb_neighbors(node).times.inject(0.0) { |sum, neighbor|
59
+ sum + p.last[neighbor]
60
+ }
61
+ end
62
+ end
63
+
64
+ private
65
+ def check_node(node)
66
+ if node < 0 || node >= nb_nodes
67
+ raise ArgumentError.new("Node index out of bounds: #{node}")
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ require 'bindata'
2
+
3
+ # binary file format is
4
+ # 4 bytes for the number of nodes in the graph
5
+ # 8*(nb_nodes) bytes for the cumulative degree for each node:
6
+ # deg(0)=degrees[0]
7
+ # deg(k)=degrees[k]-degrees[k-1]
8
+ # 4*(sum_degrees) bytes for the links
9
+ # IF WEIGHTED 4*(sum_degrees) bytes for the weights in a separate file
10
+
11
+ module FindCommunities
12
+ class BinaryGraphRecord < BinData::Record
13
+ endian :little
14
+ uint32 :nb_nodes
15
+ array :degrees, :type => :uint64, :initial_length => :nb_nodes
16
+ array :links, :type => :uint32, :initial_length => lambda { degrees.last }
17
+ end
18
+ end
@@ -0,0 +1,240 @@
1
+ require "securerandom"
2
+
3
+ module FindCommunities
4
+ class Community
5
+ attr_accessor :neigh_weight, :neigh_pos, :neigh_last
6
+
7
+ attr_accessor :g # network to compute communities for
8
+ attr_accessor :size # nummber of nodes in the network and size of all vectors
9
+ attr_accessor :n2c # community to which each node belongs
10
+ attr_accessor :in_graph, :tot # used to compute the modularity participation
11
+ # of each community
12
+
13
+ # a new pass is computed if the last one has generated an increase
14
+ # greater than min_modularity
15
+ # if 0. even a minor increase is enough to go for one more pass
16
+ attr_accessor :min_modularity
17
+
18
+ def initialize(source, nbp=nil, minm=nil)
19
+ @g = source.is_a?(BinaryGraph) ? source : BinaryGraph.new(source)
20
+ @size = g.nb_nodes
21
+ @neigh_last = 0
22
+
23
+ @neigh_weight = size.times.map { -1 }
24
+ @neigh_pos = size.times.map { 0 }
25
+ @n2c = []
26
+ @in_graph = []
27
+ @tot = []
28
+ size.times do |i|
29
+ n2c[i] = i
30
+ tot[i] = g.weighted_degree(i)
31
+ in_graph[i] = g.nb_selfloops(i)
32
+ end
33
+ @min_modularity = minm
34
+ end
35
+
36
+ def one_level
37
+ improvement = false
38
+ nb_pass_done = 0
39
+ new_mod = modularity
40
+ cur_mod = new_mod
41
+ random_order = size.times.map { |i| i }
42
+ (size-1).times do |i|
43
+ rand_pos = SecureRandom.random_number(size-i) + i
44
+ tmp = random_order[i]
45
+ random_order[i] = random_order[rand_pos]
46
+ random_order[rand_pos] = tmp
47
+ end
48
+
49
+ begin
50
+ cur_mod = new_mod
51
+ nb_moves = 0
52
+ nb_pass_done += 1
53
+
54
+ size.times do |node_tmp|
55
+ node = random_order[node_tmp]
56
+ node_comm = n2c[node]
57
+ w_degree = g.weighted_degree(node)
58
+
59
+ # computation of all neighboring communities of current node
60
+ compute_neigh_comm(node)
61
+ # remove node from its current community
62
+ remove(node, node_comm, neigh_weight[node_comm])
63
+
64
+ # compute the nearest community for node
65
+ # default choice for future insertion is the former community
66
+ best_comm = node_comm
67
+ best_nblinks = 0.0
68
+ best_increase = 0.0
69
+
70
+ neigh_last.times do |i|
71
+ increase = modularity_gain(node, neigh_pos[i],
72
+ neigh_weight[neigh_pos[i]], w_degree)
73
+ if increase > best_increase
74
+ best_comm = neigh_pos[i]
75
+ best_nblinks = neigh_weight[neigh_pos[i]]
76
+ best_increase = increase
77
+ end
78
+ end
79
+
80
+ # insert node in the nearest community
81
+ insert(node, best_comm, best_nblinks)
82
+
83
+ nb_moves += 1 if best_comm != node_comm
84
+ end
85
+
86
+ new_mod = modularity
87
+ improvement = true if nb_moves > 0
88
+ end while nb_moves > 0 && (new_mod - cur_mod > min_modularity)
89
+
90
+ improvement
91
+ end
92
+
93
+ def display_partition
94
+ renumber = size.times.map { -1 }
95
+ size.times do |node|
96
+ renumber[n2c[node]] += 1
97
+ end
98
+
99
+ final = 0
100
+ size.times do |i|
101
+ if renumber[i] != -1
102
+ renumber[i] = final
103
+ final += 1
104
+ end
105
+ end
106
+
107
+ size.times do |i|
108
+ puts "#{i} #{renumber[n2c[i]]}"
109
+ end
110
+ end
111
+
112
+ def partition2graph_binary
113
+ renumber = size.times.map { -1 }
114
+ size.times do |node|
115
+ renumber[n2c[node]] += 1
116
+ end
117
+
118
+ final = 0
119
+ size.times do |i|
120
+ if renumber[i] != -1
121
+ renumber[i] = final
122
+ final += 1
123
+ end
124
+ end
125
+
126
+ # Compute communities
127
+ comm_nodes = final.times.map { [] }
128
+ size.times do |node|
129
+ comm_nodes[renumber[n2c[node]]].push(node)
130
+ end
131
+
132
+ # Compute weighted graph
133
+ g2 = BinaryGraph.new
134
+ g2.nb_nodes = comm_nodes.size
135
+ g2.degrees = comm_nodes.size.times.map { 0 }
136
+
137
+ comm_nodes.size.times do |comm|
138
+ m = {}
139
+
140
+ comm_size = comm_nodes[comm].size
141
+ comm_size.times do |node|
142
+ p = g.neighbors(comm_nodes[comm][node])
143
+ deg = g.nb_neighbors(comm_nodes[comm][node])
144
+ deg.times do |i|
145
+ neigh = p.first[i]
146
+ neigh_comm = renumber[n2c[neigh]]
147
+ local_neigh_weight = (g.weights.size == 0 ? 1.0 : p.last[i])
148
+
149
+ if m[neigh_comm]
150
+ m[neigh_comm][1] += local_neigh_weight
151
+ else
152
+ m[neigh_comm] = [neigh_comm, local_neigh_weight]
153
+ end
154
+ end
155
+ end
156
+ g2.degrees[comm] = m.to_a.size + (comm == 0 ? 0 : g2.degrees[comm - 1])
157
+ g2.nb_links += m.to_a.size
158
+
159
+ m.each do |key, value|
160
+ g2.total_weight += value[1]
161
+ g2.links.push(value[0])
162
+ g2.weights.push(value[1])
163
+ end
164
+ end
165
+ g2
166
+ end
167
+
168
+ def modularity
169
+ q = 0.0
170
+ m2 = g.total_weight
171
+ size.times do |i|
172
+ if tot[i] > 0
173
+ q += (in_graph[i] / m2 - (tot[i] / m2)**2)
174
+ end
175
+ end
176
+
177
+ q
178
+ end
179
+
180
+ private
181
+ def check_node(node)
182
+ if node < 0 || node >= size
183
+ raise ArgumentError.new("Node index out of bounds: #{node}")
184
+ end
185
+ end
186
+
187
+ def insert(node, comm, dnodecomm)
188
+ check_node(node)
189
+
190
+ tot[comm] += g.weighted_degree(node)
191
+ in_graph[comm] += 2 * dnodecomm + g.nb_selfloops(node)
192
+ n2c[node] = comm
193
+ end
194
+
195
+ def modularity_gain(node, comm, dnodecomm, w_degree)
196
+ check_node(node)
197
+
198
+ totc = tot[comm]
199
+ degc = w_degree
200
+ m2 = g.total_weight
201
+
202
+ dnodecomm - ((totc.to_f * degc) / m2)
203
+ end
204
+
205
+ def compute_neigh_comm(node)
206
+ neigh_last.times { |i| neigh_weight[neigh_pos[i]] = -1 }
207
+
208
+ p = g.neighbors(node)
209
+
210
+ deg = g.nb_neighbors(node)
211
+
212
+ neigh_pos[0] = n2c[node]
213
+ neigh_weight[neigh_pos[0]] = 0
214
+ self.neigh_last = 1
215
+
216
+ deg.times do |i|
217
+ neigh = p.first[i]
218
+ neigh_comm = n2c[neigh]
219
+ neigh_w = (g.weights.size == 0 ? 1.0 : p.last[i])
220
+
221
+ if neigh != node
222
+ if neigh_weight[neigh_comm] == -1
223
+ neigh_weight[neigh_comm] = 0.0
224
+ neigh_pos[neigh_last] = neigh_comm
225
+ self.neigh_last += 1
226
+ end
227
+ neigh_weight[neigh_comm] += neigh_w
228
+ end
229
+ end
230
+ end
231
+
232
+ def remove(node, comm, dnodecomm)
233
+ check_node(node)
234
+
235
+ tot[comm] -= g.weighted_degree(node)
236
+ in_graph[comm] -= 2 * dnodecomm + g.nb_selfloops(node)
237
+ n2c[node] = -1
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,22 @@
1
+ module FindCommunities
2
+ class Graph
3
+ def initialize(file, type=nil)
4
+ weight = 1.0
5
+ links = []
6
+
7
+ nb_links = file.count
8
+ file.each do |line|
9
+ pieces = line.split
10
+ src = pieces[0].to_i
11
+ dest = pieces[1].to_i
12
+ weight = pieces[2].to_f if type == :weighted
13
+ links[src] ||= []
14
+ links[src] << [dest, weight]
15
+ if src != dest
16
+ links[dest] ||= []
17
+ links[dest] ||= [src, weight]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module FindCommunities
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe "community (executable)" do
4
+ it "outputs a hierarchy", :retry => 3 do
5
+ filename = File.dirname(__FILE__) + "/../data/karate.bin"
6
+ run "community -l -1 #{filename}"
7
+ relevant_lines = out.split("\n").last(4)
8
+ relevant_lines[0].should == "1 1"
9
+ relevant_lines[1].should == "2 2"
10
+ relevant_lines[2].should == "3 3"
11
+ relevant_lines[3].to_f.round(1).should == 0.4
12
+ end
13
+ end
Binary file
@@ -0,0 +1,44 @@
1
+ 0 5
2
+ 1 1
3
+ 2 1
4
+ 3 1
5
+ 4 1
6
+ 5 0
7
+ 6 2
8
+ 7 2
9
+ 8 1
10
+ 9 5
11
+ 10 5
12
+ 11 0
13
+ 12 1
14
+ 13 1
15
+ 14 1
16
+ 15 5
17
+ 16 5
18
+ 17 2
19
+ 18 1
20
+ 19 5
21
+ 20 1
22
+ 21 5
23
+ 22 1
24
+ 23 5
25
+ 24 4
26
+ 25 3
27
+ 26 3
28
+ 27 4
29
+ 28 4
30
+ 29 3
31
+ 30 4
32
+ 31 5
33
+ 32 3
34
+ 33 5
35
+ 0 1
36
+ 1 0
37
+ 2 1
38
+ 3 2
39
+ 4 3
40
+ 5 3
41
+ 0 0
42
+ 1 1
43
+ 2 2
44
+ 3 3
@@ -0,0 +1,9 @@
1
+ module Spec
2
+ module Helpers
3
+ attr_reader :out
4
+
5
+ def run(command)
6
+ @out = `#{File.dirname(__FILE__)}/../bin/#{command}`
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ include FindCommunities
3
+
4
+ describe BinaryGraph do
5
+ it "can read a file" do
6
+ filename = File.dirname(__FILE__) + "/../data/karate.bin"
7
+ bg = BinaryGraph.new(filename)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ include FindCommunities
3
+
4
+ describe Community do
5
+ it "can be initialized from a filename" do
6
+ filename = File.dirname(__FILE__) + "/../data/karate.bin"
7
+ c = Community.new(filename)
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ require 'find_communities'
2
+ require 'pry'
3
+ require 'pry-nav'
4
+ require 'helpers'
5
+ require 'rspec/retry'
6
+
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # Require this file using `require "spec_helper"` to ensure that it is only
10
+ # loaded once.
11
+ #
12
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+
18
+ # Run specs in random order to surface order dependencies. If you find an
19
+ # order dependency and want to debug it, you can fix the order by providing
20
+ # the seed, which is printed after each run.
21
+ # --seed 1234
22
+ config.order = 'random'
23
+ config.include Spec::Helpers
24
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: find_communities
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gabe Kopley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bindata
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Ruby implementation of Louvain community detection method
42
+ email:
43
+ - gabe@coshx.com
44
+ executables:
45
+ - community
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - .travis.yml
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/community
55
+ - find_communities.gemspec
56
+ - lib/find_communities.rb
57
+ - lib/find_communities/binary_graph.rb
58
+ - lib/find_communities/binary_graph_record.rb
59
+ - lib/find_communities/community.rb
60
+ - lib/find_communities/graph.rb
61
+ - lib/find_communities/version.rb
62
+ - spec/bin/community_spec.rb
63
+ - spec/data/karate.bin
64
+ - spec/data/karate.tree
65
+ - spec/helpers.rb
66
+ - spec/lib/binary_graph_spec.rb
67
+ - spec/lib/community_spec.rb
68
+ - spec/spec_helper.rb
69
+ homepage: https://github.com/gkop/find_communities-ruby
70
+ licenses:
71
+ - GPL
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.0.0
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Ruby implementation of Louvain community detection method
93
+ test_files:
94
+ - spec/bin/community_spec.rb
95
+ - spec/data/karate.bin
96
+ - spec/data/karate.tree
97
+ - spec/helpers.rb
98
+ - spec/lib/binary_graph_spec.rb
99
+ - spec/lib/community_spec.rb
100
+ - spec/spec_helper.rb