遗传算法初始种子多样性使用值编码C#

我想知道以下内容:
如何使用值编码有效地生成具有高度多样性的染色体的初始生成?
一种方法是网格初始化,但速度太慢.

到目前为止,我一直在使用.NET中的Random类来选择值编码中的随机值,但是,尽管值是均匀分布的,但是从这些染色体计算的适应度函数值却不是.这是染色体初始化的代码:

 public Chromosome(Random rand) 
        {
            Alele = new List<double>();
            for (int i = 0; i < ChromosomeLength; i++)
            {
                Alele.Add(rand.NextDouble() * 2000 - 1000);
            }
        }

因此,我开发了一个函数来计算来自新的,随机制作的染色体(上层代码)的适应度,如果适应性与染色体列表中已有的任何其他相似,则随机制作新的染色体并计算其适应度并重复此过程直到他的健康状况与列表中的健身状况不同.

以下是此部分的代码:

private bool CheckSimilarFitnes(List<Chromosome> chromosome, Chromosome newCandidate) 
    {
     Boolean flag=false;
     double fitFromList, fitFromCandidate;
     double fitBigger,fitSmaller;

     foreach (var listElement in chromosome)
      {  
      fitFromList = listElement.CalculateChromosomeFitness(listElement.Alele);
      fitFromCandidate = newCandidate.CalculateChromosomeFitness(newCandidate.Alele);
      fitBigger = fitFromList >= fitFromCandidate ? fitFromList : fitFromCandidate;
      fitSmaller =  fitFromList < fitFromCandidate ? fitFromList : fitFromCandidate;

            if ((fitFromList / fitFromCandidate) < 1.5) 
                return false
      }

     else return true;

    }

但是,我在列表中的染色体越多,添加一个新染色体就需要更长的时间,其健康状况与已经存在的其他染色体相当.

那么,有没有办法让这个网格初始化更快,像这样制作80条染色体需要几天时间?

解决方法:

这里有一些可能有用的代码(我刚才写的):GA for ordering 10 values spaced by 1.0.它首先是100个完全随机的等位基因,这正是你的代码开始的方式.

我给GA解决的目标是按升序排序值,间隔为1.0.它通过计算1.0对中每对样本的标准偏差,在适应度函数Eval_OrderedDistance中执行此操作.当适应度趋向于0.0时,等位基因应该开始按顺序出现.

第0代最适合染色体完全随机,其他染色体也是如此.你可以看到健身值非常高(即不好):

GEN: fitness   (allele, ...)
  0: 375.47460 (583.640, -4.215, -78.418, 164.228, -243.982, -250.237, 354.559, 374.306, 709.859, 115.323) 

随着世代的继续,适应度(1.0的标准差)减少,直到它在100,000代中几乎完美:

  100: 68.11683 (-154.818, -173.378, -170.846, -193.750, -198.722, -396.502, -464.710, -450.014, -422.194, -407.162)
  ...
10000:  6.01724 (-269.681, -267.947, -273.282, -281.582, -287.407, -293.622, -302.050, -307.582, -308.198, -308.648)
  ...
99999:  0.67262 (-294.746, -293.906, -293.114, -292.632, -292.596, -292.911, -292.808, -292.039, -291.112, -290.928)

该代码的有趣部分是适应度函数:

// try to pack the aleles together spaced apart by 1.0
// returns the standard deviation of the samples from 1.0
static float Eval_OrderedDistance(Chromosome c) {
    float sum = 0;
    int n = c.alele.Length;
    for(int i=1; i<n; i++) {
        float diff = (c.alele[i] - c.alele[i-1]) - 1.0f; 
        sum += diff*diff; // variance from 1.0
    }

    return (float)Math.Sqrt(sum/n);
}

而突变.我使用了一个简单的交叉和“完全改变一个等位基因”:

Chromosome ChangeOne(Chromosome c) {
    Chromosome d = c.Clone();
    int i = rand.Next() % d.alele.Length;
    d.alele[i] = (float)(rand.NextDouble()*2000-1000);
    return d;
}

我使用精英主义来保持最好的染色体的一个精确副本.然后使用突变和交叉生成100个新的染色体.

这听起来像是在计算适应度的方差,这当然会告诉你,你的人口中的适合度大致相同.我发现你定义健身功能非常重要.适应度函数越精细,您就可以越多地区分您的染色体.显然,您的适应度函数返回完全不同染色体的相似值,因为您的gen 0返回68e-19的适应度方差.

你能分享你的健康计算吗?或者你要求GA解决什么问题?我认为这可以帮助我们帮助你.

[编辑:添加明确的健身分享/ Niching]

