遗传算法:go语言实现

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 main

import (
    "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.2

type 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 = 0
var head, end *log

func 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包括j
func rand_Between_TwoNumber(i int, j int) uint16 {
    if i == j {
        return uint16(i)
    }
    return uint16(i + 1 + rand.Intn(j-i))
}

//根据概率返回1
func 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!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值