gga4r 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODA5YjdmOWY1ZWJjZWFmZWJiYTcwOGM1NjE4NjhmZjRkMzRmMTVlYw==
5
+ data.tar.gz: !binary |-
6
+ Njg3OTBlNTk4NTIwNjY0NmEyNDg0M2NmYzdhN2JhMDA1NmRhZTkxMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ Yzc5NTg5ZjQ0MmI3OWQ2NjFkN2MzNDhkMDZiODg0NTE1OTgzMDUzMWE3ODY3
10
+ MTEyZDJlYThmYzdmZDAwNDAwNWFmNzQ4MjI5Y2JiNWE2MjI5MmU3YmFkMTEx
11
+ OWUzMDViYjQ0ZWVlNWU3NDg4MjRhNjIxZmFlMGNiYTEyZDdmMjQ=
12
+ data.tar.gz: !binary |-
13
+ MjlmN2RjODNiYWI3YzIzMjRjMmNiMWU5NWNlODVlMjI3OWM4ZWRmMzdlOGYz
14
+ Mjc2MDZkZTJjMTA2MWVkMGVlYTY1ZWI5M2M3Yzc2ZDgwNTMxZGI3OGJiODgy
15
+ OTczYTU1ZWMwNzNlNjBkNTFlNTBkOWMwY2RhYWY0MDJjOWM3MTE=
File without changes
@@ -1,12 +1,7 @@
1
1
  Rakefile
2
- README.txt
3
- CHANGELOG.txt
2
+ README.md
4
3
  Manifest.txt
5
- setup.rb
6
- lib/gga4r/version.rb
7
- lib/gga4r/array_helper.rb
8
- lib/gga4r/gga4r_main.rb
9
4
  lib/gga4r.rb
10
5
  test/test_helper.rb
11
6
  test/gga4r_test.rb
12
- examples/ga_fitness_all_1s.rb
7
+ examples/ga_fitness_all_1s.rb
@@ -0,0 +1,87 @@
1
+ # gga4r - General Genetic Algorithm for Ruby
2
+
3
+ ##Introduction
4
+
5
+ General Genetic Algorithm for Ruby is a Ruby Genetic Algorithm that is very simple to use:
6
+
7
+ 1) Take a class to evolve it and define fitness, recombine and mutate methods.
8
+
9
+ ```ruby
10
+ class StringPopulation < Array
11
+ def fitness
12
+ self.select { |pos| pos == 1 }.size.to_f / self.size.to_f
13
+ end
14
+
15
+ def recombine(c2)
16
+ cross_point = (rand * c2.size).to_i
17
+ c1_a, c1_b = self.separate(cross_point)
18
+ c2_a, c2_b = c2.separate(cross_point)
19
+ StringPopulation.new(c1_a + c2_b)
20
+ end
21
+
22
+ def mutate
23
+ mutate_point = (rand * self.size).to_i
24
+ self[mutate_point] = 1
25
+ end
26
+ end
27
+ ```
28
+
29
+ 2) Create a GeneticAlgorithm object with the population.
30
+
31
+ ```ruby
32
+ def create_population_with_fit_all_1s(s_long = 10, num = 10)
33
+ population = []
34
+ num.times do
35
+ chromosome = StringPopulation.new(Array.new(s_long).collect { (rand > 0.2) ? 0:1 })
36
+ population << chromosome
37
+ end
38
+ population
39
+ end
40
+
41
+ ga = GeneticAlgorithm.new(create_population_with_fit_all_1s)
42
+ ```
43
+
44
+ 3) Call the evolve method as many times as you want and see the best evolution.
45
+
46
+ ```ruby
47
+ 100.times { |i| ga.evolve }
48
+ p ga.best_fit[0]
49
+ ```
50
+
51
+ ##Install
52
+
53
+ 1. Execute:
54
+ ```
55
+ gem install gga4r
56
+ ```
57
+
58
+ 2. Add require in your code headers:
59
+ ```
60
+ require "rubygems"
61
+ require "gga4r"
62
+ ```
63
+
64
+ ##Documentation
65
+
66
+ Documentation can be generated using rdoc tool under the source code with:
67
+ ```
68
+ rdoc README lib
69
+ ```
70
+
71
+ ##Contributors
72
+
73
+ - Ben Prew https://github.com/benprew
74
+ - Rory O'Kane
75
+ - Sergio Espeja https://github.com/spejman
76
+
77
+
78
+ ##Copying
79
+
80
+ This work is developed by Sergio Espeja ( www.upf.edu/pdi/iula/sergio.espeja, sergio.espeja at gmail.com )
81
+ mainly in Institut Universitari de Lingüística Aplicada of Universitat Pompeu Fabra ( www.iula.upf.es ),
82
+ and also in bee.com.es ( bee.com.es ).
83
+
84
+ It is free software, and may be redistributed under GPL license.
85
+
86
+
87
+
data/Rakefile CHANGED
@@ -1,19 +1,11 @@
1
1
  require 'rubygems'
