find_communities 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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