Skip to content

Instantly share code, notes, and snippets.

@ompugao
Created March 26, 2012 16:50
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 ompugao/2206451 to your computer and use it in GitHub Desktop.
Save ompugao/2206451 to your computer and use it in GitHub Desktop.
ga system written in Ruby
module GaRuby
class GaRubyError < StandardError ; end
class Gene
attr_acessor :data,:value
def initialize(gen_num=nil)
@value=0
if block_given?
@data=Array.new(gen_num){yield}
else
@data=[]
end
end
end
class Genes
attr_accessor :parent
def initialize(gen_num,parent_num,
elete_num,probability_of_mutate,probability_of_crossover,
gene_initializer,evaluate_func,mutate_func,crossover_func,
generation_num)
#遺伝子のサイズ
@gen_num=gen_num
#遺伝子(個体)数
@parent_num=parent_num
#エリート数
@elete_num=elete_num
#突然変異する確率
@probability_of_mutate=probability_of_mutate
#交叉する確率
@probability_of_crossover=probability_of_crossover
#評価関数
@evaluate_func=evaluate_func
#突然変異関数
@mutate_func=mutate_func
#交叉関数
@crossover_func=crossover_func
#世代数
@generation_num = generation_num
@parent = Array.new(@parent_num){Gene.new(@gen_num){gene_initializer.call}}
@children = []
end
def start
@generation_num.times do
mark
normalize_score
p @parent.first.data
@children = @parent.take(@elete_num).clone
begin
r = rand
@children << if r < @probability_of_mutate
indexes = roullete(1)
@mutate_func.call(@parent[indexes[0]])
elsif r < @probability_of_crossover
indexes = roullete(2)
@crossover_func.call(@parent[indexes[0]],@parent[indexes[1]])
else
@parent[roullete(1)[0]]
end
end until @children.size == @parent.size
@parent = @children.clone
end
p @children.sort!{|a,b| b.value <=> a.value}.first.data
end
private
def mark
@parent.each do |gene|
gene.value = @evaluate_func.call(gene)
end
@parent.sort!{|a,b| b.value <=> a.value}
end
def normalize_score
@probs = []
sum = @parent.inject(0){|result,gene| result += gene.value}
@parent.each{|gene| @probs << gene.value/sum}
1.step(@probs.size-1) do |idx|
@probs[idx] += @probs[idx-1]
end
@probs[@probs.size-1] = 1.0
end
#num: 選択する遺伝子数
def roullete(num)
ret = []
begin
r = rand
i = 0
while r > @probs[i]
i+=1
end
ret << i
end until ret.size == num
ret
end
end
end
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), *%w<.. lib>))
require 'ga_ruby'
extend GaRuby
evaluate_func = ->(gene){
1 / ([0,0,1,1,0,0,1,1].zip(gene.data).inject(0) do |result,elem|
result + (elem[0] - elem[1])**2
end + 0.1)
}
crossover_func = ->(gene1,gene2){
gene = Gene.new
r = rand(8)
gene.data = gene1.data[0..r] + gene2.data[r+1..7]
gene
}
mutate_func2 = ->(gene){
homu = rand(8)
if gene.data[homu] == 1
gene.data[homu] =0
else
gene.data[homu]=1
end
return gene
}
mutate_func = ->(gene){
homu = rand(8)
if rand < 0.5
gene.data[homu] += rand * gene.data[homu]
else
gene.data[homu] -= rand * gene.data[homu]
end
return gene
}
genes = Genes.new(8,16,2,0.01,0.2,->{rand},evaluate_func,mutate_func2,crossover_func,10000)
genes.start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment