Advertisement
Guest User

C# GA code with Explicit Fitness Sharing

a guest
Sep 22nd, 2012
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.38 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4.  
  5. namespace GA2
  6. {
  7.     class MainClass
  8.     {
  9.         // chromosome definition
  10.         class Chromosome {
  11.  
  12.             public float[] alele;          
  13.             public float fitness;           // raw fitness
  14.             public float scaled_fitness;    // adjusted for better selection
  15.             public int niche;               // for niche scaling
  16.             public float niche_scaled_fitness; // scaled_fitness after applying explicit fitness sharing
  17.            
  18.             public Chromosome(int n, Random rand) {
  19.                 alele = new float[n];
  20.                 for(int i=0; i<n; i++) {
  21.                     alele[i] = (float)(rand.NextDouble()*2000-1000);
  22.                 }
  23.             }
  24.  
  25.             // create a new empty chromosome
  26.             public Chromosome(int n) {
  27.                 alele = new float[n];
  28.             }
  29.  
  30.             // clones this chromosome
  31.             public Chromosome Clone() {
  32.                 Chromosome c =  new Chromosome(alele.Length);
  33.                 for(int i=0; i<alele.Length; i++) {
  34.                     c.alele[i] = alele[i];
  35.                 }
  36.                 return c;
  37.             }
  38.  
  39.             // compute the population standard deviation
  40.             public float StdDev(Chromosome other) {
  41.                 float sum = 0.0f;
  42.                 for(int i=0; i<alele.Length; i++) {
  43.                     float diff = other.alele[i] - alele[i];
  44.                     sum += diff*diff;
  45.                 }
  46.                 return (float)Math.Sqrt(sum);
  47.             }
  48.  
  49.             // string representation (MonoDevelop crashes for some reason
  50.             // if this is the ToString override)
  51.             public string ConvertToString ()
  52.             {
  53.                 StringBuilder sb = new StringBuilder();
  54.                 sb.AppendFormat("{0:0.00000} niche={1} (", fitness, niche);
  55.                 for(int i=0; i<alele.Length; i++) {
  56.                     if(i > 0) {
  57.                         sb.Append(", ");
  58.                     }
  59.                     sb.AppendFormat("{0:0.000}", alele[i]);
  60.                 }
  61.                 sb.Append(")");
  62.                 return sb.ToString();
  63.             }
  64.         }
  65.  
  66.         // roulette selection selects items proportionally
  67.         // to their fitness. Here a generic function is used
  68.         // to extract the value for the roulette selection
  69.         class Roulette<T> {
  70.             Random rand;
  71.             List<T> items = new List<T>();
  72.             float sum;
  73.             Func<T,float> fn;
  74.  
  75.             public Roulette(Random rand, Func<T,float> fn) {
  76.                 this.rand = rand;
  77.                 this.sum = 0.0f;
  78.                 this.fn = fn;
  79.             }
  80.  
  81.             public void Add(T t) {
  82.                 items.Add(t);
  83.                 sum += fn(t);
  84.             }
  85.  
  86.             public T Select() {
  87.                 float f = (float)(rand.NextDouble()*sum);
  88.                 float localsum = 0.0f;
  89.                 foreach(T t in items) {
  90.                     localsum += fn(t);
  91.                     if(localsum >= f) {
  92.                         return t;
  93.                     }
  94.                 }
  95.  
  96.                 // this shouldn't happen, so just return the last item in the list
  97.                 return items[ items.Count - 1 ];
  98.             }
  99.         }
  100.        
  101.         List<Chromosome> population;
  102.         int generation;
  103.         Random rand;
  104.  
  105.         int POPULATION_SIZE = 100;
  106.         int MAX_GENERATIONS = 100000;
  107.         int ALELE_LENGTH = 10;
  108.         float NICHE_MAX_STDDEV = 500.0f;
  109.  
  110.         public static void Main (string[] args) {
  111.             new MainClass().Run();
  112.         }
  113.  
  114.         MainClass() {
  115.         }
  116.  
  117.         public void Run() {
  118.             rand = new Random();
  119.             generation = 0;
  120.             Seed();
  121.  
  122.             for(int i=0; i<MAX_GENERATIONS; i++) {
  123.  
  124.                 // evaluate fitness
  125.                 Eval(Eval_OrderedDistance);
  126.  
  127.                 // scale fitness
  128.                 Scale_Invert(population);
  129.  
  130.                 // sort so that the fittest is on top (using scaled fitness values)
  131.                 population.Sort( SortByDecreasingFitness );
  132.  
  133.                 // compute niches
  134.                 int niche_count = ComputeNiches(NICHE_MAX_STDDEV);
  135.  
  136.                 if(generation % 1000 == 0) {
  137.                     // print entire population every 1000 iterations
  138.                     for(int j=0; j<population.Count; j++) {
  139.                         Console.WriteLine( generation + "[" + j + "]: " + population[j].ConvertToString());
  140.                     }
  141.                 }
  142.                 else {
  143.                     // print out the best-so-far
  144.                     Console.WriteLine( generation + " nicheCount=" + niche_count + " : " + population[0].ConvertToString() );
  145.                 }
  146.  
  147.                 // perform mutations to create the next generation
  148.                 Mutate();
  149.  
  150.                 ++generation;
  151.             }
  152.         }
  153.  
  154.         // seed the population with completely random values
  155.         public void Seed() {
  156.             population = new List<Chromosome>();
  157.             for(int i=0; i<POPULATION_SIZE; i++) {
  158.                 population.Add( new Chromosome(ALELE_LENGTH,rand));
  159.             }
  160.         }
  161.  
  162.         // calculate the fitness of a chromosome
  163.         void Eval(Func<Chromosome,float> fitnessFunc) {
  164.             foreach(var chromosome in population) {
  165.                 chromosome.fitness = fitnessFunc(chromosome);
  166.             }
  167.         }
  168.  
  169.         // Sorting methods
  170.         int SortByIncreasingFitness(Chromosome a, Chromosome b) {
  171.             if(a.scaled_fitness < b.scaled_fitness) return -1;
  172.             else if (a.scaled_fitness > b.scaled_fitness) return 1;
  173.             return 0;
  174.         }
  175.  
  176.         int SortByDecreasingFitness(Chromosome a, Chromosome b) {
  177.             if(a.scaled_fitness < b.scaled_fitness) return 1;
  178.             else if (a.scaled_fitness > b.scaled_fitness) return -1;
  179.             return 0;
  180.         }
  181.  
  182.         // Run the mutation and crossovers
  183.         void Mutate() {
  184.  
  185.             // start a new population
  186.             var new_population = new List<Chromosome>();
  187.            
  188.             // elitism, always keep the best
  189.             Chromosome best = population[0];
  190.             new_population.Add( best );
  191.  
  192.             // build the roulette selector
  193.             Roulette<Chromosome> roulette = new Roulette<Chromosome>(rand,
  194.                 //(c)=>{ return c.scaled_fitness; }
  195.                 (c)=>{ return c.niche_scaled_fitness; }
  196.             );
  197.             foreach(var c in population) {
  198.                 roulette.Add(c);
  199.             }
  200.  
  201.             // mutations
  202.             for(int i=0; i<POPULATION_SIZE; i++) {
  203.                 Chromosome c;
  204.  
  205.                 // half time choose crossover, half time choose mutation
  206.                 if(rand.NextDouble() < 0.5) {
  207.                     // crossover
  208.                     c = Crossover( roulette.Select(), roulette.Select() );
  209.                 }
  210.                 else {
  211.                     // mutate
  212.                     c = ChangeOne( roulette.Select() );
  213.                 }
  214.                 new_population.Add(c);
  215.             }
  216.  
  217.             population =  new_population;
  218.         }
  219.  
  220.         // returns: total number of niches in this population
  221.         // max_stddev -- any two chromosomes with population stddev less than this max
  222.         //               will be grouped together
  223.         int ComputeNiches(float max_stddev) {
  224.             List<int> niches = new List<int>();
  225.  
  226.             // clear niches
  227.             foreach(var c in population) {
  228.                 c.niche = -1;
  229.             }
  230.  
  231.             // calculate niches
  232.             for(int i=0; i<population.Count; i++) {
  233.                 var c = population[i];
  234.                 if( c.niche != -1) continue; // niche already set
  235.  
  236.                 // compute the niche by finding the stddev between the two chromosomes
  237.                 c.niche = niches.Count;
  238.                 int count_in_niche = 1; // includes the curent Chromosome
  239.                 for(int j=i+1; j<population.Count; j++) {
  240.                     var d = population[j];
  241.                     float stddev = c.StdDev(d);
  242.                     if(stddev < max_stddev) {
  243.                         d.niche = c.niche; // same niche
  244.                         ++count_in_niche;
  245.                     }
  246.                 }
  247.                 niches.Add(count_in_niche);
  248.             }
  249.  
  250.             // penalize Chromosomes by their niche size
  251.             foreach(var c in population) {
  252.                 c.niche_scaled_fitness = c.scaled_fitness / niches[c.niche];
  253.             }
  254.  
  255.             return niches.Count;
  256.         }
  257.  
  258.         // Pick a single random value to change to a different single random value
  259.         Chromosome ChangeOne(Chromosome c) {
  260.             Chromosome d = c.Clone();
  261.             int i = rand.Next() % d.alele.Length;
  262.             d.alele[i] = (float)(rand.NextDouble()*2000-1000);
  263.             return d;
  264.         }
  265.  
  266.         // A random crossover mutation
  267.         Chromosome Crossover(Chromosome a, Chromosome b) {
  268.             int location = rand.Next() % a.alele.Length;
  269.  
  270.             Chromosome c = new Chromosome(a.alele.Length);
  271.             for(int i=0; i<location; i++) {
  272.                 c.alele[i] = a.alele[i];
  273.             }
  274.             for(int i=location; i<a.alele.Length; i++) {
  275.                 c.alele[i] = b.alele[i];
  276.             }
  277.             return c;
  278.         }
  279.  
  280.         // try to pack the aleles together spaced apart by 1.0
  281.         // returns the standard deviation of the samples from 1.0
  282.         static float Eval_OrderedDistance(Chromosome c) {
  283.             float sum = 0;
  284.             int n = c.alele.Length;
  285.             for(int i=1; i<n; i++) {
  286.                 float diff = (c.alele[i] - c.alele[i-1]) - 1.0f;
  287.                 sum += diff*diff; // variance from 1.0
  288.             }
  289.  
  290.             return (float)Math.Sqrt(sum/n);
  291.         }
  292.  
  293.         // invert the fitness of the population so that the low raw fitness
  294.         // is converted to the highest fitness in the population
  295.         static void Scale_Invert(IEnumerable<Chromosome> population) {
  296.             float max = float.MinValue;
  297.             foreach(var c in population) {
  298.                 max = Math.Max(c.fitness, max);
  299.             }
  300.             foreach(var c in population) {
  301.                 c.scaled_fitness = max - c.fitness;
  302.             }
  303.         }
  304.  
  305.     }
  306. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement