alexiskhb

GA

Dec 12th, 2018
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.96 KB | None | 0 0
  1. // Взято из книги
  2. // https://www.crcpress.com/Numerical-Methods-Algorithms-and-Tools-in-C/Dos-Passos/p/book/9780849374791
  3.  
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Collections;
  10.  
  11.  
  12. namespace ConsoleApplication
  13. {
  14.     class Program
  15.     {
  16.         private static Random rand = new Random();
  17.         public delegate double GAFunction(double[] values);
  18.  
  19.         //Use the Visual C\# built-in random number generator
  20.         //generator or one of your own choosing here. This section
  21.         //was commented out because there is already a global
  22.         //instantiation of a random class object that was
  23.         //initialized ealier in this demonstration file.
  24.         //private static Random rand = new Random();
  25.  
  26.         //A Genetic Algorithm class
  27.         public class GA
  28.         {
  29.             public double MutationRate;
  30.             public double CrossoverRate;
  31.             public int ChromosomeLength;
  32.             public int PopulationSize;
  33.             public int GenerationSize;
  34.             public double TotalFitness;
  35.             public bool Elitism;
  36.             private ArrayList CurrentGenerationList;
  37.             private ArrayList NextGenerationList;
  38.             private ArrayList FitnessList;
  39.             static private GAFunction getFitness;
  40.             public GAFunction FitnessFunction
  41.             {
  42.                 get { return getFitness; }
  43.                 set { getFitness = value; }
  44.             }
  45.  
  46.             //Constructor with user specified crossover rate,
  47.             //mutation rate, population size, generation size
  48.             //and chromosome length.
  49.             public GA(double XoverRate, double mutRate, int popSize, int genSize, int ChromLength)
  50.             {
  51.                 Elitism = false;
  52.                 MutationRate = mutRate;
  53.                 CrossoverRate = XoverRate;
  54.                 PopulationSize = popSize;
  55.                 GenerationSize = genSize;
  56.                 ChromosomeLength = ChromLength;
  57.             }
  58.  
  59.             // Method which starts the GA executing.
  60.             public void LaunchGA()
  61.             {
  62.                 //Create the arrays to hold the fitness,
  63.                 //current and next generation lists
  64.                 FitnessList = new ArrayList();
  65.                 CurrentGenerationList = new ArrayList(GenerationSize);
  66.                 NextGenerationList = new ArrayList(GenerationSize);
  67.                 //and initilize the mutation rate.
  68.                 Chromosome.ChromosomeMutationRate = MutationRate;
  69.  
  70.                 //Create the initial chromosome population by repeatedly
  71.                 //calling the user supplied fitness function
  72.                 for (int i = 0; i < PopulationSize; i++)
  73.                 {
  74.                     Chromosome g = new Chromosome(ChromosomeLength, true);
  75.                     CurrentGenerationList.Add(g);
  76.                 }
  77.  
  78.                 //Rank the initial chromosome population
  79.                 RankPopulation();
  80.  
  81.                 //Loop through the entire generation size creating
  82.                 //and evaluating generations of new chromosomes.
  83.                 for (int i = 0; i < GenerationSize; i++)
  84.                 {
  85.                     CreateNextGeneration();
  86.                     RankPopulation();
  87.                 }
  88.             }
  89.  
  90.             //After ranking all the chromosomes by fitness, use a
  91.             //"roulette wheel" selection method that allocates a large
  92.             //probability of being selected to those chromosomes with the
  93.             //highest fitness. That is, preference in the selection process
  94.             //is biased towards those chromosomes exhibiting highest fitness.
  95.             private int RouletteSelection()
  96.             {
  97.                 double randomFitness = rand.NextDouble() * TotalFitness;
  98.                 int idx = -1;
  99.                 int mid;
  100.                 int first = 0;
  101.                 int last = PopulationSize - 1;
  102.                 mid = (last - first) / 2;
  103.                 while (idx == -1 && first <= last)
  104.                 {
  105.                     if (randomFitness < (double)FitnessList[mid])
  106.                     { last = mid; }
  107.                     else if (randomFitness > (double)FitnessList[mid])
  108.                     { first = mid; }
  109.                     mid = (first + last) / 2;
  110.                     if ((last - first) == 1) idx = last;
  111.                 }
  112.                 return idx;
  113.             }
  114.  
  115.             // Rank population and then sort it in order of fitness.
  116.             private void RankPopulation()
  117.             {
  118.                 TotalFitness = 0;
  119.                 for (int i = 0; i < PopulationSize; i++)
  120.                 {
  121.                     Chromosome g = ((Chromosome)CurrentGenerationList[i]);
  122.                     g.ChromosomeFitness = FitnessFunction(g.ChromosomeGenes);
  123.                     TotalFitness += g.ChromosomeFitness;
  124.                 }
  125.                 CurrentGenerationList.Sort(new ChromosomeComparer());
  126.                 double fitness = 0.0;
  127.                 FitnessList.Clear();
  128.                 for (int i = 0; i < PopulationSize; i++)
  129.                 {
  130.                     fitness += ((Chromosome)CurrentGenerationList[i]).ChromosomeFitness;
  131.                     FitnessList.Add((double)fitness);
  132.                 }
  133.             }
  134.  
  135.             //Create a new generation of chromosomes. There are many
  136.             //different ways to do this. The basic idea used here is
  137.             //to first check to see if the elitist flag has been set.
  138.             //If so, then copy the chromosomes from this generation
  139.             //to the next before looping through the entire chromosome
  140.             //population spawning and mutating children. Finally, if the
  141.             //elitism flag has been set, then copy the best chromosomes
  142.             //to the new population.
  143.             private void CreateNextGeneration()
  144.             {
  145.                 NextGenerationList.Clear();
  146.                 Chromosome g = null;
  147.                 if (Elitism)
  148.                     g = (Chromosome)CurrentGenerationList[PopulationSize - 1];
  149.                 for (int i = 0; i < PopulationSize; i += 2)
  150.                 {
  151.                     int pidx1 = RouletteSelection();
  152.                     int pidx2 = RouletteSelection();
  153.                     Chromosome parent1, parent2, child1, child2;
  154.                     parent1 = ((Chromosome)CurrentGenerationList[pidx1]);
  155.                     parent2 = ((Chromosome)CurrentGenerationList[pidx2]);
  156.  
  157.                     if (rand.NextDouble() < CrossoverRate)
  158.                     { parent1.Crossover(ref parent2, out child1, out child2); }
  159.                     else
  160.                     {
  161.                         child1 = parent1;
  162.                         child2 = parent2;
  163.                     }
  164.                     child1.Mutate();
  165.                     child2.Mutate();
  166.                     NextGenerationList.Add(child1);
  167.                     NextGenerationList.Add(child2);
  168.                 }
  169.                 if (Elitism && g != null) NextGenerationList[0] = g;
  170.                 CurrentGenerationList.Clear();
  171.                 for (int i = 0; i < PopulationSize; i++)
  172.                     CurrentGenerationList.Add(NextGenerationList[i]);
  173.             }
  174.  
  175.             //Extract the best values based on fitness from the current generation.
  176.             //Since the ranking process already sorted the latest current generation
  177.             //list, just pluck out the best values from the current generation list.
  178.             public void GetBestValues(out double[] values, out double fitness)
  179.             {
  180.                 Chromosome g = ((Chromosome)CurrentGenerationList[PopulationSize - 1]);
  181.                 values = new double[g.ChromosomeLength];
  182.                 g.ExtractChromosomeValues(ref values);
  183.                 fitness = (double)g.ChromosomeFitness;
  184.             }
  185.         }
  186.  
  187.         public class Chromosome
  188.         {
  189.             public double[] ChromosomeGenes;
  190.             public int ChromosomeLength;
  191.             public double ChromosomeFitness;
  192.             public static double ChromosomeMutationRate;
  193.  
  194.             //Chromosome class constructor
  195.             //Actual functionality is to set up an array
  196.             //called ChromosomeGenes and depending on the
  197.             //boolean flag createGenes, it may or may not
  198.             //fill this array with random values from 0 to 1
  199.             //up to some specified ChromosomeLength
  200.             public Chromosome(int length, bool createGenes)
  201.             {
  202.                 ChromosomeLength = length;
  203.                 ChromosomeGenes = new double[length];
  204.                 if (createGenes)
  205.                 {
  206.                     for (int i = 0; i < ChromosomeLength; i++)
  207.                         ChromosomeGenes[i] = rand.NextDouble();
  208.                 }
  209.             }
  210.  
  211.             //Creates two offspring children using a single crossover point.
  212.             //The basic idea is to first pick a random position, create two
  213.             //children and then swap their genes starting from the randomly
  214.             //picked position point.
  215.             public void Crossover(ref Chromosome Chromosome2, out Chromosome child1, out Chromosome child2)
  216.             {
  217.                 int position = (int)(rand.NextDouble() * (double)ChromosomeLength);
  218.                 child1 = new Chromosome(ChromosomeLength, false);
  219.                 child2 = new Chromosome(ChromosomeLength, false);
  220.                 for (int i = 0; i < ChromosomeLength; i++)
  221.                 {
  222.                     if (i < position)
  223.                     {
  224.                         child1.ChromosomeGenes[i] = ChromosomeGenes[i];
  225.                         child2.ChromosomeGenes[i] = Chromosome2.ChromosomeGenes[i];
  226.                     }
  227.                     else
  228.                     {
  229.                         child1.ChromosomeGenes[i] = Chromosome2.ChromosomeGenes[i];
  230.                         child2.ChromosomeGenes[i] = ChromosomeGenes[i];
  231.                     }
  232.                 }
  233.             }
  234.  
  235.             //Mutates the chromosome genes by randomly switching them around
  236.             public void Mutate()
  237.             {
  238.                 for (int position = 0; position < ChromosomeLength; position++)
  239.                 {
  240.                     if (rand.NextDouble() < ChromosomeMutationRate)
  241.                         ChromosomeGenes[position] = (ChromosomeGenes[position] + rand.NextDouble()) / 2.0;
  242.                 }
  243.             }
  244.  
  245.             //Extracts the chromosome values
  246.             public void ExtractChromosomeValues(ref double[] values)
  247.             {
  248.                 for (int i = 0; i < ChromosomeLength; i++)
  249.                     values[i] = ChromosomeGenes[i];
  250.             }
  251.         }
  252.  
  253.         //Compares two chromosomes by their fitness values
  254.         public sealed class ChromosomeComparer : IComparer
  255.         {
  256.             public int Compare(object x, object y)
  257.             {
  258.                 if (!(x is Chromosome) || !(y is Chromosome))
  259.                     throw new ArgumentException("Not of type Chromosome");
  260.                 if (((Chromosome)x).ChromosomeFitness > ((Chromosome)y).ChromosomeFitness)
  261.                     return 1;
  262.                 else if (((Chromosome)x).ChromosomeFitness == ((Chromosome)y).ChromosomeFitness)
  263.                     return 0;
  264.                 else
  265.                     return -1;
  266.             }
  267.         }
  268.  
  269.         public static double GenAlgTestFcn(double[] values)
  270.         {
  271.             if (values.GetLength(0) != 2)
  272.                 throw new Exception("should only have 2 args");
  273.  
  274.             double x = values[0]; double y = values[1];
  275.  
  276.             return (15 * x * y * (1 - x) * (1 - y) * Math.Sin(Math.PI * x) * Math.Sin(Math.PI * y));
  277.         }
  278.  
  279.         static void Main(string[] args)
  280.         {
  281.             Console.WriteLine("\nFinding global optimum values to the function:\n");
  282.             Console.WriteLine("f(x,y) = 15xy(1-x)(1-y)sin(pi*x)sin(pi*y)\n");
  283.             Console.WriteLine("by using a genetic algorithm with initial parameters: \n");
  284.             Console.WriteLine("Crossover\t=80%");
  285.             Console.WriteLine("Mutation\t=5%");
  286.             Console.WriteLine("Population size\t=100");
  287.             Console.WriteLine("Generations\t=2000");
  288.             Console.WriteLine("Chromosome size\t=2\n");
  289.             Console.WriteLine("Actual max values are: x_max = 0.5 and y_max = 0.5\n");
  290.  
  291.             GA ga = new GA(0.8, 0.05, 100, 2000, 2);
  292.             ga.FitnessFunction = new GAFunction(GenAlgTestFcn);
  293.             ga.Elitism = true;
  294.             ga.LaunchGA();
  295.  
  296.             double[] values; double fitness;
  297.             ga.GetBestValues(out values, out fitness);
  298.  
  299.             Console.WriteLine("Calculated max values are: \nx_max = {0} \ny_max = {1}\n", values[0], values[1]);
  300.             Console.WriteLine("f(x_max,y_max) = f({0},{1}) = {2}", values[0], values[1], fitness);
  301.             Console.WriteLine("\nPress ENTER to continue program");
  302.             Console.ReadLine();
  303.         }
  304.     }
  305. }
Add Comment
Please, Sign In to add comment