genetica 0.0.1.beta.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.
data/lib/genetica.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'genetica/chromosome'
2
+ require 'genetica/chromosome_builder'
3
+ require 'genetica/population'
4
+ require 'genetica/population_builder'
@@ -0,0 +1,40 @@
1
+ module Genetica
2
+ class Chromosome
3
+
4
+ attr_reader :chromosome
5
+
6
+ def initialize(chromosome)
7
+ @chromosome = chromosome
8
+ end
9
+
10
+ def single_point_crossover(chromosome)
11
+ other_chromosome = chromosome.chromosome
12
+ locus = rand(other_chromosome.size) + 1
13
+
14
+ offspring_a = @chromosome.take(locus) + other_chromosome.last(@chromosome.size - locus)
15
+ offspring_b = other_chromosome.take(locus) + @chromosome.last(@chromosome.size - locus)
16
+
17
+ return Chromosome.new(offspring_a), Chromosome.new(offspring_b)
18
+ end
19
+
20
+ def mutate!(mutation_probability, alleles)
21
+ if mutation_probability > 0
22
+ @chromosome.collect! do |gene|
23
+ if rand.between? 0, mutation_probability
24
+ # Mutated Gene, we select a different gene from the alleles
25
+ (alleles - [gene]).sample
26
+ else
27
+ # Gene without mutation
28
+ gene
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def to_s
35
+ return @chromosome.join
36
+ end
37
+
38
+ end
39
+ end
40
+
@@ -0,0 +1,20 @@
1
+ module Genetica
2
+ class ChromosomeBuilder
3
+
4
+ attr_accessor :length
5
+ attr_accessor :alleles
6
+
7
+ def initialize
8
+ # Default Chromosome values
9
+ @length = 8
10
+ @alleles = [0, 1]
11
+ end
12
+
13
+ def chromosome
14
+ chromosome = Array.new
15
+ @length.times { chromosome << @alleles.sample }
16
+ return Chromosome.new(chromosome)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,101 @@
1
+ module Genetica
2
+ class Population
3
+
4
+ attr_reader :population
5
+ attr_reader :generation
6
+
7
+ attr_accessor :alleles
8
+ attr_accessor :crossover_probability
9
+ attr_accessor :mutation_probability
10
+ attr_accessor :fitness_function
11
+
12
+ def initialize(population)
13
+ @generation = 0
14
+ @population = population
15
+ end
16
+
17
+ def best_chromosome
18
+ @population.at @population_fitness.index(self.best_fitness)
19
+ end
20
+
21
+ def best_fitness
22
+ @population_fitness.max
23
+ end
24
+
25
+ def average_fitness
26
+ @population_fitness.inject(:+) / @population_fitness.size.to_f
27
+ end
28
+
29
+ def population_fitness
30
+ @population.collect { |chromosome| @fitness_function.call(chromosome) }
31
+ end
32
+
33
+ def fitness_function=(new_fitness_function)
34
+ @fitness_function = new_fitness_function
35
+ @population_fitness = self.population_fitness
36
+ end
37
+
38
+ def population=(new_population)
39
+ @population = new_population
40
+ @population_fitness = self.population_fitness
41
+ end
42
+
43
+ def fitness_proportionate_selection
44
+ # FUTURE: With Ruby 1.9.3 you can use rand with ranges, e.g. rand 0.0..3.4
45
+ # Get random number
46
+ random_generator = Random.new
47
+ random_number = random_generator.rand 0.0..@population_fitness.inject(:+)
48
+
49
+ # Chromosome selection
50
+ fitness_counter = 0
51
+ @population.each_with_index do |chromosome, i|
52
+ fitness_counter += @population_fitness[i]
53
+ if fitness_counter >= random_number
54
+ return chromosome
55
+ end
56
+ end
57
+ end
58
+
59
+ def run(generations=1)
60
+ generations.times do
61
+ # Generate a new chromosome population
62
+ population = Array.new
63
+
64
+ while population.size < @population.size
65
+ # 1. Selection Step
66
+ # Select a pair of parent chromosomes from the current population.
67
+ # This selection is 'with replacement', the same chromosome can be selected
68
+ # more than once to become a parent.
69
+ chromosome_a = self.fitness_proportionate_selection
70
+ chromosome_b = self.fitness_proportionate_selection
71
+
72
+ # 2. Crossover Step
73
+ # TODO: Maybe crossover probability check would be in the single_point_crossover of
74
+ # Chromosome class.
75
+ if @crossover_probability > 0 and rand.between? 0, @crossover_probability
76
+ offspring_a, offspring_b = chromosome_a.single_point_crossover chromosome_b
77
+ else
78
+ offspring_a, offspring_b = chromosome_a, chromosome_b
79
+ end
80
+
81
+ # 3. Mutation Step
82
+ offspring_a.mutate! @mutation_probability, @alleles
83
+ offspring_b.mutate! @mutation_probability, @alleles
84
+
85
+ # 4. Adding offsprings to new chromosome population
86
+ population << offspring_a << offspring_b
87
+ end
88
+
89
+ # If original population size is odd discard a random chromosome
90
+ population.delete_at rand population.size if @population.size.odd?
91
+
92
+ # Replacing chromosome population with the new one
93
+ self.population = population
94
+
95
+ # A new generation has been created
96
+ @generation += 1
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,44 @@
1
+ module Genetica
2
+ class PopulationBuilder
3
+
4
+ # Population attributes
5
+ attr_accessor :size
6
+ attr_accessor :crossover_probability
7
+ attr_accessor :mutation_probability
8
+ attr_accessor :fitness_function
9
+ # Chromosome attributes
10
+ attr_accessor :chromosome_length
11
+ attr_accessor :chromosome_alleles
12
+
13
+ def initialize
14
+ # Default Population values
15
+ @size = 20
16
+ @crossover_probability = 0.7
17
+ @mutation_probability = 0.001
18
+ @fitness_function = nil
19
+ # Default Chromosome values
20
+ @chromosome_length = 8
21
+ @chromosome_alleles = [0, 1]
22
+ end
23
+
24
+ def population
25
+ # Generating Chromosome population
26
+ chromosome_builder = ChromosomeBuilder.new
27
+ chromosome_builder.length = @chromosome_length
28
+ chromosome_builder.alleles = @chromosome_alleles
29
+
30
+ chromosome_population = Array.new
31
+ @size.times { chromosome_population << chromosome_builder.chromosome }
32
+
33
+ # Generating Population
34
+ population = Population.new chromosome_population
35
+ population.alleles = @chromosome_alleles
36
+ population.crossover_probability = @crossover_probability
37
+ population.mutation_probability = @mutation_probability
38
+ population.fitness_function = @fitness_function
39
+
40
+ return population
41
+ end
42
+
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: genetica
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta.1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - José Francisco Calvo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-08 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: Genetica is a library to create and use Genetic Algorithms solutions
16
+ using Ruby language.
17
+ email: josefranciscocalvo@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/genetica.rb
23
+ - lib/genetica/chromosome.rb
24
+ - lib/genetica/chromosome_builder.rb
25
+ - lib/genetica/population.rb
26
+ - lib/genetica/population_builder.rb
27
+ has_rdoc: true
28
+ homepage: http://dev.monsterzen.com/projects/genetica.html
29
+ licenses: []
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>'
44
+ - !ruby/object:Gem::Version
45
+ version: 1.3.1
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.6.2
49
+ signing_key:
50
+ specification_version: 3
51
+ summary: The Ruby Genetic Algorithms Gem.
52
+ test_files: []