decode函数_使用遗传算法求解函数最值

问题说明

使用遗传算法求解三元函数z的最大值。

流程

1、构造初始种群

2、计算初始种群的每个个体的值

3、轮盘选择法进行交叉,生成子代个体

4、变异

5、如果未到终止条件,则回到步骤1

6、终止,选出最佳个体的编码

构造初始种群

如何对数据进行编码

我们需要注意到x,y本来应该是个连续值,但是计算机表示数据都是离散的(都是0,1嘛,总有数字表示不到)。那么应该如何表示呢。针对这道题,我是这样做的:

我们先想一下,15位的二进制能表示多少个值?

假设,我们把(-1,1)等分为32768份,第一份是-1(0000 0000 000 15个0,也就是十进制0),第二份是-0.99993896484375(0000 0000 001 十进制1)...,那这样不就能表示一部分小数了?(当然了,位数越大能表示的数字越多)。

写成函数就是:

写成代码就是:

# 函数功能:将一个30位的编码转换为x,y的十进制解

生成指定个数的个体

直接上代码:

# 功能:生成初始化种群

以上就是如何生成初始种群。需要注意的是:因为某一个个体的评价函数可以是负值。而后面轮盘选择法要求所有值是正值。因此,我设定在生成初始种群时,如果评价值为负,则重新生成。

计算初始种群每个个体的评价值

这个功能就很简单了,把x,y通过decode转为十进制,再利用

计算出结果就行了

代码:

# 功能:计算x,y对应的函数值

轮盘选择法,交叉生成子代

轮盘选择

轮盘选择的目的是从种群中选出两个个体。而且要求:表现越优异的个体,被选中的概率越大。那么怎么量化每个个体被选中的概率呢:

我们首先计算出种群中所有的个体的评价值(V1,V2,V3...)的总和:

然后我们设Vi被选中的概率为Pi:

那怎么用代码实现呢?

思路就是我把每个个体的被选中的概率放到一个数组中:[0.2,0.3,0.1,0.4]

那么其逐项累加的和组成的列表就是:[0.2,0.5(0.2+0.3),0.6(0.2+0.3+0.1),1(0.2+0.3+0.1+0.4)]

接着,我们随机生成一个[0,1]的数字,如果它在区间[0,0.2]那我们就选择第一个个体,如果它落在(0.2,0.5]之间那我们就选择第二个个体。以此类推。

对应代码:

# 功能:获取一个父母进行交叉

交叉生成子代

之前说到,一个子代30位二进制(前15位代表x,后15位代表y),交叉的操作其实就是:在这30位中随机选取一位,比如说选取第8位,那么就把父亲的前8位拿出来放在前面,母亲的后22位拿出来放在后面,拼起来就变成了一个子代。

对应代码:

# 输入:两个person

注意,我这里设置了,如果生成的子代评价值<0,那么则重新生成。如果怎么交叉(30位遍历完了)都小于0,那么就子代直接就是父亲的复制。

变异

生成一个子代之后就要进行变异。同样的,我们还要设置一个变异概率,即一个个体有多大的概率进行变异。我们设变异概率Pvaria=0.8,接下来我们生成一个(0,1)之间的随机数temp,如果temp<Pvaria那么子代进行变异。

那么变异具体是个怎样的操作呢:30位中间随机抽一位,把这一位的二进制取反即可(1变成0,0变成1)。

具体代码:

# 功能:进行变异,返回一个个体的二进制编码

注意,我们这里还特别设定了,如果变异后的个体评价值没有原个体好,那么返回的还是原个体的二进制编码。

收敛性

这里,由于问题空间比较大,每次收敛到一个完全相同的个体可能性很小。因此我从最优解的近似程度上来看:

我测试了80次,其中最大值在2.599的有74次,占比92.5%,在这一角度,我认为我的参数设置和一些优化的方法使该算法达到了优异的收敛性。

结果

最优个体编码:001011101011101001011101011101

函数最大值:2.25998622121993

完整代码

完整代码在这里:遗传算法实例

如果GitHub速度较慢的话,欢迎关注我的公众号:

40582ddcd0fb5808042b6fe86a31b988.png

发送关键词:遗传算法,即可获取百度云下载链接问题说明

