【问题标题】:Genetic Algorithm implementation in C#C#中的遗传算法实现
【发布时间】:2014-10-02 09:08:21
【问题描述】:

我最近开始使用 C#,目前正在尝试实现 GA to solve Schwefel’s function 的一个版本(参见下面的代码)。该代码基于我构建的工作处理代码。

第一代(前 100 个人)似乎工作正常,但之后适应度函数得到重复值。我确定我在这里遗漏了一些东西,但有人知道可能是什么问题吗?

    public void button21_Click(object sender, EventArgs e)
    {
        Population p;
        // populationNum = 100;
        p = new Population();
        int gen = 0;
        while (gen < 8000)
        {
            p.evolve();
        }
        ++gen;
    }

    //Class Genotype
    public partial class Genotype
    {
        public int[] genes;

        public Genotype()
        {
            genes = new int[2];
            for (int i = 0; i < genes.Length; i++)
            {
                Random rnd = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
                //Random rnd = new Random(0);
                int random = rnd.Next(256);
                genes[i] = (int)random;
            }
        }

        public void mutate()
        {
            //5% mutation rate
            for (int i = 0; i < genes.Length; i++)
            {
                Random rnd = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
                int random = rnd.Next(100);
                if (random < 5)
                {
                    //Random genernd = new Random();
                    int generandom = rnd.Next(256);
                    genes[i] = (int)generandom;
                }
            }
        }
    }

    static Genotype crossover(Genotype a, Genotype b)
    {
        Genotype c = new Genotype();
        for (int i = 0; i < c.genes.Length; i++)
        {
            //50-50 chance of selection
            Random rnd = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));

            float random = rnd.Next(0, 1);
            if (random < 0.5)
            {
                c.genes[i] = a.genes[i];
            }
            else
            {
                c.genes[i] = b.genes[i];
            }
        }
        return c;
    }


    //Class Phenotype
    public partial class Phenotype
    {
        double i_x;
        double i_y;

        public Phenotype(Genotype g)
        {
            i_x = g.genes[0] * 500 / 256;
            i_y = g.genes[1] * 500 / 256;
        }

        public double evaluate()
        {
            double fitness = 0;
            fitness -= (-1.0*i_x * Math.Sin(Math.Sqrt(Math.Abs(i_x)))) + (-1.0*i_y * Math.Sin(Math.Sqrt(Math.Abs(i_y))));
            Console.WriteLine(fitness);
            return fitness;  
        }
    }

    //Class Individual
    public partial class Individual : IComparable<Individual>
    {
        public Genotype i_genotype;
        public Phenotype i_phenotype;
        double i_fitness;

        public Individual()
        {
            this.i_genotype = new Genotype();
            this.i_phenotype = new Phenotype(i_genotype);
            this.i_fitness = 0;
        }

        public void evaluate()
        {
            i_fitness = i_phenotype.evaluate();
        }

        int IComparable<Individual>.CompareTo(Individual objI)
        {
            Individual iToCompare = (Individual)objI;
            if (i_fitness < iToCompare.i_fitness)
            {
                return -1; //if I am less fit than iCompare return -1
            }
            else if (i_fitness > iToCompare.i_fitness)
            {
                return 1; //if I am fitter than iCompare return 1
            }

            return 0; // if we are equally return 0
        }
    }

    static Individual breed(Individual a, Individual b)
    {
        Individual c = new Individual();
        c.i_genotype = crossover(a.i_genotype, b.i_genotype);
        c.i_genotype.mutate();
        c.i_phenotype = new Phenotype(c.i_genotype);
        return c;
    }

    //Class Population
    public class Population
    {
        Individual[] pop;
        int populationNum = 100;

        public Population()
        {
            pop = new Individual[populationNum];
            for (int i = 0; i < populationNum; i++)
            {
                this.pop[i] = new Individual();
                pop[i].evaluate();
            }
            Array.Sort(this.pop);
        }

        public void evolve()
        {
            Individual a = select();
            Individual b = select();
            //breed the two selected individuals
            Individual x = breed(a, b);
            //place the offspring in the lowest position in the population, thus replacing the previously weakest offspring
            pop[0] = x;
            //evaluate the new individual (grow)
            x.evaluate();
            //the fitter offspring will find its way in the population ranks
            Array.Sort(this.pop);
            //rnd = new Random(0);
        }

        Individual select()
        {
            Random rnd = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
            float random = rnd.Next(0, 1);
            //skew distribution; multiplying by 99.999999 scales a number from 0-1 to 0-99, BUT NOT 100
            //the sqrt of a number between 0-1 has bigger possibilities of giving us a smaller number
            //if we subtract that squares number from 1 the opposite is true-> we have bigger possibilities of having a larger number
            int which = (int)Math.Floor(((float)populationNum - 1e-6) * (1.0 - Math.Pow(random, random)));
            return pop[which];
        }
    }

