Skip to content

Instantly share code, notes, and snippets.

@xiejiangzhi
Last active February 16, 2017 08:06
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 xiejiangzhi/92e8a6e49f74e158b61ae862938e8752 to your computer and use it in GitHub Desktop.
Save xiejiangzhi/92e8a6e49f74e158b61ae862938e8752 to your computer and use it in GitHub Desktop.
# class Unit
# include GA
# attr_accessor :genome, :value
#
# def self.random_new
# self.new(10.times.map { rand(2) == 1 })
# end
#
# def initialize(genome)
# @genome = genome.dup
# end
#
# def value
# # a number
# end
#
# def exchange!(unit)
# (rand(length) + 1).times do
# i = rand(length)
# genome[i], unit.genome[i] = unit.genome[i], genome[i]
# end
# end
#
# def variation!
# rand(length).times { genome[rand(length)] ^= true }
# end
#
# def <=>(target)
# self.value <=> target.value
# end
# end
#
# #evolve(total_units, generations, exchange_rate, variation_rate)
# Unit.evolve(10, 100, 0.8, 0.15)
#
module GA
def self.included(cls)
cls.extend(ClassMethods)
end
module ClassMethods
def evolve(total_unit = 32, generations = 100, exchange_rate = 0.8, variation_rate = 0.1)
units = total_unit.times.map { self.random_new }
evolve_with_units(units, generations, exchange_rate, variation_rate)
end
def evolve_with_units(units, generations, exchange_rate, variation_rate)
new_units = units
generations.times do |i|
@before_evolue_callback.call(new_units, generations) if @before_evolue_callback
@before_init_callback.call(new_units) if @before_init_callback
if @debug then
puts "GA-#{i + 1}/#{generations} #{new_units[-1].genome.length}" +
" #{new_units.sort[0..2].map(&:value).join(', ')}" +
" ... #{new_units.sort[-7..-1].map(&:value).join(', ')}"
end
new_units = ga_select_units(new_units)
ga_exchange_units(new_units, exchange_rate)
ga_variation_units(new_units, variation_rate)
@after_evolve_callback.call(new_units, generations) if @after_evolve_callback
end
return new_units
end
def ga_debug!
@debug = true
end
def ga_before_evolve(&block)
@before_evolve_callback = block
end
def ga_after_evolve(&block)
@after_evolve_callback = block
end
def ga_before_init_value(&block)
@before_init_callback = block
end
private
def ga_select_units(units)
new_units = units.map do
ou = units.sample(3).max
self.new(ou.genome).tap {|u| u.value = ou.value }
end
min_index = new_units.index(new_units.min)
if min_index != 0 then
new_units[min_index], new_units[0] = new_units[0], new_units[min_index]
end
new_units[0] = self.new(units.max.genome)
new_units
end
def ga_exchange_units(units, rate)
last_index = nil
total = 0
units.each_with_index do |unit, index|
next if index == 0
next if rand() >= rate
total += 1
if last_index
units[last_index].exchange!(unit)
units[last_index].value = unit.value = nil
last_index = nil
else
last_index = index
end
end
puts("exchange total #{total}") if @debug
end
def ga_variation_units(units, rate)
total = 0
units.each_with_index do |unit, index|
next if index == 0
next if rand() >= rate
total += 1
unit.variation!
unit.value = nil
end
puts("variation total #{total}") if @debug
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment