用Java实现简单的遗传算法

遗传算法是解决复杂问题的一种搜索策略,是一种智能计算。他模拟自然界中的种群进化。从这点看,它和神经网络这些算法的起源很像,都是使用计算机去模拟一些自然法则和运作规律。同样,和神经网络一样,遗传算法也是一种基于概率的算法。当然,在现代启发式算法中,很多算法都都是基于概率的,比如神经网络,粒子群算法,模拟退火等。这类方法的要解决的一个问题就是NP问题,要求得结果是满意解,而非最优解。理解这点,我觉得很重要。
本文中的GA实现的例子来自于http://www.theprojectspot.com/tutorial-post/creating-a-genetic-algorithm-for-beginners/3 一文。有兴趣的读者,也可以参考原文的实现。
遗传算法工作的时候,可以分为以下几个步骤:
1.初始化:首先需要初始化一个种群,大小可以根据需要随意,几个个体或者几千个个体都可以。种群的中个体的产生是随机的。
2.评估:每一个种群成员需要计算他们的适应度,就和自然界里的生物对自然环境的适应度一样。这里的适应度计算是一个关键,一个基本原则是,把对解决当前问题有意义的个体的适应度应该设置得比较高,否则应该给一个低的适应度。适应度计算函数很影响遗传算法性能。因为每一次进化,每一次迭代,每一个个体都要不停得被评估,如果这个方法很慢,搜索性能就会比较差。
3.选择:选择适应度比较高的个体进入下一个进化阶段。适应度低的可以抛弃。
4.交叉:将选中的个体进行基因交叉,产生下一代种群。这个过程就和自然界中生物体有性生殖一样,做DNA的交叉。
5.变异:和自然界一样,DNA是会变异的,变异操作可以帮助我们跳出局部最优。
6.重复:不停重复以上评估、选择、交叉、变异,直到找到一个满意的个体作为算法的最终解。
下面来看一个实现,首先看一下个体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package simpleGa;

public class Individual {

    static int defaultGeneLength = 64;
    private byte[] genes = new byte[defaultGeneLength];
    private int fitness = 0;

    // 随机的个体
    public void generateIndividual() {
        for (int i = 0; i < size(); i++) {
            byte gene = (byte) Math.round(Math.random());
            genes[i] = gene;
        }
    }

    // Use this if you want to create individuals with different gene lengths
    public static void setDefaultGeneLength(int length) {
        defaultGeneLength = length;
    }
    
    public byte getGene(int index) {
        return genes[index];
    }

    public void setGene(int index, byte value) {
        genes[index] = value;
        fitness = 0;
    }

    public int size() {
        return genes.length;
    }

    public int getFitness() {
        if (fitness == 0) {
            fitness = FitnessCalc.getFitness(this);
        }
        return fitness;
    }

    @Override
    public String toString() {
        String geneString = "";
        for (int i = 0; i < size(); i++) {
            geneString += getGene(i);
        }
        return geneString;
    }
}

每一个个体需要计算它的适应度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package simpleGa;

public class FitnessCalc {

    static byte[] solution = new byte[64];

    // 设置一个候选解
    public static void setSolution(byte[] newSolution) {
        solution = newSolution;
    }

    // 设置一个候选解 就是参数类型不一样,这里做个转换
    static void setSolution(String newSolution) {
        solution = new byte[newSolution.length()];
        // Loop through each character of our string and save it in our byte 
        // array
        for (int i = 0; i < newSolution.length(); i++) {
            String character = newSolution.substring(i, i + 1);
            if (character.contains("0") || character.contains("1")) {
                solution[i] = Byte.parseByte(character);
            } else {
                solution[i] = 0;
            }
        }
    }

    // 计算某一个个体的适应度
    static int getFitness(Individual individual) {
        int fitness = 0;
        // 个体和候选解比较,约接近候选集,适应度越高
        for (int i = 0; i < individual.size() && i < solution.length; i++) {
            if (individual.getGene(i) == solution[i]) {
                fitness++;
            }
        }
        return fitness;
    }
    
