golang 实现的一个遗传算法的例子

mqyang56 · 2018-11-21 10:15:17 · 1202 次点击 · 预计阅读时间 6 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2018-11-21 10:15:17 的文章,其中的信息可能已经有所发展或是发生改变。

假设有N个任务,需要负载均衡器分配给M个服务器节点去处理。每个任务的任务长度、每台服务器节点(下面简称“节点”)的处理速度已知,请给出一种任务分配方式,使得所有任务的总处理时间最短。

package main

import (
    "fmt"
    "math/rand"
    "sort"
)

const (
    // TaskNum 任务数为100
    TaskNum = 100
    // NodeNum 计算节点数为10
    NodeNum = 10
    // TaskLengthMin 任务长度最小值10
    TaskLengthMin = 10
    // TaskLengthMax 任务长度最大值100
    TaskLengthMax = 100
    // NodeSpeedMin 节点计算能力最小值10
    NodeSpeedMin = 10
    // NodeSpeedMax 节点计算能力最大值100
    NodeSpeedMax = 100
    // IteratorNum 迭代次数100
    IteratorNum = 10000
    // ChromosomeNum 染色体个数10
    ChromosomeNum = 20
    // CopyPercent 复制比例0.2
    CopyPercent = 0.2
    // CrossoverNum 由染色体的数量和复制比例确定,保证每一代的染色体数量都是相同的
    CrossoverNum = ChromosomeNum * (1 - CopyPercent)
)

//tasks[i]表示第i个任务的长度
var tasks []int

//nodes[i]表示第i个节点的处理速度
var nodes []int

// 给指定长度的切片的值赋随机值
func randomIntSlice(length, min, max int) []int {
    m := make([]int, length)
    for i := 0; i < length; i++ {
        m[i] = rand.Intn(max-min) + min
    }
    return m
}

// 生成新一代的染色体
func createGeneration(chromosomeMatrix [][]int, selectionProbability []float64) [][]int {
    newChromosomeMatrix := make([][]int, ChromosomeNum)
    // 第一代
    if chromosomeMatrix == nil {
        for i := 0; i < ChromosomeNum; i++ {
            newChromosomeMatrix[i] = make([]int, TaskNum)
            for j := 0; j < TaskNum; j++ {
                newChromosomeMatrix[i][j] = rand.Intn(NodeNum)
            }
        }
        return newChromosomeMatrix
    }
    // 交叉
    newChromosomeMatrix = crossover(chromosomeMatrix, selectionProbability)
    // 变异
    newChromosomeMatrix = mutation(newChromosomeMatrix)
    // 复制
    newChromosomeMatrix = copy(newChromosomeMatrix, chromosomeMatrix, selectionProbability)
    return newChromosomeMatrix
}

// 交叉
func crossover(chromosomeMatrix [][]int, selectionProbability []float64) (newChromosomeMatrix [][]int) {
    for i := 0; i < CrossoverNum; i++ {
        //父亲染色体
        chromosomeBa := chromosomeMatrix[rws(selectionProbability)]
        //母亲染色体
        chromosomeMa := chromosomeMatrix[rws(selectionProbability)]
        //随机一个交叉位置
        index := rand.Intn(TaskNum)
        //儿子染色体
        var chromosomeSon []int
        chromosomeSon = append(chromosomeSon, chromosomeBa[:index]...)
        chromosomeSon = append(chromosomeSon, chromosomeMa[index:]...)
        newChromosomeMatrix = append(newChromosomeMatrix, chromosomeSon)
    }
    return
}

// 变异
func mutation(chromosomeMatrix [][]int) [][]int {
    //随机找一个染色体
    index := rand.Intn(CrossoverNum)
    //随机找一个任务
    taskIndex := rand.Intn(TaskNum)
    //随机找一个节点
    nodeIndex := rand.Intn(NodeNum)
    chromosomeMatrix[index][taskIndex] = nodeIndex
    return chromosomeMatrix
}

// 复制
func copy(chromosomeMatrix [][]int, oldChromosomeMatrix [][]int, selectionProbability []float64) [][]int {
    indexs := maxn(selectionProbability, ChromosomeNum-CrossoverNum)
    for _, i := range indexs {
        chromosomeMatrix = append(chromosomeMatrix, oldChromosomeMatrix[i])
    }
    return chromosomeMatrix
}

// 找到适应度大的的n个染色体的索引
func maxn(selectionProbability []float64, n int) (indexs []int) {
    //将一维切片,转化成map,key为selectionProbability的值,value为selectionProbability的索引
    m := make(map[float64]int)
    for k, v := range selectionProbability {
        m[v] = k
    }

    //将m的key保存到切片
    var keys []float64
    for k := range m {
        keys = append(keys, k)
    }

    sort.Float64s(keys)

    //获取前n个keys对应m的值
    for i := 0; i < n; i++ {
        indexs = append(indexs, m[keys[len(keys)-i-1]])
    }
    return
}

// 轮盘赌博算法,返回染色体索引
func rws(selectionProbability []float64) (index int) {
    sum := 0.0
    r := rand.Float64()
    for index < len(selectionProbability) {
        sum += selectionProbability[index]
        if sum >= r {
            break
        }
        index++
    }
    return
}

// 计算每一代的最佳时间
func calCalTime(chromosomeMatrix [][]int) float64 {
    min := 0.0
    for i := 0; i < len(chromosomeMatrix); i++ {
        sum := 0.0
        for j := 0; j < len(chromosomeMatrix[0]); j++ {
            nodeIndex := chromosomeMatrix[i][j]
            sum += float64(tasks[j]) / float64(nodes[nodeIndex])
        }
        if min == 0.0 || sum < min {
            min = sum
        }
    }
    return min
}

// 计算适应度函数
func calAdaptability(chromosomeMatrix [][]int) (selectionProbability []float64) {
    var adaptability []float64
    for i := 0; i < len(chromosomeMatrix); i++ {
        sum := 0.0
        for j := 0; j < len(chromosomeMatrix[0]); j++ {
            nodeIndex := chromosomeMatrix[i][j]
            sum += float64(tasks[j]) / float64(nodes[nodeIndex])
        }
        adaptability = append(adaptability, 1.0/sum)
    }

    // 计算基数
    total := 0.0
    for _, v := range adaptability {
        total += v
    }

    //计算选择概率
    for _, v := range adaptability {
        selectionProbability = append(selectionProbability, v/total)
    }
    return selectionProbability
}

// 开始迭代
func goSearch(iteratorNum, chromosomeNum int) {
    chromosomeMatrix := createGeneration(nil, nil)
    fmt.Printf("第0代所需时间:%f \n", calCalTime(chromosomeMatrix))

    for i := 0; i < iteratorNum; i++ {
        selectionProbability := calAdaptability(chromosomeMatrix)
        chromosomeMatrix = createGeneration(chromosomeMatrix, selectionProbability)
        fmt.Printf("第%d代所需时间:%f \n", i+1, calCalTime(chromosomeMatrix))
    }

}

func main() {
    tasks = randomIntSlice(TaskNum, TaskLengthMin, TaskLengthMax)
    nodes = randomIntSlice(NodeNum, NodeSpeedMin, NodeSpeedMax)

    goSearch(IteratorNum, ChromosomeNum)
}

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1202 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传