2
- require 'rake'
3
- require 'rake/clean'
4
- require 'rake/testtask'
5
- require 'rake/packagetask'
6
- require 'rake/gempackagetask'
7
- require 'rake/rdoctask'
8
- require 'rake/contrib/rubyforgepublisher'
9
- require 'fileutils'
10
2
  require 'hoe'
3
+
11
4
  include FileUtils
12
- require File.join(File.dirname(__FILE__), 'lib', 'gga4r', 'version')
13
5
 
14
6
  AUTHOR = "Sergio Espeja"
15
7
  EMAIL = "sergio.espeja@gmail.com"
16
- DESCRIPTION = "A Ruby Genetic Algorithm. So simple to use: 1, take a class to evolve it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm object with the population. 3, call evolve method as many times as you want.description of gem"
8
+ DESCRIPTION = "A Ruby Genetic Algorithm. Very simple to use: 1, take a class to evolve it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm object with the population. 3, call the evolve method as many times as you want.description of gem"
17
9
  GEM_NAME = "gga4r" # what ppl will type to install your gem
18
10
  RUBYFORGE_PROJECT = "gga4r" # The unix name for your project
19
11
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
@@ -21,32 +13,30 @@ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
21
13
 
22
14
  NAME = "gga4r"
23
15
  REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
- VERS = ENV['VERSION'] || (Gga4r::VERSION::STRING + (REV ? ".#{REV}" : ""))
25
- CLEAN.include ['**/.*.sw?', '*.gem', '.config']
26
16
  RDOC_OPTS = ['--quiet', '--title', "gga4r documentation",
27
17
  "--opname", "index.html",
28
- "--line-numbers",
18
+ "--line-numbers",
29
19
  "--main", "README",
30
20
  "--inline-source"]
31
21
 
32
22
  class Hoe
33
- def extra_deps
34
- @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
- end
23
+ def extra_deps
24
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
25
+ end
36
26
  end
37
27
 
38
28
  # Generate all the Rake tasks
39
29
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
40
- hoe = Hoe.new(GEM_NAME, VERS) do |p|
41
- p.author = AUTHOR
30
+ hoe = Hoe.spec GEM_NAME do |p|
31
+ p.author = AUTHOR
42
32
  p.description = DESCRIPTION
43
33
  p.email = EMAIL
44
34
  p.summary = DESCRIPTION
45
- p.url = HOMEPATH
35
+ p.urls = [HOMEPATH]
46
36
  p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
47
37
  p.test_globs = ["test/**/*_test.rb"]
48
- p.clean_globs = CLEAN #An array of file patterns to delete on clean.
49
-
38
+ p.readme_file = 'README.md'
39
+
50
40
  # == Optional
51
41
  #p.changes - A description of the release's latest changes.
52
42
  #p.extra_deps - An array of rubygem dependencies.
