首页 > 代码库 > 多目标遗传算法 ------ NSGA-II (部分源码解析)二元锦标赛选择 tourselect.c

多目标遗传算法 ------ NSGA-II (部分源码解析)二元锦标赛选择 tourselect.c

 

tourselect.c  文件中共有两个函数:

selection (population *old_pop, population *new_pop)

individual* tournament (individual *ind1, individual *ind2)

 

首先,第一个函数代码如下:

 1 /* Routine for tournament selection, it creates a new_pop from old_pop by performing tournament selection and the crossover */
 2 void selection (population *old_pop, population *new_pop)
 3 {
 4     int *a1, *a2;
 5     int temp;
 6     int i;
 7     int rand;
 8     individual *parent1, *parent2;
 9     a1 = (int *)malloc(popsize*sizeof(int));
10     a2 = (int *)malloc(popsize*sizeof(int));
11     for (i=0; i<popsize; i++)
12     {
13         a1[i] = a2[i] = i;
14     }
15     for (i=0; i<popsize; i++)
16     {
17         rand = rnd (i, popsize-1);
18         temp = a1[rand];
19         a1[rand] = a1[i];
20         a1[i] = temp;
21         rand = rnd (i, popsize-1);
22         temp = a2[rand];
23         a2[rand] = a2[i];
24         a2[i] = temp;
25     }
26     for (i=0; i<popsize; i+=4)
27     {
28         parent1 = tournament (&old_pop->ind[a1[i]], &old_pop->ind[a1[i+1]]);
29         parent2 = tournament (&old_pop->ind[a1[i+2]], &old_pop->ind[a1[i+3]]);
30         crossover (parent1, parent2, &new_pop->ind[i], &new_pop->ind[i+1]);
31         parent1 = tournament (&old_pop->ind[a2[i]], &old_pop->ind[a2[i+1]]);
32         parent2 = tournament (&old_pop->ind[a2[i+2]], &old_pop->ind[a2[i+3]]);
33         crossover (parent1, parent2, &new_pop->ind[i+2], &new_pop->ind[i+3]);
34     }
35     free (a1);
36     free (a2);
37     return;
38 }

 

其中,

    a1 = (int *)malloc(popsize*sizeof(int));
    a2 = (int *)malloc(popsize*sizeof(int));

分别生成两个  种群个体大小的数组 a1  a2,这两个数组里面以后会分别保存乱序的种群个体序号。

 

 

    for (i=0; i<popsize; i++)
    {
        a1[i] = a2[i] = i;
    }

对两个数组进行初始话,顺序存放种群个体序号。

 

 

 

    for (i=0; i<popsize; i++)
    {
        rand = rnd (i, popsize-1);
        temp = a1[rand];
        a1[rand] = a1[i];
        a1[i] = temp;
        rand = rnd (i, popsize-1);
        temp = a2[rand];
        a2[rand] = a2[i];
        a2[i] = temp;
    }

对a1, a2  数组中存放的个体序号打乱,其中打乱的次数为  popsize  ,该操作基本保证所有个体的序号基本不在其原有位置上。

(在高级面向对象语言中以上代码可以用一句库函数调用代替)

 

 

    for (i=0; i<popsize; i+=4)
    {
        parent1 = tournament (&old_pop->ind[a1[i]], &old_pop->ind[a1[i+1]]);
        parent2 = tournament (&old_pop->ind[a1[i+2]], &old_pop->ind[a1[i+3]]);
        crossover (parent1, parent2, &new_pop->ind[i], &new_pop->ind[i+1]);
        parent1 = tournament (&old_pop->ind[a2[i]], &old_pop->ind[a2[i+1]]);
        parent2 = tournament (&old_pop->ind[a2[i+2]], &old_pop->ind[a2[i+3]]);
        crossover (parent1, parent2, &new_pop->ind[i+2], &new_pop->ind[i+3]);
    }

这部分代码完成了遗传算法中的  选择操作  和  交叉操作

其中  old_pop  new_pop  都是相同种群个体大小的种群,其种群大小均为  popsize。

tournament   锦标赛法,这里面使用的是二元锦标赛选择法,循环体内共有4次  tournament  操作,该循环共执行  popsize/4  次,故共进行了  popsize  次二元锦标赛选择。由于每次选择出一个新个体,所以该方式选择出的新种群 new_pop  个体数   和   旧种群 old_pop  个体数一致。

 

同理,crossover  操作进行了  popsize/2  次 , (其中每次进行交叉操作的时候都是选择两个个体,每次判断选择的两个个体是否进行交叉都要根据给定的交叉概率进行判断),该循环体中crossover函数总共会对   popsize   个个体进行处理。

注意: crossover  操作  循环调用    popsize/2  次  而不是    popsize  次。

 

 

 

 1 /* Routine for binary tournament */
 2 individual* tournament (individual *ind1, individual *ind2)
 3 {
 4     int flag;
 5     flag = check_dominance (ind1, ind2);
 6     if (flag==1)
 7     {
 8         return (ind1);
 9     }
10     if (flag==-1)
11     {
12         return (ind2);
13     }
14     if (ind1->crowd_dist > ind2->crowd_dist)
15     {
16         return(ind1);
17     }
18     if (ind2->crowd_dist > ind1->crowd_dist)
19     {
20         return(ind2);
21     }
22     if ((randomperc()) <= 0.5)
23     {
24         return(ind1);
25     }
26     else
27     {
28         return(ind2);
29     }
30 }

 

二元锦标赛竞赛法比较简单,  其中调用  check_dominance  函数判断两个个体的支配关系,如果互不支配则判断两个个体的拥挤距离,如果都相同这则随机选择一个个体。

 

多目标遗传算法 ------ NSGA-II (部分源码解析)二元锦标赛选择 tourselect.c