C#中的遗传算法实现

时间:2014-08-08 19:40:05

标签: c# genetic-algorithm

我最近开始使用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];
        }
    }

4 个答案:

答案 0 :(得分: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];
        }
    }
}

}

答案 1 :(得分:0)

我认为最大的问题是你的选择功能。

GA的成功在很大程度上取决于选择正确的变异,评估和选择技术,虽然乍一看你的选择功能看起来优雅偏斜分布,但你只是根据相对位置来扭曲它(即Pop [0]&lt; Pop [1])但您并没有考虑 彼此之间的差异。

在GA中,最好的个人拥有100.0健身,而第二人拥有99.9而不是最好拥有100.0,第二个拥有75.0,你的选择功能完全忽略了这个事实。

发生了什么,为什么你看到重复的健身价值,是因为你一遍又一遍地采摘大致相同的个体,使你的遗传池停滞不前,并在当地最低限度停滞(或者无论你是什么?寻找)。

如果你寻找像Roullette这样的方法(http://en.wikipedia.org/wiki/Fitness_proportionate_selection),他们会选择概率作为个体适应度的函数除以总体适应度,分享机会&#39;根据他们的行为方式被挑选出来,虽然这种方法也可能被困在当地人手中,但它远不如你现在拥有的那样,这应该会给你一个很好的推动,探索搜索空间。

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

答案 2 :(得分:0)

这是一个问题:

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<Individual>,并允许使用简单的Add()InsertAt()RemoveAt()方法。

PS。同样常见的做法是将PascalCasing用于所有方法和属性。

答案 3 :(得分:0)

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