7994a1db4a97e1420159d92f2e624f71.png
专业代写,扫码了解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
遗传算法是一种优化算法,可以用来求解函数的最大。以下是一个简单的用C语言实现遗传算法求解函数最大的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define POP_SIZE 100 // 种群大小 #define CHROM_LEN 20 // 染色体长度 #define MAX_GEN 1000 // 最大迭代次数 #define MUT_RATE 0.01 // 变异率 #define CROSS_RATE 0.6 // 交叉率 #define ELITIST 1 // 是否启用精英选择 #define PI 3.1415926535898 // 求解的目标函数 double func(double x) { return sin(x) * x + 2 * cos(x) * x + 3 * sin(2 * x) * x; } // 随机生成一个染色体 void create_chrom(int chrom[]) { for (int i = 0; i < CHROM_LEN; i++) { chrom[i] = rand() % 2; } } // 计算染色体对应的变量 double decode_chrom(int chrom[]) { double x = 0.0; for (int i = 0; i < CHROM_LEN; i++) { x += chrom[i] * pow(2, i); } return x * 10 / (pow(2, CHROM_LEN) - 1); } // 计算适应度函数 double fitness(int chrom[]) { double x = decode_chrom(chrom); return func(x); } // 选择操作 void selection(int pop[][CHROM_LEN], double fit[], int new_pop[][CHROM_LEN]) { // 计算适应度函数总和 double sum_fit = 0.0; for (int i = 0; i < POP_SIZE; i++) { sum_fit += fit[i]; } // 计算适应度函数概率 double prob[POP_SIZE]; for (int i = 0; i < POP_SIZE; i++) { prob[i] = fit[i] / sum_fit; } // 计算累计概率 double accum_prob[POP_SIZE]; accum_prob[0] = prob[0]; for (int i = 1; i < POP_SIZE; i++) { accum_prob[i] = accum_prob[i - 1] + prob[i]; } // 选择操作 for (int i = 0; i < POP_SIZE; i++) { double r = (double)rand() / RAND_MAX; int j = 0; while (r > accum_prob[j]) { j++; } for (int k = 0; k < CHROM_LEN; k++) { new_pop[i][k] = pop[j][k]; } } } // 交叉操作 void crossover(int pop[][CHROM_LEN], int new_pop[][CHROM_LEN]) { for (int i = 0; i < POP_SIZE; i += 2) { double r = (double)rand() / RAND_MAX; if (r < CROSS_RATE) { int point = rand() % CHROM_LEN; for (int j = point; j < CHROM_LEN; j++) { int temp = new_pop[i][j]; new_pop[i][j] = new_pop[i + 1][j]; new_pop[i + 1][j] = temp; } } } } // 变异操作 void mutation(int new_pop[][CHROM_LEN]) { for (int i = 0; i < POP_SIZE; i++) { for (int j = 0; j < CHROM_LEN; j++) { double r = (double)rand() / RAND_MAX; if (r < MUT_RATE) { new_pop[i][j] = 1 - new_pop[i][j]; } } } } // 精英选择操作 void elitist(int pop[][CHROM_LEN], double fit[], int new_pop[][CHROM_LEN]) { double max_fit = fit[0]; int max_index = 0; for (int i = 1; i < POP_SIZE; i++) { if (fit[i] > max_fit) { max_fit = fit[i]; max_index = i; } } for (int i = 0; i < CHROM_LEN; i++) { new_pop[0][i] = pop[max_index][i]; } } int main() { srand((unsigned int)time(NULL)); int pop[POP_SIZE][CHROM_LEN]; // 种群 int new_pop[POP_SIZE][CHROM_LEN]; // 新的种群 double fit[POP_SIZE]; // 适应度函数 int gen = 0; // 当前迭代次数 // 初始化种群 for (int i = 0; i < POP_SIZE; i++) { create_chrom(pop[i]); } // 迭代优化 while (gen < MAX_GEN) { // 计算适应度函数 for (int i = 0; i < POP_SIZE; i++) { fit[i] = fitness(pop[i]); } // 选择操作 selection(pop, fit, new_pop); // 交叉操作 crossover(pop, new_pop); // 变异操作 mutation(new_pop); // 精英选择操作 if (ELITIST) { elitist(pop, fit, new_pop); } // 更新种群 for (int i = 0; i < POP_SIZE; i++) { for (int j = 0; j < CHROM_LEN; j++) { pop[i][j] = new_pop[i][j]; } } gen++; } // 输出结果 double max_fit = fit[0]; int max_index = 0; for (int i = 1; i < POP_SIZE; i++) { if (fit[i] > max_fit) { max_fit = fit[i]; max_index = i; } } double x = decode_chrom(pop[max_index]); printf("x = %lf, f(x) = %lf\n", x, max_fit); return 0; } ``` 在这个示例代码中,我们使用遗传算法求解了一个函数的最大。具体来说,我们随机生成一个长度为20的01串作为染色体,然后根据染色体编码计算出对应的变量,再将变量带入目标函数计算适应度函数。然后,我们使用选择、交叉、变异等操作对种群进行优化,直到达到最大迭代次数为止。最后,我们输出适应度函数最大的染色体对应的变量函数作为最终结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值