PDA

Visualizza la versione completa : GA - Conservare le buone soluzioni


Il Totem
07-04-2010, 19:08
Da due giorni ormai mi sto rompendo la testa per far funzionare tutto in ruby, ma ottengo comportamenti sempre pių imprevedibili... Questo dovrebbe essere un algoritmo genetico per evolvere delle funzioni che approssimino relazioni tra ennuple di valori e una loro immagine.
In sostanza, dati a, b, c, d, ..., y approssima f tale che f(a, b, c, d, ...) = y:

#....

class GeneticEngine
attr_accessor :population_size, :crossover_number, :mutation_probability, :max_depth, :elitism
attr_accessor :values #array di array
attr_reader :population

def initialize()
end

def current_generation()
return @current_generation
end

def generate_population()
@population = Array.new()
for i in (1..@population_size) do
@population[i - 1] = Boid.create_random(@max_depth)
@population[i - 1].evaluate_fitness(values)
end
@current_generation = 0
end

def next_generation()
@population.sort! { |x, y| x.fitness <=> y.fitness }

best = @population[0..(@crossover_number-1)]

0.upto(@crossover_number - 1) do |i|
@population.concat(Boid.crossover(@population[i * 2], @population[i * 2 + 1]))
end

@population.each { |boid| boid.evaluate_fitness(@values) }
#@population.each { |boid| puts boid.fitness }
#gets

tmp_pop = Array.new()
0.upto(@population_size - 1) do |i|
if @population[i].fitness >= Float::MAX then
tmp_pop[i] = nil
else
tmp_pop[i] = @population[i]
end
end
tmp_pop.compact! #elimina nil
tmp_pop.sort! { |x, y| x.fitness <=> y.fitness }
#tmp_pop.each { |boid| puts boid.fitness }
#gets

if tmp_pop.length > @population_size then
tmp_pop = tmp_pop[0..(@population_size-1)]
end

tmp_pop.each { |boid| boid.attempt_mutation(@mutation_probability) }

if tmp_pop.length < @population_size then
(tmp_pop.length).upto(@population_size - 1) do |i|
tmp_pop[i] = Boid.create_random(@max_depth)
end
end

tmp_pop.each { |boid| boid.evaluate_fitness(@values) }
minfit = (tmp_pop.min { |x, y| x.fitness <=> y.fitness }).fitness
bestfit = (best.min { |x, y| x.fitness <=> y.fitness}).fitness
if bestfit < minfit then
tmp_pop[-(@crossover_number)..-1] = best
end

@population = tmp_pop
@current_generation += 1
end

def get_best_solution()
return (@population.sort { |x, y| x.fitness <=> y.fitness })[0]
end
end

g = GeneticEngine.new()
g.population_size = 20
g.crossover_number = 5
g.mutation_probability = 0.7
g.max_depth = 1
g.values = [[1, 2], [2, 3], [3, 4]]
g.generate_population()

while (g.current_generation < 1450) do
g.next_generation()
#g.population.each { |x| puts "> " + x.expression.to_s(), " > " + x.fitness.to_s() }
best = g.get_best_solution()
if best then
if best.fitness == 0 then
break
end
if g.current_generation % 50 == 0 then
puts "Generation " + g.current_generation.to_s()
puts "Best solution: " + best.expression.to_s()
puts "Fitness: " + best.fitness.to_s()
end
end
end
Il problema č che nelle 1450 generazioni la soluzione migliore č sempre la stessa, con una fitness orribile. Dopo vari studi, ho notato che compaiono soluzioni con fitness molto bassa, ma, non so perchč, scompaiono dopo poco tempo. Per evitare questo ho anche forzato l'inserimento delle migliori soluzioni nell'array finale:

tmp_pop.each { |boid| boid.evaluate_fitness(@values) }
minfit = (tmp_pop.min { |x, y| x.fitness <=> y.fitness }).fitness
bestfit = (best.min { |x, y| x.fitness <=> y.fitness}).fitness
if bestfit < minfit then
tmp_pop[-(@crossover_number)..-1] = best
end
Ma anche cosė le soluzioni con fitness bassa continuano a scomparire, e rimane sempre una funzione stupida che si impone sulle altre... Fino a non poco tempo fa, risultava addirittura che questa funzione rimpiazzasse tutte le altre (non si sa come). Qualcuno mi sa aiutare?

Loading