遗传算法:go语言实现
来源:互联网 发布:才子网络电话录音 编辑:程序博客网 时间:2024/05/14 07:55
tips:写这个遗传算法的另一个目的是为了练习go语言,如有缺陷,请不吝赐教。
下面算法用来求解函数y=x^7+x^6-100x^5+200x^4-300x^3-13579x^2-2468x+123456789函数再(-8,8)上的最小值
对于该问题解空间是非常明确的。对于结果偏差小于0.001则视为未改变。为了方便采用二进制编码我们将解空间换算为(8-(-8))*1000=1600因此每条染色体的基因数可以设为14
种群规模设为20。
执行步骤
1.初始化操作
该步骤主要用来初始化算法需要的一些基础资源。包括设置随机数种子,初始化第一代种群等数据。
2.计算出第一代种群的适应度,这里指函数的值。
3.对适应度进行排序
4.迭代种群,达到最优
4.1 父种群按概率进行交叉操作,交叉位置随机生成。产生子代种群。
4.2 对子种群进行适应度计算。
4.3 对子种群按适应度进行排序
4.4 在父子种群中选择适应度最高的20个作为父种群遗传下去
4.5 是否达到最优
4.6 记录最优值
4.7 按概率进行变异操作。
4.8 对变异后的种群进行计算
4.9 对变异后的种群进行排序
注意:
1.这里变异操作并没有进行每一个基因的按概率变异,而是计算出某个染色体变异的概率,然后按概概率判断当前染色体是否变异,若变异则随机生成变异位进行变异。
2.终止条件即为100次迭代中种群的相邻两代最优适应度的值相差小于0.001的次数达到100次则视为最优。当然这可以根据实际情况进行调整。如果达到最大循环次数任然未达到最优则视为失败。在记录文件末尾打印error。
可以先用该算法进行一个小小的测试,计算y=x^2-4在(-8,8)上的最小值,每一代的最优值记录在GeneticLog文件中。结果贴在代码后面。
//用于求解函数y=x^7+x^6-100x^5+200x^4-300x^3-13579x^2-2468x+123456789在(-8,8)之间的最小值package mainimport ( "math/rand" "fmt" "time" "os" "strconv")//染色体数量const COUNT int = 20//最大循环次数,若超过该次数程序仍然没有终止则退出程序并未达到最优const MAXLOOP int = 1500//两次结果小于该值则认为结果没有改变const MINIMAL_SUB float32 = 0.01//交叉概率const CROSS_PROBABILITY float32 = 0.2//变异概率const CHANGE_PROBABILITY float32 = 0.2type chromosome struct { //用int的后十四位表示染色体的二进制编码 value uint16 //该染色体对应的适应度函数值 suitability float32}type log struct { value uint16 suitability float32 Next *log}//定义染色体组var chromosome_group [COUNT] chromosome//定义子染色体组var chromosome_new_group [COUNT] chromosome//最优染色体var chromosome_most_suitable chromosome//适应度没有改变的次数,达到二十次则认为结果已经最优var suitability_unchange_count int = 0var head, end *logfunc main() { isParent := 1 initialization() calculateSuit(isParent) sortSuit(isParent) for i := 0; i < MAXLOOP; i++ { cross() calculateSuit(0) sortSuit(0) selection() if complete() { break } record() variation() calculateSuit(1) sortSuit(1) } writeLog() fmt.Println("取值为", Binary_to_Decimal(chromosome_most_suitable.value), "时,达到最大适应度", chromosome_most_suitable.suitability, "。")}//将寻找最优解的过程写入文件func writeLog() { file, err := os.Create("./src/main/GeneticLog") if err != nil { fmt.Println(file, err) } defer file.Close() i := 1 for ; head.Next != nil; i++ { d := strconv.FormatFloat(float64(head.Next.suitability), 'f', -1, 32) file.WriteString(d + " ") if i%10 == 0 { file.WriteString("\n") } head = head.Next } d := strconv.FormatFloat(float64(head.suitability), 'f', -1, 32) file.WriteString(d + " ") if i%10 == 0 { file.WriteString("\n") } if complete() { file.WriteString("complete!") } else { file.WriteString("error") }}//检查是否达到最优func complete() bool { if chromosome_group[0].suitability-end.suitability < MINIMAL_SUB && chromosome_group[0].suitability-end.suitability > -MINIMAL_SUB { suitability_unchange_count++ } else { suitability_unchange_count = 0 } if suitability_unchange_count >= UNCHANGE_COUNT_MAX { return true } else { return false }}//变异操作func variation() { for i := 0; i < COUNT; i++ { //判断该染色体是否变异 if rand_ByProbability(1-power(1-CHANGE_PROBABILITY, 14)) == 1 { //选择具体的变异位置 point := rand_Between_TwoNumber(0, 13) mark := uint16(1 << point) chromosome_group[i].value = chromosome_group[i].value ^ mark } }}//记录每次的最优情况func record() { logx := log{} logx.suitability = chromosome_group[0].suitability logx.value = chromosome_group[0].value logx.Next = nil end.Next = &logx end = end.Next chromosome_most_suitable = chromosome_group[0]}//选择适应度最高的COUNT个染色体作为父总群func selection() { for i, j, k := 0, 0, 0; i < COUNT; i++ { if chromosome_group[j].suitability <= chromosome_new_group[k].suitability { chromosome_group[i] = chromosome_group[j] j++ } else { chromosome_group[i] = chromosome_new_group[k] k++ } }}//交叉产生新种群func cross() { var flag [COUNT] int for i, j := 0, 0; i < COUNT; i++ { //随机选择另一条染色体 if flag[i] == 0 { for { j = int(rand_Between_TwoNumber(i, COUNT-1)) if flag[j] == 0 { break } } } //按概率对染色体i,j进行交叉 if rand_ByProbability(CROSS_PROBABILITY) == 1 { mark1 := create_mark(uint16(rand_Between_TwoNumber(0, 13))) mark2 := ^mark1 chromosome_new_group[i].value = (chromosome_group[i].value)&mark1 + (chromosome_group[j].value)&mark2 chromosome_new_group[j].value = (chromosome_group[i].value)&mark2 + (chromosome_group[j].value)&mark1 } else { chromosome_new_group[i] = chromosome_group[i] chromosome_new_group[j] = chromosome_group[j] } }}//按适应度对中群内个体进行排序func sortSuit(isParent int) { if isParent == 1 { for i := 0; i < COUNT; i++ { for j := i + 1; j < COUNT; j++ { if chromosome_group[i].suitability > chromosome_group[j].suitability { temp := chromosome_group[i] chromosome_group[i] = chromosome_group[j] chromosome_group[j] = temp } } } } else { for i := 0; i < COUNT; i++ { for j := i + 1; j < COUNT; j++ { if chromosome_new_group[i].suitability > chromosome_new_group[j].suitability { temp := chromosome_new_group[i] chromosome_new_group[i] = chromosome_new_group[j] chromosome_new_group[j] = temp } } } }}//计算种群每个个体的适应度func calculateSuit(isParent int) { if isParent == 1 { for i := 0; i < COUNT; i++ { x := Binary_to_Decimal(chromosome_group[i].value) //x^7-600x^6-100x^5+200x^4-300x^3-13579x^2-2468x+123456789 chromosome_group[i].suitability = x*(x*(x*(x*(x*(x*(x*(x-600))-100)+200)-300)-13579)-2468) + 123456789 //chromosome_group[i].suitability = (x + 2) * (x - 2) } } else { for i := 0; i < COUNT; i++ { x := Binary_to_Decimal(chromosome_new_group[i].value) //用于求解函数y=x^7+600x^6-100x^5+200x^4-300x^3-13579x^2-2468x+123456789在(-8,8)之间的最小值 chromosome_new_group[i].suitability = x*(x*(x*(x*(x*(x*(x*(x-600))-100)+200)-300)-13579)-2468) + 123456789 //chromosome_new_group[i].suitability = (x + 2) * (x - 2) } }}//初始化染色体func initialization() { //随机数种子,防止每次产生的随机数一样 rand.Seed(int64(time.Now().Nanosecond())) for i := 0; i < COUNT; i++ { chromosome_group[i].value = rand_generate_chromosome() } chromosome_most_suitable.suitability = -100000 suitability_unchange_count = 0 //初始化记录链表 log0 := log{0, 0, nil} head = &log0 end = head head = end}//随机初始化种群,产生0-16000之间的随机数func rand_generate_chromosome() uint16 { return uint16(rand.Intn(16000) + 1)}//实际值转化为二进制表示func Decimal_to_Binary(x float32) uint16 { var y int = int(x) return uint16(y*1000 + 8000)}//二进制值转化为实际值func Binary_to_Decimal(x uint16) float32 { var y float32 = float32(x) return (y - 8000) / 1000}//随机产生具体数字之间的一个数,不包括i包括jfunc rand_Between_TwoNumber(i int, j int) uint16 { if i == j { return uint16(i) } return uint16(i + 1 + rand.Intn(j-i))}//根据概率返回1func rand_ByProbability(p float32) int { if float32(rand.Intn(100)) > 99*p { return 0 } else { return 1 }}//根据交叉位置生成相应的二进制操作数func create_mark(number uint16) uint16 { return (1 << (number + 1)) - 1}//func power(x float32, y int) float32 { result := x for y > 1 { result = result * x y-- } return result}
求解y=x^2-4的最小值的结果
-3.733744 -3.999984 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.999984 -3.9999359 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.999984 -3.9999359 -3.999984 -3.999984 -3.9999359 -3.999984 -3.9999962 -3.999984 -3.9999962 -3.999984 -3.9999359 -3.9999 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.999984 -3.999984 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.999964 -3.999964 -3.999964 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999 -3.9999962 -3.999964 -3.9999962 -3.9999962 -3.9999962 -3.999964 -3.9999962 -3.999964 -3.9999962 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 -3.9999962 -3.999964 -3.9999962 -3.9999962 -3.999984 -3.9999962 -3.9999962 -3.9999962 complete!
求解y=x^7+x^6-100x^5+200x^4-300x^3-13579x^2-2468x+123456789在(-8,8)的最小值
对于这种相差较大的适应度应调整结果不变的判断值,这里是调整为10000,变异概率为0.01时的结果
-490958300 -570994200 -570994200 -570994200 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 -1600633000 complete!
- 遗传算法:go语言实现
- Go语言如何实现遗传算法
- Go语言如何实现遗传算法
- Go语言如何实现遗传算法
- 转载R语言实现遗传算法
- 遗传算法的C语言实现(二)
- Go语言实现LRU算法
- 遗传算法_C语言
- R语言遗传算法
- 原材料配送问题的遗传算法实现(C语言)
- 遗传算法(GA)的C语言实现
- 用遗传算法走迷宫 [Java语言实现]
- 遗传算法Python实现
- JAVA实现遗传算法
- C++遗传算法实现
- Matlab实现遗传算法
- 遗传算法java实现
- 遗传算法及其实现
- word 单个单元格内边距设置
- redis在linux的安装和配置启用/关闭
- TreeMap源码分析解读
- Spring Cloud Config
- 织梦dedecms列表页分页显示为竖排的解决方
- 遗传算法:go语言实现
- Spring mvc拦截器
- 织梦dedecms产品栏目调取子栏目错乱的解决方法
- 父类与子类中的重名问题(shadow)
- Arduino小游戏集合(俄罗斯方块)
- CentOS使用魔改BBR加速网络
- 拉格朗日对偶
- Arduino小游戏集合(2048)
- 织梦dedecms重装或者升级程序需要保存的主要的程序文件