我重新考虑了这一点和updated my code.如果你想保持独特的染色体,你必须比较它们的内容(正如其他人提到的那样).一种方法是计算它们之间的标准差.如果它低于某个阈值,您可以认为它们是相同的.从类染色体:

// compute the population standard deviation
public float StdDev(Chromosome other) {
    float sum = 0.0f;
    for(int i=0; i<alele.Length; i++) {
        float diff = other.alele[i] - alele[i];
        sum += diff*diff;
    }
    return (float)Math.Sqrt(sum);
}

我想Niching会给你你想要的东西.它比较了人群中的所有染色体,以确定它们的相似性,并为每个染色体分配一个“利基”值.然后使用称为Explicit Fitness Sharing的技术将染色体“惩罚”为属于利基.适合度值除以每个生态位中的染色体数量.因此,如果你有三个利基A组(A,A,A)而不是那个可能被选择3倍的利基,它被视为一个单一的实体.

我将我的样本与Explicit Fitness Sharing进行了比较.最大STDDEV为500且Niching关闭,大约有18-20个壁龛(因此在100个人口中每个项目基本上重复5个).随着Niching的开启,大约有85个壁龛.这是人群中85%独特的染色体.在我的测试输出中,你可以看到diversity after 17000 generations.

这是niching代码:

// returns: total number of niches in this population
// max_stddev -- any two chromosomes with population stddev less than this max
//               will be grouped together
int ComputeNiches(float max_stddev) {
    List<int> niches = new List<int>();

    // clear niches
    foreach(var c in population) {
        c.niche = -1;
    }

    // calculate niches
    for(int i=0; i<population.Count; i++) {
        var c = population[i];
        if( c.niche != -1) continue; // niche already set

        // compute the niche by finding the stddev between the two chromosomes 
        c.niche = niches.Count;
        int count_in_niche = 1; // includes the curent Chromosome
        for(int j=i+1; j<population.Count; j++) {
            var d = population[j];
            float stddev = c.StdDev(d);
            if(stddev < max_stddev) {
                d.niche = c.niche; // same niche
                ++count_in_niche;
            }
        }
        niches.Add(count_in_niche);
    }

    // penalize Chromosomes by their niche size
    foreach(var c in population) {
        c.niche_scaled_fitness = c.scaled_fitness / niches[c.niche];
    }

    return niches.Count;
}

[编辑:安东代码的后分析和更新]

我知道这可能不是解决家庭作业问题的正确论坛,但是因为我在知道这一点之前做了很多努力,并且我有很多乐趣这样做,我认为它只会对Anton有所帮助.

Genotip.cs,Kromosom.cs,KromoMain.cs

这段代码保持了良好的多样性,我能够在一次运行中将“原始适应度”降低到47,这在你的情况下是平均误差.那非常接近!

正如我的评论中所述,我想尝试帮助您完成编程,而不仅仅是帮助您完成作业.请阅读这些对您工作的分析.

>正如我们所料,没有必要从一开始就建立一个“更多样化”的人口.只需生成一些完全随机的Kromosomes.
>你的突变和交叉是非常具有破坏性的,你只有少数几个.我添加了几个似乎更适合这个问题的新运算符.
>你丢掉了最好的解决方案.当我的代码仅使用锦标赛选项运行时,会有一个Kromo比其余的都好99%.选择锦标赛时,最有价值的东西很可能会被遗忘.我添加了一些“精英主义”,它为下一代保留了该值的副本.
>考虑面向对象的技术.将我发给你的重写与原始代码进行比较.
>不要重复代码.您有两个不同类的采样参数.
>保持代码清洁.有几个未使用的代码部分.特别是在向SO提交问题时,请尝试缩小范围,删除未使用的代码,并进行一些清理.
>评论你的代码!我已经对重新评估做了很多评论.我知道这是塞尔维亚语,但即使是一些评论也会帮助其他人了解你在做什么以及你打算做什么.
>总体而言,很好地完成了一些比较复杂的事情,如锦标赛选择
>首选double []数组而不是List.开销较少.此外,甚至不需要几个List临时变量.你的结构

List temp = new List();
for(…){
    temp.add(值);
}
for(temp中的每个值){
    sum = value
}
average = sum / temp.Count

很容易写成:

sum = 0
for(...) {
    sum += value;
}
average = sum / count;

>在几个地方你忘了初始化一个循环变量,这可能很容易添加到你的问题.这样的事情会导致严重的问题,并且在你的健身代码中还有一两个其他地方

double fit = 0;
for(每条染色体){
    //你应该在LOOP内初始化
    for(每个等位基因){
        fit = …;
    }
    适合/ =计数;
}

祝你好运!

上一篇:nginx 反向代理及 https 证书配置


下一篇:java-如何将测试功能应用于遗传算法