@@ -1 +1,142 @@
1
- Dir[File.join(File.dirname(__FILE__), 'gga4r/**/*.rb')].sort.each { |lib| require lib }
1
+ require 'logger'
2
+
3
+ class GeneticAlgorithm
4
+ VERSION = '0.9.3'
5
+
6
+ # Must be initialized with a Array of chromosomes
7
+ # To be a chomosome the object must implement the next methods:
8
+ # - fitness
9
+ # - recombine
10
+ # - mutate
11
+ # - distance (only for multi-modal optimization)
12
+ # Accepts the next properties:
13
+ # - max_population: maximum number of individuals that are allowed to form a generation.
14
+ # - logger: logger to write messages if given.
15
+ # - multi_recombination: set to true if the result of a chromosome's #recombination method
16
+ # returns an array. Default to false
17
+ # - multi_modal: set to true to use a multi-modal algorithm using deterministic crowding and a distance-derated fitness.
18
+ # - share_radius: in multi-modal optimization, determines the niche radius for derated fitness calculation.
19
+ def initialize(in_pop, prop = {})
20
+ @max_population = prop[:max_population]
21
+ @logger = prop[:logger] || Logger.new('/dev/null')
22
+ @population = in_pop
23
+ @multi_recombination = prop[:multi_recombination] || false
24
+ @generations = []
25
+ @multi_modal = prop[:multi_modal] || false
26
+ @share_radius = prop[:share_radius] or 3
27
+ end
28
+
29
+ # Returns an array with the best fitted individuals for last generation
30
+ def best_fit
31
+ @population.max_by(&:fitness)
32
+ end
33
+
34
+ # Returns an array with the best fitted n individuals from the population (might include local optima)
35
+ def best_fitted(n)
36
+ @population.uniq.sort_by{|c| -c.fitness}.first(n)
37
+ end
38
+
39
+ # Returns an array with the best fitted n individuals from the population (might include local optima)
40
+ # Uses a distance-derated fitness metric
41
+ def best_fitted_derated(n)
42
+ @population.uniq.sort_by{|c| -(derated_fitness(c,@population))}.first(n)
43
+ end
44
+
45
+ # Returns a GeneticAlgorithm object with the generations
46
+ # loaded from given files and with properties prop.
47
+ # Files must contain the chromosomes in YAML format.
48
+ def self.populate_from_file(filename, prop = {})
49
+ GeneticAlgorithm.new(YAML.load(File.open(filename, 'r')), prop)
50
+ end
51
+
52
+ # Saves into filename and in yaml format the generation that matchs with given
53
+ # generation number ( by default from last generation ).
54
+ def save_population(filename)
55
+ f = File.new(filename, "w")
56
+ f.write(@population.to_yaml)
57
+ f.close
58
+ end
59
+
60
+ # EVOLUTION METHODS
61
+
62
+ # Evolves the actual generation num_steps steps (1 by default).
63
+ def evolve(num_steps = 1)
64
+ num_steps.times do |t|
65
+ @population = selection(@population)
66
+ new_gen = @population.map { |chromosome| chromosome.dup }
67
+ if !@multi_modal
68
+ @population += recombination(new_gen) + mutation(new_gen)
69
+ else
70
+ @population = deterministic_crowding(@population)
71
+ @population = mutation(@population)
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ # Selects population to survive and recombine
79
+ def selection(g)
80
+ @max_population && g.length > @max_population ? g.sort_by{|c| -c.fitness}.first(@max_population) : g
81
+ end
82
+
83
+ # Recombines population
84
+ def recombination(g)
85
+ @logger.debug "Recombination " + g.size.to_s + " chromosomes." if @logger
86
+ new_generation = g.dup.shuffle!
87
+ @logger.debug "Shuffled!" if @logger
88
+ new_children = []
89
+ new_generation.each_slice(2) do |chromosome1, chromosome2|
90
+ next if chromosome2.nil?
91
+ @logger.debug "Recombining" if @logger
92
+ new_children << chromosome1.recombine(chromosome2)
93
+ end
94
+ new_children.flatten!(1) if @multi_recombination
95
+ new_generation + new_children
96
+ end
97
+
98
+ def deterministic_crowding(g)
99
+ groups = g.shuffle
100
+ group1 = groups.first(g.length/2)
101
+ group2 = groups[g.length/2..-1]
102
+
103
+ new_gen = []
104
+
105
+ group1.each_with_index do |p1,i|
106
+ p2 = group2[i]
107
+
108
+ if p2
109
+
110
+ c1, c2 = p1.recombine(p2)
111
+
112
+ if p1.distance(c1) + p2.distance(c2) <= p1.distance(c2) + p2.distance(c1)
113
+ new_gen << [p1,c1].max_by{|c| derated_fitness(c,g)}
114
+ new_gen << [p2,c2].max_by{|c| derated_fitness(c,g)}
115
+ else
116
+ new_gen << [p1,c2].max_by{|c| derated_fitness(c,g)}
117
+ new_gen << [p2,c1].max_by{|c| derated_fitness(c,g)}
118
+ end
119
+ else
120
+ new_gen << p1
121
+ end
122
+ end
123
+ new_gen
124
+ end
125
+
126
+ def derated_fitness(c,g)
127
+ share_count = g.map{|c2| [(1-c.distance(c2)/@share_radius),0].max }.sum
128
+ share_count = Float::EPSILON if share_count==0
129
+ c.fitness/share_count
130
+ end
131
+
132
+ # Mutates population
133
+ def mutation(g)
134
+ @logger.debug "Mutation " + g.size.to_s + " chromosomes." if @logger
135
+ new_generation = g.dup
136
+ new_generation.each do |chromosome|
137
+ @logger.debug "Mutate" if @logger
138
+ chromosome.mutate
139
+ end
140
+ new_generation
141
+ end
142
+ end
@@ -1,37 +1,73 @@
1
1
  require File.dirname(__FILE__) + '/test_helper.rb'
