人工智能实验2——用遗传算法求解TSP问题

本来这个实验早就想写上来的了,但是当时这门课成绩还没出,怕引起不必要的麻烦就搁置了一段时间。

问题描述:
这个问题可分为对称旅行商问题(dij=dji,,i,j=1,2,3,…,n)和非对称旅行商问题(dij≠dji,,i,j=1,2,3,…,n)。   
若对于城市v={v1,v2,v3,…,vn}的一个访问顺序为t=(t1,t2,t3,…,ti,…,tn),其中ti∈v(i=1,2,3,…,n),且记tn+1= t1,
则旅行商问题的数学模型为:      min    { l=∑d(t(i),t(i+1))  (i=1,…,n)}    
旅行商问题是一个典型的组合优化问题,并且是一个np难问题,其可能的路径数目与城市数目n是成指数型增长的,
所以一般很难精确地求出其最优解,这里采用遗传算法求其近似解。

实验步骤:
(1)初始化过程:用v1,v2,v3,…,vn代表所选n个城市。定义整数pop-size作为染色体的个数,并且随机产生pop-size个初始染色体,每个染色体为1到18的整数组成的随机序列。
(2)适应度f的计算:对种群中的每个染色体vi,计算其适应度,f=∑d(t(i),t(i+1))。
(3)评价函数eval(vi):用来对种群中的每个染色体vi设定一个概率,以使该染色体被选中的可能性与其种群中其它染色体的适应性成比例,既通过轮盘赌,适应性强的染色体被选择产生后台的机会要大,设alpha∈(0,1),本文定义基于序的评价函数为eval(vi)=alpha*(1-alpha)^(i-1) 。
(4)选择过程:选择过程是以旋转赌轮pop-size次为基础,每次旋转都为新的种群选择一个染色体。赌轮是按每个染色体的适应度进行选择染色体的。   
step1.对每个染色体vi,计算累计概率qi, q0=0;qi=∑eval(vj)   j=1,…,i;i=1,…,pop-size.   
step2.从区间[0,1]中产生一个随机数r;   
step3.若qi-1<r<qi,则选择第i个染色体
step4.重复step2和step3共pop-size次,这样可以得到pop-size个复制的染色体。
(5)交叉过程:本文采用常规单点交叉。为确定交叉操作的父代,从1 到pop-size重复以下过程:从[0,1]中产生一个随机数r,如果r 将所选的父代两两组队,随机产生一个位置进行交叉,如:          
8 14 2 13 8 6 3 2 5 7 3 4 3 2 4 2 2 1          
6 12 3 5   6 8 5 6 3 1 8 5 6 3 3 2 1 1
交叉后为:        
8 14 2 13 8 6 3 2 5 1 8 5 6 3 3 2 1 1        
6 12 3 5   6 8 5 6 3 7 3 4 3 2 4 2 2 1
(6)变异过程:本文采用均匀多点变异。类似交叉操作中选择父代的过程,在r选择多个染色体vi作为父代。对每一个选择的父代,随机选择多个位置,使其在每位置按均匀变异(该变异点xk的取值范围为[ukmin,ukmax],产生一个[0,1]中随机数r,该点变异为x'k=ukmin+r(ukmax-ukmin))操作。如:        
8 14 2 13 8 6 3 2 5 7 3 4 3 2 4 2 2 1      
变异后:        
8 14 2 13 10 6 3 2 2 7 3 4 5 2 4 1 2 1
(7)循环操作: 判断是否满足设定的代数xzome, 否,则跳入适应度f的计算; 是,结束遗传操作,跳出。

有关代码部分有几点要在这里说明一下说明:
1.评价函数我没有用PPT里的eval(vi)=alpha*(1-alpha)^(i-1) 而是用了eval(vi)=(1/fi)/f总
2.选择过程是用的赌轮
3.交叉过程的配对是直接的1和2,3和4,5和6...用的是单点交叉
4.变异过程这里不确定有没有问题,我是把每个染色体都按变异率决定有几个位置要进行变异操作,采用均匀变异
5.最后在迭代完后会输出那一代最小适应度的路径,即最优路径
6.因为我们整个过程中涉及生成,选择,交叉,变异,所以我们真正用的是原来的城市访问序列的编码,而不是序列本身,在最后用changeCodeToPath()函数还原访问序列。如下是编码方法的描述:


package MyWork.net;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;

public class test {

    static double fitnessReciprocalSum;

    class Chromosome {
        int[] code;
        int[] path;
        int fitness;
        double eval;
        double q;
    }
    
    public int[] initialChromosome(int pathLength) {
        int[] pathCode = new int[pathLength];
        Random r = new Random();
        for (int i = 0; i < pathLength; i++)
            if (i == 0)
                pathCode[i] = 1;// set the first place to 1 to avoid the
                                // redundant paths
            else
                pathCode[i] = r.nextInt(pathLength - i) + 1;
        return pathCode;
    }

    public int[] changeCodeToPath(int[] code) {

        int[] mark = new int[code.length];
        int[] path = new int[code.length];

        for (int i = 0; i < code.length; i++) {
            int k = 0;
            for (int j = 0; j < code.length; j++) {
                if (mark[j] == 1)
                    k++;
                else {
                    if (code[i] + k == j + 1) {
                        path[i] = j + 1;
                        mark[j] = 1;
                        break;
                    }
                }
            }
        }
        return path;
    }

    public int[] changePathToCode(int[] path) {

        int[] mark = new int[path.length];
        int[] code = new int[path.length];

        for (int i = 0; i < path.length; i++) {
            int k = 0;
            for (int j = 1; j < path.length; j++) {
                if (mark[j] == 0) {
                    if (path[i] == j) {
                        code[i] = j - k;
                        mark[j] = 1;
                        break;
                    }
                } else
                    k++;
            }
        }
        return code;
    }

    public int countFitness(int[] path, int[][] DistanceMaze) {

        int length = 0;
        for (int i = 0; i < path.length - 1; i++)
            length = DistanceMaze[path[i] - 1][path[i + 1] - 1] + length;
        // add the whole distance circle
        length += DistanceMaze[path[path.length - 1] - 1][path[0] - 1];
        // count the max fitness
        fitnessReciprocalSum += (double)1/length;
        return length;// fitness

    }

    public double countEvaluation(int fitness) {

        return (double)1/fitness/fitnessReciprocalSum;

    }
    
    public void onePointCrossover(int[] code1,int[] code2){
        
        Random r = new Random();
        int k = r.nextInt(code1.length-1)+1;
        int temp;
        for(; k < code1.length; k++){
            temp = code1[k];
            code1[k] = code2[k];
            code2[k] = temp;
        }
    }
    
    public void averageMutation(int[] code, double pm){
        
        int mutationTotal = (int)( pm * code.length);
        Random r = new Random();
        int k;
        for(int i=0; i<mutationTotal; i++){
            k = r.nextInt(code.length-1) + 1;
            code[k] = 1 + (int)Math.random()*(code.length - k -1);
        }
    }

    public void driver(int[][] D, double pMutation, int xzone) {
        int PopSize = 5;// chromosomeTotal
        int n = 5;// cityTotal
        int[][] DistanceMaze = D;
        Chromosome[] chromosomes = new Chromosome[PopSize];

        // initial ChromosomesCode
        for (int i = 0; i < PopSize; i++) {
            chromosomes[i] = new Chromosome();
            chromosomes[i].code = initialChromosome(n);
        }
        System.out.println("code:");
        for (int i = 0; i < PopSize; i++) {
            System.out.print("code"+i+":");
            for (int j = 0; j < n; j++)
                System.out.print(chromosomes[i].code[j] + " ");
            System.out.println();
        }

        for(int xz = 0; xz< xzone; xz++ ){
            System.out.println("the"+xz+"xzone");
            // change Code to Path
            for (int i = 0; i < PopSize; i++) {
                chromosomes[i].path = changeCodeToPath(chromosomes[i].code);
            }
            System.out.println("path:");
            for (int i = 0; i < PopSize; i++) {
                System.out.print("path"+i+":");
                for (int j = 0; j < n; j++)
                    System.out.print(chromosomes[i].path[j] + " ");
                System.out.println();
            }

            // count the fitness
            System.out.print("fitness:");
            for (int i = 0; i < PopSize; i++) {
                chromosomes[i].fitness = countFitness(chromosomes[i].path,
                        DistanceMaze);
                System.out.print(chromosomes[i].fitness + " ");
            }
            System.out.println();

            // count the evaluation
            System.out.print("eval:");
            for (int i = 0; i < PopSize; i++) {
                chromosomes[i].eval = countEvaluation(chromosomes[i].fitness);
                System.out.print(chromosomes[i].eval + " ");
            }
            System.out.println();
            
            // calculate the cumulative probability q
            for (int i = 0; i < PopSize; i++){
                if(i == 0)
                    chromosomes[i].q = chromosomes[i].eval;
                else 
                    chromosomes[i].q = chromosomes[i-1].q + chromosomes[i].eval;
            }
            System.out.print("q:");
            for (int i = 0; i < PopSize; i++) {
                System.out.print(chromosomes[i].q + " ");
            }
            System.out.println();
            
            //do the choosing progress
            int[] chosenChromosome = new int[PopSize];
            System.out.print("r:");
            for (int i = 0; i<PopSize; i++){
                double r = Math.random();
                System.out.print(r+" ");
                for (int j=0; j<PopSize; j++){        
                    if(j == 0){
                        if(0 < r && r < chromosomes[0].q){
                            chosenChromosome[i] = 0;
                            break;
                        }
                    }
                    else if(chromosomes[j-1].q<r && chromosomes[j].q>r){
                        chosenChromosome[i] = j;
                        break;
                    }
                }
            }
            System.out.println();
            System.out.print("chosen:");
            for (int i = 0; i < PopSize; i++) {
                System.out.print(chosenChromosome[i] + " ");
            }
            System.out.println();
            //copy the sons to fathers
            Chromosome[] tempChromo = new Chromosome[PopSize];
            for(int i=0; i < PopSize; i++)
                tempChromo[i] = chromosomes[i];
            for(int i=0; i < PopSize; i++){
                chromosomes[i] = new Chromosome();
                chromosomes[i].code = new int[n];
                for(int j=0; j<n; j++)
                    chromosomes[i].code[j] = tempChromo[chosenChromosome[i]].code[j];
            }
            for (int i = 0; i < PopSize; i++) {
                System.out.print("code"+i+":");
                for (int j = 0; j < n; j++)
                    System.out.print(chromosomes[i].code[j] + " ");
                System.out.println();
            }
            
            //do the crossover progress
            for( int i = 0; i+1 < PopSize; i += 2){
                onePointCrossover(chromosomes[i].code, chromosomes[i+1].code);
            }
            System.out.println("After crossover:");
            for (int i = 0; i < PopSize; i++) {
                System.out.print("code"+i+":");
                for (int j = 0; j < n; j++)
                    System.out.print(chromosomes[i].code[j] + " ");
                System.out.println();
            } 
            
            //do the mutation progress
            for( int i = 0; i < PopSize; i++){
                averageMutation(chromosomes[i].code, pMutation);
            }
            System.out.println("After mutation:");
            for (int i = 0; i < PopSize; i++) {
                System.out.print("code"+i+":");
                for (int j = 0; j < n; j++)
                    System.out.print(chromosomes[i].code[j] + " ");
                System.out.println();
            } 
        }
        
        //The last generation
        //change code to path
        for (int i = 0; i < PopSize; i++) {
            chromosomes[i].path = changeCodeToPath(chromosomes[i].code);
        }
        System.out.println("path:");
        for (int i = 0; i < PopSize; i++) {
            System.out.print("path"+i+":");
            for (int j = 0; j < n; j++)
                System.out.print(chromosomes[i].path[j] + " ");
            System.out.println();
        }
        // count the fitness
        System.out.print("fitness:");
        for (int i = 0; i < PopSize; i++) {
            chromosomes[i].fitness = countFitness(chromosomes[i].path,
                    DistanceMaze);
            System.out.print(chromosomes[i].fitness + " ");
        }
        System.out.println();
        //pick up the most optimal path
        int opNum = 0;
        int opFit = chromosomes[0].fitness;
        for(int i=0; i< PopSize; i++)
            if(opFit > chromosomes[i].fitness){
                opFit = chromosomes[i].fitness;
                opNum = i;
            }
        System.out.println("The Optimal Path:"+Arrays.toString(chromosomes[opNum].path));
            
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        test t = new test();
        int[][] DistanceMaze = { { 0, 4, 10, 5, 8 },
                { 4, 0, 13, 3, 9 }, { 10, 13, 0, 6, 2 },
                { 5, 3, 6, 0, 30 }, { 8, 9, 2, 30, 0 } };
        double pMutation = 0.001;
        int xzone = 5;
        t.driver(DistanceMaze, pMutation, xzone);

    }

}

因为写得仓促,可能有不正确的地方,欢迎指正。

posted @ 2013-03-02 12:54  sillypudding  阅读(1175)  评论(0编辑  收藏  举报