Skip to content

Instantly share code, notes, and snippets.

@mattm
Last active September 26, 2018 06:56

Revisions

  1. mattm revised this gist Aug 18, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.rb
    Original file line number Diff line number Diff line change
    @@ -135,7 +135,7 @@ def select
    end
    end

    puts "Generation #{generation} - Average: #{population.average_fitness.round} - Max: #{population.max_fitness}"
    puts "Generation #{generation} - Average: #{population.average_fitness.round(2)} - Max: #{population.max_fitness}"

    population = offspring
    end
  2. mattm revised this gist Aug 18, 2013. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions gistfile1.rb
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,6 @@
    POPULATION_SIZE = 24
    NUM_BITS = 64

    NUM_GENERATIONS = 1000

    CROSSOVER_RATE = 0.7
    MUTATION_RATE = 0.001

  3. mattm created this gist Aug 18, 2013.
    145 changes: 145 additions & 0 deletions gistfile1.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    POPULATION_SIZE = 24
    NUM_BITS = 64

    NUM_GENERATIONS = 1000

    CROSSOVER_RATE = 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 &(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(NUM_GENERATIONS).each do |generation|

    offspring = Population.new

    while offspring.count < population.count
    parent1 = population.select
    parent2 = population.select

    if rand <= CROSSOVER_RATE
    child1, child2 = parent1 & parent2
    else
    child1 = parent1
    child2 = parent2
    end

    child1.mutate!
    child2.mutate!

    if POPULATION_SIZE.even?
    offspring.chromosomes << child1 << child2
    else
    offspring.chromosomes << [child1, child2].sample
    end
    end

    puts "Generation #{generation} - Average: #{population.average_fitness.round} - Max: #{population.max_fitness}"

    population = offspring
    end

    puts "Final population: " + population.inspect