Skip to content

Instantly share code, notes, and snippets.

@mattm
Created August 18, 2013 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattm/6262488 to your computer and use it in GitHub Desktop.
Save mattm/6262488 to your computer and use it in GitHub Desktop.
POPULATION_SIZE = 50
NUM_BITS = 64
GENERATIONS = 1000
SAMPLE_SIZE = 100
CROSSOVER_PROBABILITY = 0.7
MUTATION_RATE = 0.001
class Chromosome
attr_accessor :genes
def initialize(genes = "")
if genes == ""
self.genes = (1..NUM_BITS).map{ rand(2) }.join
else
self.genes = genes
end
end
def to_s
genes.to_s
end
def count
genes.count
end
def fitness
genes.count("1")
end
def mutate!
mutated = ""
0.upto(genes.length - 1).each do |i|
allele = genes[i, 1]
if rand <= MUTATION_RATE
mutated += (allele == "0") ? "1" : "0"
else
mutated += allele
end
end
self.genes = mutated
end
def crossover_with(other)
locus = rand(genes.length) + 1
child1 = genes[0, locus] + other.genes[locus, other.genes.length]
child2 = other.genes[0, locus] + genes[locus, other.genes.length]
return [
Chromosome.new(child1),
Chromosome.new(child2),
]
end
end
class Population
attr_accessor :chromosomes
def initialize
self.chromosomes = Array.new
end
def inspect
chromosomes.join(" ")
end
def seed!
chromosomes = Array.new
1.upto(POPULATION_SIZE).each do
chromosomes << Chromosome.new
end
self.chromosomes = chromosomes
end
def count
chromosomes.count
end
def fitness_values
chromosomes.collect(&:fitness)
end
def total_fitness
fitness_values.inject{|total, value| total + value }
end
def max_fitness
fitness_values.max
end
def average_fitness
total_fitness.to_f / chromosomes.length.to_f
end
def select
rand_selection = rand(total_fitness)
total = 0
chromosomes.each_with_index do |chromosome, index|
total += chromosome.fitness
return chromosome if total > rand_selection || index == chromosomes.count - 1
end
end
end
population = Population.new
population.seed!
1.upto(GENERATIONS).each do |generation|
offspring = Population.new
while offspring.count < population.count
parent1 = population.select
parent2 = population.select
if rand <= CROSSOVER_PROBABILITY
child1, child2 = parent1.crossover_with(parent2)
else
child1 = parent1
child2 = parent2
end
child1.mutate!
child2.mutate!
offspring.chromosomes << child1 << child2
end
puts "Generation: #{generation} - Average: #{population.average_fitness} - Max: #{population.max_fitness}"
population = offspring
end
puts "Final population: " + population.inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment