rcpm 0.1.0

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: 967d41e31aae19de32a51334c9791c7eaded9773
4
+ data.tar.gz: aac5b07ef54940bfbbf7cf4ad233e1c942532311
5
+ SHA512:
6
+ metadata.gz: 57699c6a3d6c2b2a91efb9ff404942edc60fabe87982b4aa58248469c38e96cc92a9366b5f0183bcc7ea163365cc03d666efc01175d673c7530897b51f5cd84b
7
+ data.tar.gz: f87f44a34a11a2eb2c22eb77997ec42feb07ac2488810cd683fc422d57d758e52c423ea2a670950d7100838b43694c2913f717611af1fa6cef7012f61789cbb0
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,30 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect
4
+ all people who contribute through reporting issues, posting feature
5
+ requests, updating documentation, submitting pull requests or patches,
6
+ and other activities.
7
+
8
+ We are committed to making participation in this project a
9
+ harassment-free experience for everyone, regardless of level of
10
+ experience, gender, gender identity and expression, sexual orientation,
11
+ disability, personal appearance, body size, race, age, or religion.
12
+
13
+ Examples of unacceptable behavior by participants include the use of
14
+ sexual language or imagery, derogatory comments or personal attacks,
15
+ trolling, public or private harassment, insults, or other unprofessional
16
+ conduct.
17
+
18
+ Project maintainers have the right and responsibility to remove, edit,
19
+ or reject comments, commits, code, wiki edits, issues, and other
20
+ contributions that are not aligned to this Code of Conduct. Project
21
+ maintainers who do not follow the Code of Conduct may be removed from
22
+ the project team.
23
+
24
+ Instances of abusive, harassing, or otherwise unacceptable behavior may
25
+ be reported by opening an issue or contacting one or more of the project
26
+ maintainers.
27
+
28
+ This Code of Conduct is adapted from the [Contributor
29
+ Covenant](http:contributor-covenant.org), version 1.0.0, available at
30
+ [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Michel Boaventura
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # Rcpm
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rcpm`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'rcpm'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install rcpm
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/rcpm/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+
4
+ Rake::ExtensionTask.new('bk')
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ task :default => [:compile]
9
+ task :test => [:compile]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rcpm"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,61 @@
1
+ #!/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'rcpm'
5
+ require 'csv'
6
+ require 'set'
7
+ require 'optparse'
8
+
9
+ options = { k: 0, file: "" }
10
+
11
+ optparse = OptionParser.new do |opts|
12
+ opts.banner = "Usage: rcpm -k K -f file1"
13
+
14
+ opts.on("-k K", Integer, "K value" ) do |k|
15
+ options[:k] = k
16
+ end
17
+
18
+ opts.on( "-f FILE", String, "File input" ) do |file|
19
+ options[:file] = file
20
+ end
21
+ end
22
+
23
+ begin
24
+ optparse.parse!
25
+ rescue OptionParser::MissingArgument
26
+ puts optparse
27
+ exit
28
+ end
29
+
30
+ if options[:k] <= 0
31
+ puts "Invalid K value #{options[:k]}"
32
+ puts optparse
33
+ exit
34
+ end
35
+
36
+ unless File.exist?(options[:file])
37
+ puts "File #{options[:file]} does not exist"
38
+ puts options
39
+ exit
40
+ end
41
+
42
+ code_to_id, graphs = RCPM.read_file(options[:file])
43
+ cpms_id = {}
44
+ cpms = {}
45
+
46
+ graphs.each_pair do |year, graph|
47
+ cpms_id[year] = RCPM.cpm(RCPM.graph_to_matrix(graph), options[:k])
48
+ end
49
+
50
+ cpms_id.each_pair do |year, cpm|
51
+ cpms[year] = cpm.map do |nodes|
52
+ Set.new(nodes.map { |node| code_to_id[year].key(node) })
53
+ end
54
+ end
55
+
56
+ cpms.each_pair do |year, cliques|
57
+ puts "Period: #{year}---------------"
58
+ cliques.each do |clique|
59
+ puts clique.to_a.join(",")
60
+ end
61
+ end
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,119 @@
1
+ #include <ruby.h>
2
+
3
+ void print_array(VALUE arr) {
4
+ printf("%s\n",RSTRING_PTR(rb_inspect(arr)));
5
+ }
6
+
7
+ void bkv2(VALUE m, VALUE old_set, int ne, int ce, VALUE cliques, VALUE potential_clique) {
8
+ VALUE new_set;
9
+
10
+ int nod, fixp, newne, newce, i, j, count, pos, p, s, sel, minnod;
11
+
12
+ new_set = rb_ary_new2(ce);
13
+ minnod = ce;
14
+ nod = 0;
15
+ fixp = 0;
16
+ pos = 0;
17
+ s = 0;
18
+
19
+ /* Determine each counter value and look for minimum */
20
+ for (i = 0 ; i < ce && minnod != 0; i++) {
21
+ p = NUM2INT(rb_ary_entry(old_set, i));
22
+ count = 0;
23
+
24
+ /* Count disconnections */
25
+ for (j = ne; j < ce && count < minnod; j++) {
26
+ if(!NUM2INT(rb_ary_entry(rb_ary_entry(m, p), NUM2INT(rb_ary_entry(old_set, j))))) {
27
+ count++;
28
+ /* Save position of potential candidate */
29
+ pos = j;
30
+ }
31
+ }
32
+
33
+ /* Test new minimum */
34
+ if (count < minnod) {
35
+ fixp = p;
36
+ minnod = count;
37
+
38
+ if (i < ne) {
39
+ s = pos;
40
+ }
41
+ else {
42
+ s = i;
43
+ /* pre-increment */
44
+ nod = 1;
45
+ }
46
+ }
47
+ }
48
+
49
+ /* If fixed point initially chosen from candidates then
50
+ number of diconnections will be preincreased by one */
51
+
52
+ /* Backtrackcycle */
53
+ for (nod=minnod+nod; nod>=1; nod--) {
54
+ /* Interchange */
55
+ p = NUM2INT(rb_ary_entry(old_set, s));
56
+ rb_ary_store(old_set, s, rb_ary_entry(old_set, ne));
57
+ sel = p;
58
+ rb_ary_store(old_set, ne, INT2NUM(sel));
59
+
60
+ /* Fill new set "not" */
61
+ newne = 0;
62
+ for (i = 0 ; i < ne ; i++) {
63
+ if(NUM2INT(rb_ary_entry(rb_ary_entry(m, sel), NUM2INT(rb_ary_entry(old_set, i))))) {
64
+ rb_ary_store(new_set, newne++, rb_ary_entry(old_set, i));
65
+ }
66
+ }
67
+
68
+ /*Fill new set "cand" */
69
+ newce = newne;
70
+ for (i=ne+1; i < ce; i++) {
71
+ if(NUM2INT(rb_ary_entry(rb_ary_entry(m, sel), NUM2INT(rb_ary_entry(old_set, i))))) {
72
+ rb_ary_store(new_set, newce++, rb_ary_entry(old_set, i));
73
+ }
74
+ }
75
+
76
+ rb_ary_push(potential_clique, INT2NUM(sel));
77
+
78
+ if (newce == 0) {
79
+ rb_ary_push(cliques, rb_ary_dup(potential_clique));
80
+ }
81
+ else if (newne < newce) {
82
+ bkv2(m, new_set, newne, newce, cliques, potential_clique);
83
+ }
84
+
85
+ rb_ary_pop(potential_clique);
86
+
87
+ /* Add to "not" */
88
+ ne++;
89
+ if (nod > 1) {
90
+ /* Select a candidate disconnected to the fixed point */
91
+
92
+ for(s = ne; NUM2INT((rb_ary_entry(rb_ary_entry(m, fixp), NUM2INT(rb_ary_entry(old_set, s))))); s++);
93
+ }
94
+
95
+ } /* Backtrackcycle */
96
+ }
97
+
98
+ static VALUE bk(VALUE arr) {
99
+ int i, n;
100
+ VALUE all, cliques, potential_clique;
101
+
102
+ n = RARRAY_LEN(arr);
103
+
104
+ all = rb_ary_new2(n);
105
+ potential_clique = rb_ary_new();
106
+ cliques = rb_ary_new();
107
+
108
+ for (i = 0; i < n; i++) {
109
+ rb_ary_push(all, INT2NUM(i));
110
+ }
111
+
112
+ bkv2(arr, all, 0, n, cliques, potential_clique);
113
+
114
+ return cliques;
115
+ }
116
+
117
+ void Init_bk() {
118
+ rb_define_method(rb_cArray, "bk", bk, 0);
119
+ }
@@ -0,0 +1,5 @@
1
+ require "mkmf"
2
+
3
+ $CFLAGS << ' -O3 -Wextra -Wall -pedantic -std=gnu99'
4
+
5
+ create_makefile "bk"
@@ -0,0 +1,119 @@
1
+ require "rcpm/version"
2
+ require 'bk'
3
+
4
+ module RCPM
5
+ def self.read_file(filename)
6
+ current_id = {}
7
+ code_to_id = {}
8
+ graphs = {}
9
+
10
+ CSV.open(filename, headers: [:id1, :id2, :year]).each do |line|
11
+ year = line[:year]
12
+
13
+ current_id[year] ||= -1
14
+ code_to_id[year] ||= {}
15
+ graphs[year] ||= []
16
+
17
+ id1 = code_to_id[year][line[:id1]] ||= current_id[year] += 1
18
+ id2 = code_to_id[year][line[:id2]] ||= current_id[year] += 1
19
+
20
+ graphs[year] << [id1,id2]
21
+ end
22
+
23
+ return [code_to_id, graphs]
24
+ end
25
+
26
+ def self.graph_to_matrix(ary)
27
+ max = ary.flatten.max
28
+
29
+ matrix = Array.new(max + 1) { Array.new(max + 1, 0) }
30
+
31
+ 0.upto(max - 1) { |i| matrix[i][i] = 1 }
32
+
33
+ ary.each do |n1, n2|
34
+ matrix[n1][n2] = 1
35
+ matrix[n2][n1] = 1
36
+ end
37
+
38
+ return matrix
39
+ end
40
+
41
+ def self.cpm(g, k)
42
+ cliques_to_components = {}
43
+ current_component = 0
44
+
45
+ cliques = g.bk.select{|cl| cl.size >= k}
46
+
47
+ nodes_to_cliques = nodes_to_cliques(cliques)
48
+
49
+ #Para cada uma das cliques
50
+ cliques.each do |clique|
51
+
52
+ #Se ela ainda não possui componente(não foi processada)
53
+ if !cliques_to_components.key?(clique)
54
+ current_component += 1
55
+ #Adiciona um novo componente para ela
56
+ cliques_to_components[clique] = current_component
57
+ #Coloca esta clique na fronteira
58
+ frontier = [clique]
59
+
60
+ #Enquanto fronteira não for vazia
61
+ while current_clique = frontier.pop
62
+ #Pega todas as cliques vizinhas de current_clique
63
+ get_adjacent_cliques(current_clique, nodes_to_cliques).each do |neighbour|
64
+ #Se neighbour tem uma interseção com current_clique de tamanho >= k - 1
65
+ if (current_clique & neighbour).size >= k - 1
66
+ #Então neighbour também faz parte de current_component
67
+ cliques_to_components[neighbour] = current_component
68
+ #Adiciona neighbour à frontier
69
+ frontier << neighbour
70
+ #E para cada node de neighbour
71
+ neighbour.each do |node|
72
+ #Remove ele da lista de nós não processados
73
+ nodes_to_cliques[node].delete(neighbour)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ #Agora basta unir todos os nós que foram rotulados com o mesmo componente
81
+ component_to_nodes = {}
82
+ cliques_to_components.each_pair do |clique, component_clique_in|
83
+ component_to_nodes[component_clique_in] ||= []
84
+ component_to_nodes[component_clique_in] += clique
85
+ end
86
+
87
+ return component_to_nodes.values
88
+ end
89
+
90
+ private
91
+
92
+ #Cria um hash do tipo node -> [cliques que contém node]
93
+ def self.nodes_to_cliques(cliques)
94
+ output = Hash.new {|h,k| h[k] = []}
95
+
96
+ cliques.each do |clique|
97
+ clique.each do |node|
98
+ output[node] << clique
99
+ end
100
+ end
101
+ return output
102
+ end
103
+
104
+ #Dado uma clique, retorna todas as outras adjacentes à ela. Duas cliques são
105
+ #adjacentes se elas compartilham ao menos um nó
106
+ def self.get_adjacent_cliques(clique, nodes_to_cliques)
107
+ adjacent_cliques = []
108
+
109
+ clique.each do |node|
110
+ nodes_to_cliques[node].each do |adj_clique|
111
+ if clique != adj_clique
112
+ adjacent_cliques << adj_clique
113
+ end
114
+ end
115
+ end
116
+ return adjacent_cliques
117
+ end
118
+
119
+ end
@@ -0,0 +1,3 @@
1
+ module RCPM
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'rcpm/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rcpm"
7
+ spec.version = RCPM::VERSION
8
+ spec.authors = ["Michel Boaventura"]
9
+ spec.email = ["michel.boaventura@gmail.com"]
10
+
11
+ spec.summary = %q{Ruby's implementation of Clique Percolation Method}
12
+ spec.homepage = "http://github.com/michelboaventura/rcpm"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.executables = ["rcpm"]
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.extensions = %w[ext/bk/extconf.rb]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.8"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rake-compiler", "~> 0.9"
24
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rcpm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michel Boaventura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
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'
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'
55
+ description:
56
+ email:
57
+ - michel.boaventura@gmail.com
58
+ executables:
59
+ - rcpm
60
+ extensions:
61
+ - ext/bk/extconf.rb
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - CODE_OF_CONDUCT.md
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/rcpm
72
+ - bin/setup
73
+ - ext/bk/bk.c
74
+ - ext/bk/extconf.rb
75
+ - lib/rcpm.rb
76
+ - lib/rcpm/version.rb
77
+ - rcpm.gemspec
78
+ homepage: http://github.com/michelboaventura/rcpm
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.6
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Ruby's implementation of Clique Percolation Method
102
+ test_files: []