2
2
 
3
3
  class IndividualStub < Array
4
+
5
+ def mutate
6
+ end
7
+
8
+ def fitness
9
+ end
10
+
4
11
  def recombine(a)
5
12
  self * 2
6
13
  end
14
+
7
15
  def self.create_random_population(num_population = 30)
8
16
  population = []
9
17
  num_population.times do
10
- population << IndividualStub.new
18
+ population << IndividualStub.new([1,2,3])
11
19
  end
12
20
  return population
13
21
  end
14
22
  end
15
23
 
16
- class Gga4rTest < Test::Unit::TestCase
24
+ class StringPopulation < Array
25
+ def fitness
26
+ fitness = self.select { |pos| pos == 1 }.size.to_f / self.size.to_f
27
+ fitness
28
+ end
29
+
30
+ def recombine(c2)
31
+ cross_point = rand([self.size, c2.size].min) + 1
32
+ c1_a, c1_b = self.slice(0,cross_point), self.slice(cross_point, 0)
33
+ c2_a, c2_b = c2.slice(0,cross_point), c2.slice(cross_point, 0)
34
+ [StringPopulation.new(c1_a + c2_b), StringPopulation.new(c2_a + c1_b)]
35
+ end
17
36
 
18
- def setup
37
+ def mutate
38
+ mutate_point = (rand * self.size).to_i
39
+ self[mutate_point] = 1
19
40
  end
20
-
21
- def test_truth
22
- assert true
41
+
42
+ def self.create_population(s_long = 10, num = 10)
43
+ population = []
44
+ num.times do
45
+ chromosome = self.new(Array.new(s_long).collect { (rand > 0.2) ? 0:1 })
46
+ population << chromosome
47
+ end
48
+ population
23
49
  end
24
-
25
- def test_recombine
50
+ end
51
+
52
+ class Gga4rTest < Test::Unit::TestCase
53
+ def test_single_recombination_result
26
54
  first_pop_even = IndividualStub.create_random_population(30)