【问题讨论】:

  • 什么是“遗传算法”,对于我们这些老人来说,您是指“遗传算法”吗?
  • 就像约翰桑德斯提到的那样,定义会很好。更好的是到函数的链接,或者对其逻辑的解释。问题可能出在您的逻辑上,也可能不是代码错误?如果我们不知道逻辑,我们就无法帮助解决问题,如果这是原因的话。 @John 是的 GA 是遗传算法。
  • GA 主要基于对问题本身的广泛研究。您可能会遇到收敛,因为您的适应度函数不够好、交叉点有问题,或者您的选择方法不适合此特定问题。
  • 您可能还想在biology.stackexchange.com 尝试您的问题。
  • 旁注:您对Random 的使用是非常随机的,请考虑在发布公共示例时更经常地使用single static generator(除非有重要的理由走其他特定路线)。

标签: c# genetic-algorithm


【解决方案1】:

这是一个我认为它执行良好的更新代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;

    namespace ConsoleApplication8
   {
    class Program
     {
       static Random random = new Random();

        static void Main(string[] args)
        {
        Population p;
        System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt");
        int population = 100;
        p = new Population(file, population);

        int gen = 0;
        while (gen <= 1000)
        {
            p.evolve(file);
            ++gen;
        }
        file.Close();
    }

    public static double GetRandomNumber(double min, double max)
    {
        return (random.NextDouble() * (max - min)) + min;
        //return random.NextDouble() *random.Next(min,max);
    }

    //Class Genotype
    public class Genotype
    {
        public int[] genes;

        public Genotype()
        {
            this.genes = new int[2];
            for (int i = 0; i < genes.Length; i++)
            {
                this.genes[i] = (int)GetRandomNumber(-500.0, 500.0);
            }
        }

        public void mutate()
        {
            //5% mutation rate
            for (int i = 0; i < genes.Length; i++)
            {
                 if (GetRandomNumber(0.0, 100) < 5)
                 {
                    //Random genernd = new Random();
                    this.genes[i] = (int)GetRandomNumber(0.0, 256.0);
                 }
            }
        }
    }

    static Genotype crossover(Genotype a, Genotype b)
    {

        Genotype c = new Genotype();
        for (int i = 0; i < c.genes.Length; i++)
        {
            //50-50 chance of selection
            if (GetRandomNumber(0.0, 1) < 0.5)
            {
                c.genes[i] = a.genes[i];
            }
            else
            {
                c.genes[i] = b.genes[i];
            }
        }
        return c;
    }

    //Class Phenotype
    public class Phenotype
    {
        double i_x;
        double i_y;

        public Phenotype(Genotype g)
        {
            this.i_x = g.genes[0];
            this.i_y = g.genes[1];
        }

        public double evaluate(System.IO.StreamWriter file)
        {
            double fitness = 0;
            //fitness -= i_x + i_y;
            fitness -= (i_x*Math.Sin(Math.Sqrt(Math.Abs(i_x)))) + i_y*(Math.Sin(Math.Sqrt(Math.Abs(i_y))));
            file.WriteLine(fitness);
            return fitness;  
        }
    }

    //Class Individual
    public class Individual : IComparable<Individual>
    {
        public Genotype i_genotype;
        public Phenotype i_phenotype;
        double i_fitness;

        public Individual()
        {
            this.i_genotype = new Genotype();
            this.i_phenotype = new Phenotype(i_genotype);
            this.i_fitness = 0.0;
        }

        public void evaluate(System.IO.StreamWriter file)
        {
            this.i_fitness = i_phenotype.evaluate(file);
        }

        int IComparable<Individual>.CompareTo(Individual objI)
        {
            Individual iToCompare = (Individual)objI;
            if (i_fitness < iToCompare.i_fitness)
            {
                return -1; //if I am less fit than iCompare return -1
            }
            else if (i_fitness > iToCompare.i_fitness)
            {
                return 1; //if I am fitter than iCompare return 1
            }
            return 0; // if we are equally return 0
        }
    }

    public static Individual breed(Individual a, Individual b)
    {
        Individual c = new Individual();
        c.i_genotype = crossover(a.i_genotype, b.i_genotype);
        c.i_genotype.mutate();
        c.i_phenotype = new Phenotype(c.i_genotype);
        return c;
    }

    //Class Population
    public class Population
    {
        Individual[] pop;
        //int populationNum = 100;

        public Population(System.IO.StreamWriter file, int populationNum)
        {
            this.pop = new Individual[populationNum];

            for (int i = 0; i < populationNum; i++)
            {
                this.pop[i] = new Individual();
                this.pop[i].evaluate(file);
            }
            Array.Sort(pop);
        }

        public void evolve(System.IO.StreamWriter file)
        {
            Individual a = select(100);
            Individual b = select(100);
            //breed the two selected individuals
            Individual x = breed(a, b);
            //place the offspring in the lowest position in the population, thus  replacing the previously weakest offspring
            this.pop[0] = x;
            //evaluate the new individual (grow)
            x.evaluate(file);
            //the fitter offspring will find its way in the population ranks
            Array.Sort(pop);
        }

        Individual select(int popNum)
        {
            //skew distribution; multiplying by 99.999999 scales a number from 0-1 to  0-99, BUT NOT 100
            //the sqrt of a number between 0-1 has bigger possibilities of giving us a smaller number
            //if we subtract that squares number from 1 the opposite is true-> we have bigger possibilities of having a larger number
           int which = (int)Math.Floor(((float)popNum - 1E-6) * (1.0 - Math.Pow(GetRandomNumber(0.0, 1.0), 2)));
           return pop[which];
        }
    }
}

}

