1 /* Crowding distance computation routines */ 2 3 # include <stdio.h> 4 # include <stdlib.h> 5 # include <math.h> 6 7 # include "global.h" 8 # include "rand.h" 9 10 /* Routine to compute crowding distance based on ojbective function values when the population in in the form of a list */ 11 void assign_crowding_distance_list (population *pop, list *lst, int front_size) 12 { 13 int **obj_array; 14 int *dist; 15 int i, j; 16 list *temp; 17 temp = lst; 18 if (front_size==1) 19 { 20 pop->ind[lst->index].crowd_dist = INF; 21 return; 22 } 23 if (front_size==2) 24 { 25 pop->ind[lst->index].crowd_dist = INF; 26 pop->ind[lst->child->index].crowd_dist = INF; 27 return; 28 } 29 obj_array = (int **)malloc(nobj*sizeof(int)); 30 dist = (int *)malloc(front_size*sizeof(int)); 31 for (i=0; i<nobj; i++) 32 { 33 obj_array[i] = (int *)malloc(front_size*sizeof(int)); 34 } 35 for (j=0; j<front_size; j++) 36 { 37 dist[j] = temp->index; 38 temp = temp->child; 39 } 40 assign_crowding_distance (pop, dist, obj_array, front_size); 41 free (dist); 42 for (i=0; i<nobj; i++) 43 { 44 free (obj_array[i]); 45 } 46 free (obj_array); 47 return; 48 } 49 50 /* Routine to compute crowding distance based on objective function values when the population in in the form of an array */ 51 void assign_crowding_distance_indices (population *pop, int c1, int c2) 52 { 53 int **obj_array; 54 int *dist; 55 int i, j; 56 int front_size; 57 front_size = c2-c1+1; 58 if (front_size==1) 59 { 60 pop->ind[c1].crowd_dist = INF; 61 return; 62 } 63 if (front_size==2) 64 { 65 pop->ind[c1].crowd_dist = INF; 66 pop->ind[c2].crowd_dist = INF; 67 return; 68 } 69 obj_array = (int **)malloc(nobj*sizeof(int)); 70 dist = (int *)malloc(front_size*sizeof(int)); 71 for (i=0; i<nobj; i++) 72 { 73 obj_array[i] = (int *)malloc(front_size*sizeof(int)); 74 } 75 for (j=0; j<front_size; j++) 76 { 77 dist[j] = c1++; 78 } 79 assign_crowding_distance (pop, dist, obj_array, front_size); 80 free (dist); 81 for (i=0; i<nobj; i++) 82 { 83 free (obj_array[i]); 84 } 85 free (obj_array); 86 return; 87 }
以上代碼里的兩個函數都為包裝函數,最終的計算都是需要調用下面的函數
assign_crowding_distance (population *pop, int *dist, int **obj_array, int front_size) 。
其中,加入一定的判斷過程,對一個層里面只有兩個個體的情況直接對這兩個個體的擁擠距離設定為無窮。
距離計算的核心代碼,如下:
1 /* Routine to compute crowding distances */ 2 void assign_crowding_distance (population *pop, int *dist, int **obj_array, int front_size) 3 { 4 int i, j; 5 for (i=0; i<nobj; i++) 6 { 7 for (j=0; j<front_size; j++) 8 { 9 obj_array[i][j] = dist[j]; 10 } 11 quicksort_front_obj (pop, i, obj_array[i], front_size); 12 } 13 for (j=0; j<front_size; j++) 14 { 15 pop->ind[dist[j]].crowd_dist = 0.0; 16 } 17 18 for (i=0; i<nobj; i++) 19 { 20 pop->ind[obj_array[i][0]].crowd_dist = INF; 21 } 22 23 for (i=0; i<nobj; i++) 24 { 25 for (j=1; j<front_size-1; j++) 26 { 27 if (pop->ind[obj_array[i][j]].crowd_dist != INF) 28 { 29 if (pop->ind[obj_array[i][front_size-1]].obj[i] == pop->ind[obj_array[i][0]].obj[i]) 30 { 31 pop->ind[obj_array[i][j]].crowd_dist += 0.0; 32 } 33 else 34 { 35 pop->ind[obj_array[i][j]].crowd_dist += (pop->ind[obj_array[i][j+1]].obj[i] - pop->ind[obj_array[i][j-1]].obj[i])/(pop->ind[obj_array[i][front_size-1]].obj[i] - pop->ind[obj_array[i][0]].obj[i]); 36 } 37 } 38 } 39 } 40 41 for (j=0; j<front_size; j++) 42 { 43 if (pop->ind[dist[j]].crowd_dist != INF) 44 { 45 pop->ind[dist[j]].crowd_dist = (pop->ind[dist[j]].crowd_dist)/nobj; 46 } 47 } 48 return; 49 }
5 行 到 12行, 初始化 多目標索引矩陣,並對其不同目標列進行索引排序(按照目標函數值的大小)。
13行 到 16行, 個體的擁擠距離初始化。
18行 到 21行, 對按照某目標函數排序后最小的個體的擁擠距離賦值為無窮(並沒有對兩端賦值無窮,而是最小端的個體)。
27行,如果一個個體的擁擠距離已經被賦值為無窮,則對其不再計算。
29行 到 32行,如果某目標函數的排序后所有個體的該目標函數值相同,則該目標函數貢獻的距離為 0 。
pop->ind[obj_array[i][j]].crowd_dist += (pop->ind[obj_array[i][j+1]].obj[i] - pop->ind[obj_array[i][j-1]].obj[i])/(pop->ind[obj_array[i][front_size-1]].obj[i] - pop->ind[obj_array[i][0]].obj[i]);
35行代碼, 某個個體在某一個目標函數上的擁擠距離 為 該個體在該目標函數上前后個體距離之差除以該層該目標的最大最小值之差。
41 行 到 47行, 將擁擠距離不為無窮的所有個體的擁擠距離除以目標函數值個數(歸一化操作) 。