Question

I'm a beginner in Ruby writing a very simple program to mimic genetics, but the output fitness always stays around 15-24, roughly. Shouldn't this program eventually reach a fitness of 32 and then output so?

Edited code:

#!/usr/bin/env ruby

class Animal
  attr_reader :genes

  def initialize (genes=[])
    @genes = genes
  end

  def random_chromosome
    @genes = Array.new(32).collect {|x| rand 2}
    self
  end

  def calc_fitness
    @genes.inject(0){|i, v| next i + v if v == 1; i}
  end

  def mutate
   2.times { @genes[rand 32] = rand 2}
  end

  def mate(other)
    @genes = (@genes[0...16] + other.genes[0...16])
    mutate
    self
  end

  def is_spartan?
    @genes == (Array.new.fill 1)
  end
end

class Generation
  attr_reader :animals

  def initialize (animals=[], gen_size = 10)
    @animals = animals
    @gen_size = gen_size
  end
  def seed
    @animals = Array.new(@gen_size).collect {Animal.new.random_chromosome}
  end
  def mate
    @animals = [].tap {|a|
        @gen_size.times{ 
            a << @animals[rand @gen_size].mate(@animals[rand @gen_size])
          }
        }
  end
  def alphas
    @animals.sort! {|a, b| b.calc_fitness <=> a.calc_fitness}.first(@gen_size)
  end
  def include_spartans?
    @animals.include? Array.new(32).fill 1  #perfect genes
  end
  def output
    @animals.each {|an| print "#{an.genes.join}: #{an.calc_fitness}\n"}
  end
end

NUM_OFFSPRING = 10
gen = Generation.new
gen.seed

i = 0
loop do
  i += 1
  if gen.include_spartans? #end if there are any perfect genes
    puts "Members have reached spartan status!"
    break
  end

  puts "*** ALPHAS FROM GENERATION: #{i}***" 
  gen.mate
  gen.alphas
  gen.output
  sleep(0.2)
    end

Sample Output

* ALPHAS FROM GENERATION: 1*

11101101011111101001010110101101: 21 10111111111100000110000101011001: 18 11101111110110111100001100000001: 18 11000101101111010110000111011001: 18 11101111110110111100001100000001: 18 10111111111100000110000101011001: 18 11000101101111010110000111011001: 18 11000011010000011001101111101101: 17 01100001110110011000101111110000: 16 10001010111110001100001101000001: 14

* ALPHAS FROM GENERATION: 2*

11101111110110101110111111010011: 24 01100001110110011110111111011110: 21 11000101101111011100001101000001: 16 10001010111110000110000111011001: 16 11000101101111011100001101000001: 16 10111111010100001000001101100001: 15 10111111010100001000001101100001: 15 10111111010100001000001101100001: 15 10111111010100001000001101100001: 15 10111111010100001000001101100001: 15

* ALPHAS FROM GENERATION: 3*

11101111111110101011111111000000: 22 11101111111110101011111111000000: 22 10111111110000001110011111011010: 20 10111111110000001110011111011010: 20 10111111110000001110011111011010: 20 11000101101111011000101011111000: 18 11000101101111011000101011111000: 18 11000101101111011000101011111000: 18 11000101101111011000101011111000: 18 01100001110100011011111101010000: 16

Was it helpful?

Solution

Patru put you on the right track. It's a handful of issues resolved here: https://gist.github.com/matt-glover/9700810

The original code does not use NUM_OFFSPRING. Even if it did it also pulls 10 animals back as alphas (or tries to anyway) so NUM_OFFSPRING really should be bigger to see the alpha selection show any impact.

The original code sorts the animals in place to find alphas but does not actually keep the top 10. Instead it returns the top 10 from the method call but stores the full sorted @animals array.

Mating needs to produce a new Animal otherwise the same animal can be selected over and over again in the mating stage. The original code keeps the results only from the last mating attempt stored in the first animal in the mating pair. This eventually eliminates the animal pool to a single animal showing up multiple times in the animals list and only reflecting the genes from the last mating attempt that iteration.

Finally the include_spartans? check either needs to map the genes as done in the example or call through to each animal and perform the check there. The old code was checking an animal instance against an array of ones.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top