【讨论】:

    【解决方案2】:

    这是个问题:

    float random = rnd.Next(0, 1);   // returns an integer from 0 to 0 as a float
    // Documentation states the second argument is exclusive
    

    试试

    float random = (float)rnd.NextDouble(); // rnd should be static, init'd once.
    

    并将Individual[] 的所有实例替换为List&lt;Individual&gt;,它包装了一个数组并允许使用简单的Add()、InsertAt() 和RemoveAt() 方法。

    附言。还有一个常见的约定是对所有方法和属性使用PascalCasing。

    【讨论】:

      【解决方案3】:

      我认为最大的问题在于您的选择功能。

      遗传算法的成功很大程度上取决于选择正确的变异、评估和选择技术,尽管乍一看您的选择函数似乎很优雅地倾斜分布,但您只是根据相对位置(即 Pop[0] 它们之间的差异。

      在 GA 中,最好的个人有 100.0 的健康度和第二个有 99.9 与最好的有 100.0 和第二个有 75.0 之间的巨大差异,而您的选择函数完全忽略了这个事实。

      发生了什么,为什么您会看到重复的适应度值,是因为您一遍又一遍地挑选大致相同的个体,使您的基因库停滞不前并停滞在局部最小值(或您正在寻找的最大值) .

      如果您寻找像轮盘赌 (http://en.wikipedia.org/wiki/Fitness_proportionate_selection) 这样的方法,他们会根据个体适应度除以总适应度来选择概率,根据他们的行为方式分享在更多个体中被选中的“机会”,虽然这种方法也可能会被当地人困住,但它远不如你目前所拥有的那样容易,这应该会给你探索搜索空间带来很大的帮助。

      TL;DR - 选择功能不够好,因为它过于严重地扭曲分布并且只考虑相对比较。

      【讨论】:

        【解决方案4】:

        Random.next(int min,int max),将只生成最小值和最大值之间的整数。 尝试 (rnd.NextDouble) 生成一个介于 0 和 1 之间的随机数。 这就是我现在可以提供的帮助:)

        【讨论】:

          猜你喜欢
          • 2020-08-04
          • 1970-01-01
          • 2016-11-28
          • 1970-01-01
          • 2011-05-24
          • 2010-10-19
          • 2012-02-28
          • 2012-07-03
          • 2020-07-20
          相关资源
          最近更新 更多