def objective_function(vector) return vector.inject(0.0) {|sum, x| sum + (x ** 2.0)} end def random_vector(minmax) return Array.new(minmax.size) do |i| minmax[i][0] + ((minmax[i][1] - minmax[i][0]) * rand()) end end def random_gaussian(mean=0.0, stdev=1.0) u1 = u2 = w = 0 begin u1 = 2 * rand() - 1 u2 = 2 * rand() - 1 w = u1 * u1 + u2 * u2 end while w >= 1 w = Math.sqrt((-2.0 * Math.log(w)) / w) return mean + (u2 * w) * stdev end def mutate(candidate, search_space) child = {:vector=>[], :strategy=>[]} candidate[:vector].each_with_index do |v_old, i| s_old = candidate[:strategy][i] v = v_old + s_old * random_gaussian() v = search_space[i][0] if v < search_space[i][0] v = search_space[i][1] if v > search_space[i][1] child[:vector] << v child[:strategy] << s_old + random_gaussian() * s_old.abs**0.5 end return child end def tournament(candidate, population, bout_size) candidate[:wins] = 0 bout_size.times do |i| other = population[rand(population.size)] candidate[:wins] += 1 if candidate[:fitness] < other[:fitness] end end def init_population(minmax, pop_size) strategy = Array.new(minmax.size) do |i| [0, (minmax[i][1]-minmax[i][0]) * 0.05] end pop = Array.new(pop_size, {}) pop.each_index do |i| pop[i][:vector] = random_vector(minmax) pop[i][:strategy] = random_vector(strategy) end pop.each{|c| c[:fitness] = objective_function(c[:vector])} return pop end def search(max_gens, search_space, pop_size, bout_size) population = init_population(search_space, pop_size) population.each{|c| c[:fitness] = objective_function(c[:vector])} best = population.sort{|x,y| x[:fitness] <=> y[:fitness]}.first max_gens.times do |gen| children = Array.new(pop_size) {|i| mutate(population[i], search_space)} children.each{|c| c[:fitness] = objective_function(c[:vector])} children.sort!{|x,y| x[:fitness] <=> y[:fitness]} best = children.first if children.first[:fitness] < best[:fitness] union = children+population union.each{|c| tournament(c, union, bout_size)} union.sort!{|x,y| y[:wins] <=> x[:wins]} population = union.first(pop_size) puts " > gen #{gen}, fitness=#{best[:fitness]}" end return best end if __FILE__ == $0 # problem configuration problem_size = 2 search_space = Array.new(problem_size) {|i| [-5, +5]} # algorithm configuration max_gens = 200 pop_size = 100 bout_size = 5 # execute the algorithm best = search(max_gens, search_space, pop_size, bout_size) puts "done! Solution: f=#{best[:fitness]}, s=#{best[:vector].inspect}" end