0

我正在实现与遗传算法非常相似的东西。所以你经历了多代种群——在一代结束时,你以三种不同的方式“随机”、“突变”和“交叉”创建一个新种群。

目前概率是静态的,但我需要做到这一点,以便突变的概率逐渐增加。我很感激任何方向,因为我有点卡住了..

这就是我所拥有的:

int random = generator.nextInt(10);
if (random < 1)  
    randomlyCreate() 
else if (random > 1 && random < 9 )
    crossover(); 
else  
    mutate();

谢谢你。

4

3 回答 3

1

在你的 if 语句中,用变量替换硬编码的数字,并在每一代开始时更新它们。

您的 if 语句有效地将区间 0 到 10 分成三个箱。mutate()调用vs crossover()vs的概率randomlyCreate()取决于每个 bin 的大小。您可以通过逐渐移动 bin 的边界来调整突变率。

在您的代码中,mutate()有 20% 的时间被调用(当随机数 = 9 或 1 时),randomlyCreate()有 10% 的时间被调用(当随机数 = 0 时),crossover()另外 70% 的时间被调用。

下面的代码在第 0 代开始使用这些相同的比率,但突变率每代增加 1%。所以第 1 代的突变率为 21%,第 2 代的突变率为 22%,以此类推。无论突变率如何,都randomlyCreate()被称为 1 / 7 。crossover()

您可以通过改变getMutationBoundary().

我在下面的代码中使用了浮点数。双打也可以。

如果您最感兴趣的是突变率,则移动突变箱使其最初位于 [0, 2] 可能更直观,然后从那里增加其上边界(2.1、2.2 等)。然后您可以轻松读取突变率(21%、22% 等)。

void mainLoop() {
    // make lots of generations
    for (int generation = 0; generation < MAX_GEN; generation++) {
        float mutationBoundary = getMutationBoundary(generation);   
        float creationBoundary = getCreationBoundary(mutationBoundary);
        createNewGeneration(mutationBoundary, creationBoundary);
        // Do some stuff with this generation, e.g. measure fitness
    }
}

void createNewGeneration(float mutationBoundary, float creationBoundary) {
    // create each member of this generation
    for (int i = 0; i < MAX_POP; i++) {
        createNewMember(mutationBoundary, creationBoundary);
    }
}

void createNewMember(float mutationBoundary, float creationBoundary) {
    float random = 10 * generator.nextFloat();

    if (random > mutationBoundary) {
        mutate();
    }
    else {
        if (random < creationBoundary) {
            randomlyCreate();
        }
        else {
            crossover();
        }
    }
}

float getMutationBoundary(int generation) {
    // Mutation bin is is initially between [8, 10].
    // Lower bound slides down linearly, so it becomes [7.9, 10], [7.8, 10], etc.
    // Subtracting 0.1 each generation makes the bin grow in size.
    // Initially the bin is 10 - 8 = 2.0 units wide, then 10 - 7.9 = 2.1 units wide,
    // and so on. So the probability of mutation grows from 2 / 10 = 20%
    // to 2.1 / 10 = 21% and so on.
    float boundary = 8 - 0.1f * generation;

    if (boundary < 0) {
        boundary = 0;
    }
    return boundary;    
}

float getCreationBoundary(float creationBoundary) {
    return creationBoundary / 8; // fixed ratio
}
于 2013-11-19T19:35:34.160 回答
0

操作员的遗传概率的任何选择都是任意的(如果您使用某些函数来增加或减少概率,这也是有效的)。最好在染色体内编码运算符。例如,您可以添加一些位来编码您使用的所有运算符。生成子代时,您会查看总体中所有元素的这些位,并以与全局考虑的整个总体中运算符的当前情况相等的概率应用运算符。

例如:

void adaptive_probabilities(GA *ga, long chromosome_length) {
    register int i, mut = 1, xover = 1, uxover = 1, ixover = 1, pop;
    char bit1, bit2;

    for (i = 0; i < ga->npop; i++) {
        bit1 = ga->pop[i]->chromosome[chromosome_length - 2];
        bit2 = ga->pop[i]->chromosome[chromosome_length - 1];

        if (bit1 == '0' && bit2 == '0') {
            mut++;
        } else if (bit1 == '0' && bit2 == '1') {
            xover++;
        } else if (bit1 == '1' && bit2 == '0') {
            uxover++;
        } else if (bit1 == '1' && bit2 == '1') {
            ixover++;
        }
    }

    pop = ga->npop + 4;

    ga->prob[0] = mut / (float)pop;
    ga->prob[1] = xover / (float)pop;
    ga->prob[2] = uxover / (float)pop;
    ga->prob[3] = ixover / (float)pop;
}

在我的情况下,我使用两位,因为我的染色体编码为四个运算符(三种类型的交叉 + 突变)。运算符位位于染色体末端。所有概率都 > 0(运算符的计数器从 1 开始),然后我必须正确地标准化所有概率

pop = ga->npop + 4;

然后,我生成一个随机数,用于根据保存在数组 ga->prob 中的计算概率来选择运算符。新子项的最后一位被更改以反映所使用的运算符。

这种机制确保了 GA 的双重搜索:在错误空间(像往常一样)和运算符空间。概率会自动更改并进行优化,因为在计算的任何时刻使用最佳运算符以更高的概率生成子​​级。

于 2014-02-06T12:40:29.293 回答
0

在您当前使用的地方使用一个变量9,并且(例如)将其乘以0.9每次迭代,除非mutate()发生这种情况,在这种情况下您将它乘以3例如。这样,突变的机会缓慢但呈指数增长(是的,这是可能的),直到它们真正发生突变,此时另一个突变的机会像砖头一样下降,整个过程又重新开始。

这些值是完全随机的,并且不基于任何关于突变的知识,但我只是向您展示如何操纵它以每次都具有可变值。另外:如果您使用我刚刚使用的,请确保变量的值设置为 10,如果它超过 10。

于 2013-11-19T15:43:33.323 回答