    // 适应度的最大值
    static int getMaxFitness() {
        int maxFitness = solution.length;
        return maxFitness;
    }
}

基于个体而产生的种群:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package simpleGa;

public class Population {

    Individual[] individuals;
    // 建立一个总群
    public Population(int populationSize, boolean initialise) {
        individuals = new Individual[populationSize];
        // 初始化种群
        if (initialise) {
            // 建立每一个个体
            for (int i = 0; i < size(); i++) {
                Individual newIndividual = new Individual();
                newIndividual.generateIndividual();
                saveIndividual(i, newIndividual);
            }
        }
    }

    public Individual getIndividual(int index) {
        return individuals[index];
    }

    public Individual getFittest() {
        Individual fittest = individuals[0];
        // 取得适应度最高的个体作为种群的适应度
        for (int i = 0; i < size(); i++) {
            if (fittest.getFitness() <= getIndividual(i).getFitness()) {
                fittest = getIndividual(i);
            }
        }
        return fittest;
    }

    // Get population size
    public int size() {
        return individuals.length;
    }

    // Save individual
    public void saveIndividual(int index, Individual indiv) {
        individuals[index] = indiv;
    }
}

基于以上的个体和种群,就可以进行遗传算法的主要工作,交叉,变异等等。来看一下核心的算法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package simpleGa;

public class Algorithm {

    private static final double uniformRate = 0.5;
    private static final double mutationRate = 0.015;
    private static final int tournamentSize = 5;
    private static final boolean elitism = true;
    
    // 进化一个种群
    public static Population evolvePopulation(Population pop) {
        Population newPopulation = new Population(pop.size()false);

        // 保留最优秀的个体
        if (elitism) {
            newPopulation.saveIndividual(0, pop.getFittest());
        }
        // 交叉种群
        int elitismOffset;
        if (elitism) {
            elitismOffset = 1;
        } else {
            elitismOffset = 0;
        }
        // 交叉产生新的个体
        for (int i = elitismOffset; i < pop.size(); i++) {
        //确保不要把最差的个体选进来
            Individual indiv1 = tournamentSelection(pop);
            Individual indiv2 = tournamentSelection(pop);
            Individual newIndiv = crossover(indiv1, indiv2);
            newPopulation.saveIndividual(i, newIndiv);
        }

        // 变异
        for (int i = elitismOffset; i < newPopulation.size(); i++) {
            mutate(newPopulation.getIndividual(i));
        }

        return newPopulation;
    }

    // 交叉
    private static Individual crossover(Individual indiv1, Individual indiv2) {
        Individual newSol = new Individual();
        // Loop through genes
        for (int i = 0; i < indiv1.size(); i++) {
            // 以一定概率交叉
            if (Math.random() <= uniformRate) {
                newSol.setGene(i, indiv1.getGene(i));
            } else {
                newSol.setGene(i, indiv2.getGene(i));
            }
        }
        return newSol;
    }

    // 变异
    private static void mutate(Individual indiv) {
        // Loop through genes
        for (int i = 0; i < indiv.size(); i++) {
            if (Math.random() <= mutationRate) {
                // 以一定概率变异
                byte gene = (byte) Math.round(Math.random());
                indiv.setGene(i, gene);
            }
        }
    }

    // 选择用于交叉的个体,确保最差的个体不会进来
    private static Individual tournamentSelection(Population pop) {
        Population tournament = new Population(tournamentSize, false);
        for (int i = 0; i < tournamentSize; i++) {
            int randomId = (int) (Math.random() * pop.size());
            tournament.saveIndividual(i, pop.getIndividual(randomId));
        }
        Individual fittest = tournament.getFittest();
        return fittest;
    }
}

以上就是全部的实现,最后,测试这些代码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值