27
55
  ga = GeneticAlgorithm.new(first_pop_even)
28
- new_pop = ga.recombination!
29
- assert true, first_pop_even.size < new_pop.size
30
-
31
- first_pop_odd = IndividualStub.create_random_population(31)
32
- ga = GeneticAlgorithm.new(first_pop_odd)
33
- new_pop = ga.recombination!
34
- assert true, first_pop_odd.size < new_pop.size
35
-
56
+ 5.times do |i|
57
+ ga.evolve
58
+ new_pop = ga.instance_variable_get(:@population)
59
+ assert first_pop_even.size < new_pop.size
60
+ end
61
+ end
62
+
63
+ def test_multiple_recombination
64
+ opts = {multi_recombination: true}
65
+ ga = GeneticAlgorithm.new(StringPopulation.create_population, opts)
66
+ assert ga.instance_variable_get(:@multi_recombination)
67
+ 4.times do |i|
68
+ assert_nothing_raised do
69
+ ga.evolve
70
+ end
71
+ end
36
72
  end
37
73
  end
metadata CHANGED
@@ -1,60 +1,90 @@
1
- --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
1
+ --- !ruby/object:Gem::Specification
4
2
  name: gga4r
5
- version: !ruby/object:Gem::Version
6
- version: 0.9.2
7
- date: 2007-11-30 00:00:00 +01:00
8
- summary: "A Ruby Genetic Algorithm. So simple to use: 1, take a class to evolve it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm object with the population. 3, call evolve method as many times as you want.description of gem"
9
- require_paths:
10
- - lib
11
- email: sergio.espeja@gmail.com
12
- homepage: http://gga4r.rubyforge.org
13
- rubyforge_project: gga4r
14
- description: "A Ruby Genetic Algorithm. So simple to use: 1, take a class to evolve it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm object with the population. 3, call evolve method as many times as you want.description of gem"
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.3
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
- authors:
6
+ authors:
30
7
  - Sergio Espeja
31
- files:
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hoe
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.7'
41
+ description: ! 'A Ruby Genetic Algorithm. Very simple to use: 1, take a class to evolve
42
+ it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm
43
+ object with the population. 3, call the evolve method as many times as you want.description
44
+ of gem'
45
+ email: sergio.espeja@gmail.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files:
49
+ - README.md
50
+ - Manifest.txt
51
+ files:
32
52
  - Rakefile
33
- - README.txt
34
- - CHANGELOG.txt
53
+ - README.md
35
54
  - Manifest.txt
36
- - setup.rb
37
- - lib/gga4r/version.rb
38
- - lib/gga4r/array_helper.rb
39
- - lib/gga4r/gga4r_main.rb
40
55
  - lib/gga4r.rb
41
56
  - test/test_helper.rb
42
57
  - test/gga4r_test.rb
43
58
  - examples/ga_fitness_all_1s.rb
44
- test_files:
45
- - test/gga4r_test.rb
46
- rdoc_options:
59
+ - .gemtest
60
+ homepage: http://gga4r.rubyforge.org
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options:
47
66
  - --main
48
- - README.txt
49
- extra_rdoc_files:
50
- - README.txt
51
- - CHANGELOG.txt
52
- - Manifest.txt
53
- executables: []
54
-
55
- extensions: []
56
-
67
+ - README.md
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
57
80
  requirements: []
58
-
59
- dependencies: []
60
-
81
+ rubyforge_project: gga4r
82
+ rubygems_version: 2.1.10
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: ! 'A Ruby Genetic Algorithm. Very simple to use: 1, take a class to evolve
86
+ it and define fitness, recombine and mutate methods. 2, create a GeneticAlgorithm
87
+ object with the population. 3, call the evolve method as many times as you want.description
88
+ of gem'
89
+ test_files:
90
+ - test/gga4r_test.rb