gga4r 0.9.2 → 0.9.3

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,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