多目标遗传算法 ------ NSGA-II (部分源码解析) 拥挤距离计算 crowddist.c

时间:2021-02-13 19:39:18
 /* Crowding distance computation routines */

 # include <stdio.h>
# include <stdlib.h>
# include <math.h> # include "global.h"
# include "rand.h" /* Routine to compute crowding distance based on ojbective function values when the population in in the form of a list */
void assign_crowding_distance_list (population *pop, list *lst, int front_size)
{
int **obj_array;
int *dist;
int i, j;
list *temp;
temp = lst;
if (front_size==)
{
pop->ind[lst->index].crowd_dist = INF;
return;
}
if (front_size==)
{
pop->ind[lst->index].crowd_dist = INF;
pop->ind[lst->child->index].crowd_dist = INF;
return;
}
obj_array = (int **)malloc(nobj*sizeof(int));
dist = (int *)malloc(front_size*sizeof(int));
for (i=; i<nobj; i++)
{
obj_array[i] = (int *)malloc(front_size*sizeof(int));
}
for (j=; j<front_size; j++)
{
dist[j] = temp->index;
temp = temp->child;
}
assign_crowding_distance (pop, dist, obj_array, front_size);
free (dist);
for (i=; i<nobj; i++)
{
free (obj_array[i]);
}
free (obj_array);
return;
} /* Routine to compute crowding distance based on objective function values when the population in in the form of an array */
void assign_crowding_distance_indices (population *pop, int c1, int c2)
{
int **obj_array;
int *dist;
int i, j;
int front_size;
front_size = c2-c1+;
if (front_size==)
{
pop->ind[c1].crowd_dist = INF;
return;
}
if (front_size==)
{
pop->ind[c1].crowd_dist = INF;
pop->ind[c2].crowd_dist = INF;
return;
}
obj_array = (int **)malloc(nobj*sizeof(int));
dist = (int *)malloc(front_size*sizeof(int));
for (i=; i<nobj; i++)
{
obj_array[i] = (int *)malloc(front_size*sizeof(int));
}
for (j=; j<front_size; j++)
{
dist[j] = c1++;
}
assign_crowding_distance (pop, dist, obj_array, front_size);
free (dist);
for (i=; i<nobj; i++)
{
free (obj_array[i]);
}
free (obj_array);
return;
}

以上代码里的两个函数都为包装函数,最终的计算都是需要调用下面的函数

assign_crowding_distance (population *pop, int *dist, int **obj_array, int front_size)  。

其中,加入一定的判断过程,对一个层里面只有两个个体的情况直接对这两个个体的拥挤距离设定为无穷。

距离计算的核心代码,如下:

 /* Routine to compute crowding distances */
void assign_crowding_distance (population *pop, int *dist, int **obj_array, int front_size)
{
int i, j;
for (i=; i<nobj; i++)
{
for (j=; j<front_size; j++)
{
obj_array[i][j] = dist[j];
}
quicksort_front_obj (pop, i, obj_array[i], front_size);
}
for (j=; j<front_size; j++)
{
pop->ind[dist[j]].crowd_dist = 0.0;
} for (i=; i<nobj; i++)
{
pop->ind[obj_array[i][]].crowd_dist = INF;
} for (i=; i<nobj; i++)
{
for (j=; j<front_size-; j++)
{
if (pop->ind[obj_array[i][j]].crowd_dist != INF)
{
if (pop->ind[obj_array[i][front_size-]].obj[i] == pop->ind[obj_array[i][]].obj[i])
{
pop->ind[obj_array[i][j]].crowd_dist += 0.0;
}
else
{
pop->ind[obj_array[i][j]].crowd_dist += (pop->ind[obj_array[i][j+]].obj[i] - pop->ind[obj_array[i][j-]].obj[i])/(pop->ind[obj_array[i][front_size-]].obj[i] - pop->ind[obj_array[i][]].obj[i]);
}
}
}
} for (j=; j<front_size; j++)
{
if (pop->ind[dist[j]].crowd_dist != INF)
{
pop->ind[dist[j]].crowd_dist = (pop->ind[dist[j]].crowd_dist)/nobj;
}
}
return;
}

5 行 到  12行,  初始化  多目标索引矩阵,并对其不同目标列进行索引排序(按照目标函数值的大小)。

13行 到 16行, 个体的拥挤距离初始化。

18行 到 21行, 对按照某目标函数排序后最小的个体的拥挤距离赋值为无穷(并没有对两端赋值无穷,而是最小端的个体)。

27行,如果一个个体的拥挤距离已经被赋值为无穷,则对其不再计算。

29行 到  32行,如果某目标函数的排序后所有个体的该目标函数值相同,则该目标函数贡献的距离为 0  。

pop->ind[obj_array[i][j]].crowd_dist += (pop->ind[obj_array[i][j+]].obj[i] - pop->ind[obj_array[i][j-]].obj[i])/(pop->ind[obj_array[i][front_size-]].obj[i] - pop->ind[obj_array[i][]].obj[i]);

35行代码,  某个个体在某一个目标函数上的拥挤距离  为 该个体在该目标函数上前后个体距离之差除以该层该目标的最大最小值之差。

41 行  到   47行,  将拥挤距离不为无穷的所有个体的拥挤距离除以目标函数值个数(归一化操作)  。