我正在尝试实现遗传算法,以最大化n个整数变量x1..xn的函数,其中每个变量属于[-n,n]范围。我正在考虑使用二进制编码来表示染色体,但我不确定如何编码负整数。我已经搜索了很长一段时间,但我没有遇到二进制编码的常见公式。 在遗传算法的[-n,n]范围内编码整数的最常用方法是什么? 我希望交叉和变异具有更少的复杂性(更少的条件检查)。如果对于初始填充,而不是在-n和n之间生成数字,我会生成从0到2n的数字并以二进制编码它们然后在解码时,我每次都减去n(对于每个后续生成)吗? / p>
答案 0 :(得分:2)
user1765444的答案很有道理......我只是阅读了sashkello的建议(使用偏移二进制文件可以消除不得不在GA内部使用签名的内容)。使用shashkello和user1765444的答案组合进行交叉和变异等很容易。问题是如果您的数据类型的宽度大于您的范围,那么交叉可能会产生无效的子级。
假设int32具有您需要的宽度。然后是int32数组[n]。你知道有32n位,所以你可以随机取m的交叉点,其中m> = 0且m <1。 32N。您知道位m出现在数组[m / n]中,位位置m%n从msb开始(想象数组只是一个长二进制字符串)。
然后说你有2个父亲int32 parent1 [n]和int32 parent2 [n]。像下面的伪ish代码?在这个交叉中,为了交叉,字符串只是一个二进制字符串(即符号位被视为另一个位)......
免责声明:很抱歉,以下代码粗略准备,未编译,因此可能包含错误......只是想一想!
int child1[n];
uint32 m = rand_like_func(); // random cross over point, a bit position
// in the binary string of length n*32;
uint32 arraySlotForCrossOvr = (uint32)(m / n);
uint32 bitInSlotForCrossOvr = 31 - m % n;
uint32 maskForCrossOvrP2 = (1 << bitInSlotForCrossOvr) - 1;
uint32 maskForCrossOvrP1 = ~maskForCrossOvrP2;
// crossover to create child 1
memcpy(child1, parent1, arraySlotForCrossOvr);
child1[arraySlotForCrossOvr] =
(int32)( ((uint32)parent1[arraySlotForCrossOvr] & maskForCrossOverP1) |
((uint32)parent2[arraySlotForCrossOvr] & maskForCrossOvrP2) )
memcpy(
child1,
parent2 + arraySlotForCrossOvr + 1,
total_num_slots - arraySlotForCrossOvr);
然后你可能必须检测超出范围的孩子,或者让超出范围的孩子在下一轮中得分为零。也许你可以用一些智能来增加交叉,比如将无效值限制到最接近的有效值等?
希望有帮助吗?
此外,我发现“如何解决它:Z. Michalewicz和D Fogel的现代启发式”在尝试理解问题的编码时非常有用:)