require 'rubyneat/dsl' include NEAT::DSL # This defines the controller define "<%= description %>" do # Define the IO neurons inputs <%= inputs.map {|name, klass| "#{name}: #{klass}"}.join(', ') %> outputs <%= outputs.map {|name, klass| "#{name}: #{klass}"}.join(', ') %> # Hidden neuron specification is optional. # The name given here is largely meaningless, but may be useful as some sort # of unique flag. hidden <%= name='hid0'; hidden.map {|klass| name.next!; "#{name}: #{klass}"}.join(', ') %> ### Settings ## General hash_on_fitness false start_population_size 30 population_size 30 max_generations 10000 max_population_history 10 ## Evolver probabilities and SDs # Perturbations mutate_perturb_gene_weights_prob 0.10 mutate_perturb_gene_weights_sd 0.25 # Complete Change of weight mutate_change_gene_weights_prob 0.10 mutate_change_gene_weights_sd 1.00 # Adding new neurons and genes mutate_add_neuron_prob 0.05 mutate_add_gene_prob 0.20 # Switching genes on and off mutate_gene_disable_prob 0.01 mutate_gene_reenable_prob 0.01 interspecies_mate_rate 0.03 mate_only_prob 0.10 #0.7 # Mating survival_threshold 0.20 # top % allowed to mate in a species. survival_mininum_per_species 4 # for small populations, we need SOMETHING to go on. # Fitness costs fitness_cost_per_neuron 0#.00001 fitness_cost_per_gene 0#.00001 # Speciation compatibility_threshold 2.5 disjoint_coefficient 0.6 excess_coefficient 0.6 weight_coefficient 0.2 max_species 20 dropoff_age 15 smallest_species 5 # Sequencing start_sequence_at 0 end_sequence_at 2 ** XOR_INPUTS - 1 end evolve do # This query shall return a vector result that will serve # as the inputs to the critter. query { |seq| # We'll use the seq to create the xor sequences via # the least signficant bits. condition_boolean_vector (0 ... XOR_INPUTS).map{|i| (seq & (1 << i)) != 0} } # Compare the fitness of two critters. We may choose a different ordering # here. compare {|f1, f2| f2 <=> f1 } # Here we integrate the cost with the fitness. cost { |fitvec, cost| fit = XOR_STATES - fitvec.reduce {|a,r| a+r} - cost $log.debug ">>>>>>> fitvec #{fitvec} => #{fit}, cost #{cost}" fit } fitness { |vin, vout, seq| unless vout == :error bin = uncondition_boolean_vector vin bout = uncondition_boolean_vector vout bactual = [xor(*vin)] vactual = condition_boolean_vector bactual fit = (bout == bactual) ? 0.00 : 1.00 #simple_fitness_error(vout, vactual.map{|f| f * 0.50 }) bfit = (bout == bactual) ? 'T' : 'F' $log.debug "(%s) Fitness bin=%s, bout=%s, bactual=%s, vout=%s, fit=%6.3f, seq=%s" % [bfit, bin, bout, bactual, vout, fit, seq] fit else $log.debug "Error on #{vin} [#{seq}]" 1.0 end } stop_on_fitness {|fitness, c| puts "*** Generation Run #{c.generation_num}, best is #{fitness[:best]} ***\n\n" fitness[:best] >= ALMOST_FIT } end report do |rept| $log.info "REPORT #{rept.to_yaml}" end # The block here is called upon the completion of each generation run_engine do |c| $log.info "******** Run of generation %s completed, history count %d ********" % [c.generation_num, c.population_history.size] end