多目標遺傳算法 ------ NSGA-II (部分源碼解析) 非支配排序、分層 rank.c


  1 /* Rank assignment routine */
  2 
  3 # include <stdio.h>
  4 # include <stdlib.h>
  5 # include <math.h>
  6 
  7 # include "global.h"
  8 # include "rand.h"
  9 
 10 /* Function to assign rank and crowding distance to a population of size pop_size*/
 11 void assign_rank_and_crowding_distance (population *new_pop)
 12 {
 13     int flag;
 14     int i;
 15     int end;
 16     int front_size;
 17     int rank=1;
 18     list *orig;
 19     list *cur;
 20     list *temp1, *temp2;
 21     orig = (list *)malloc(sizeof(list));
 22     cur = (list *)malloc(sizeof(list));
 23     front_size = 0;
 24     orig->index = -1;
 25     orig->parent = NULL;
 26     orig->child = NULL;
 27     cur->index = -1;
 28     cur->parent = NULL;
 29     cur->child = NULL;
 30     temp1 = orig;
 31 
 32     /* 對orig 鏈表中的個體進行初始化,元素賦值相對的個體序號 */
 33     for (i=0; i<popsize; i++)
 34     {
 35         insert (temp1,i);
 36         temp1 = temp1->child;
 37     }
 38 
 39 
 40     /* 支配關系分層的主循環函數 */
 41     do
 42     {
 43         /*
 44               如果orig鏈表中只有一個個體,則直接對其分層賦值,
 45               因為該層只有一個個體對其擁擠度直接賦值為無窮,並break主循環
 46         */
 47         if (orig->child->child == NULL)
 48         {
 49             new_pop->ind[orig->child->index].rank = rank;
 50             new_pop->ind[orig->child->index].crowd_dist = INF;
 51             break;
 52         }
 53 
 54         /*
 55               orig 中的元素為待分層的元素, 此時 cur 鏈表為空。
 56 
 57               取出 orig 鏈表中的頭一個個體插入到 cur 鏈表中,該操作相當於對以下內循環的初始化
 58               此時,cur鏈表中只有一個元素
 59         */
 60         temp1 = orig->child;
 61         insert (cur, temp1->index);
 62         front_size = 1;
 63         temp2 = cur->child;
 64         temp1 = del (temp1);
 65         temp1 = temp1->child;
 66         
 67 
 68         do
 69         {   
 70             /*temp2 指向cur鏈表的第一個節點*/ 
 71             temp2 = cur->child;
 72             do
 73             {   
 74                 /*結束標志位 歸0 */   
 75                 end = 0;
 76                 /*判斷 orig 和 cur 鏈表中 temp1, temp2 指針指向的節點元素所對應的個體支配關系 */  
 77                 flag = check_dominance (&(new_pop->ind[temp1->index]), &(new_pop->ind[temp2->index]));
 78                 
 79                 /*若 a支配b ,在orig中插入a,在cur中刪除b */
 80                 if (flag == 1)
 81                 {
 82                     insert (orig, temp2->index);
 83                     temp2 = del (temp2);
 84                     front_size--;
 85                     temp2 = temp2->child;
 86               
 87                 
 88                 /*個體a b互不支配, cur鏈表指針下移一位*/
 89                 if (flag == 0)
 90                 {
 91                     temp2 = temp2->child;
 92                 }
 93                  
 94                 /*個體b 支配 個體a , 結束該次循環*/
 95                 if (flag == -1)
 96                 {
 97                     end = 1;
 98                 }
 99             }
100             /* 
101                 個體b 被 個體a 支配即 flag==-1,  將該層循環結束位 end置1,結束該層循環。
102                 cur 鏈表中 所有個體均已遍歷,沒有b個體,結束循環。 
103             */
104             while (end!=1 && temp2!=NULL);
105 
106 
107 
108             /* 
109                   個體a 支配 個體b   或者  互不支配 
110                   將個體a 插入到 cur鏈表最前端,同時移除orig鏈表中的a個體
111             */
112             if (flag == 0 || flag == 1)
113             {
114                 insert (cur, temp1->index);
115                 front_size++;
116                 temp1 = del (temp1);
117             }
118 
119             /*orig鏈表中所指向個體的指針后移一位*/
120             temp1 = temp1->child;
121         }
122         /*temp1指針指向NULL意味着orig鏈表中所有元素對應的個體均被 cur鏈表中對應的個體  支配*/
123         while (temp1 != NULL);
124 
125 
126 
127 
128 
129         /*
130               temp2重新指向 cur 列表中第一個元素,cur列表中的元素為當前已分層的元素
131         */
132         temp2 = cur->child;
133         do
134         {
135             new_pop->ind[temp2->index].rank = rank;
136             temp2 = temp2->child;
137         }
138         while (temp2 != NULL);
139         /* 對當前層的個體進行擁擠度判斷 */
140         assign_crowding_distance_list (new_pop, cur->child, front_size);
141 
142 
143         /* 對 cur 鏈表中的個體釋放內存空間 */
144         temp2 = cur->child;
145         do
146         {
147             temp2 = del (temp2);
148             temp2 = temp2->child;
149         }
150         while (cur->child !=NULL);
151         /* 分層的排序值 加1 */
152         rank+=1;
153     }
154     /* 循環判斷,直到orig鏈表中出頭節點外為空,即所有個體全部分層 */
155     while (orig->child!=NULL);
156 
157 
158     /* 將鏈表orig cur的頭結點內存空間釋放掉 */
159     free (orig);
160     free (cur);
161     return;
162 }

 

該非支配分層基本思想是設置兩個雙向鏈表(orig   cur),orig 鏈表里面存放所有待分層排序的個體索引,cur鏈表中的元素為分層結束后該層的個體索引。

每次在orig 中取出的元素對應的個體為 a,  cur 中取出的元素對應的個體為 b 。

 

 

若 b支配於 a  ,則取 orig 中對應的下一個個體作為 a ,

若 a  b  互不支配  ,則依次取 cur 中對應的下一個個體作為 b ,  遍歷cur 中所有個體(cur 中的個體為待分層的個體,其互不支配),若a 與  cur 中所有個體互不支配則將個體a移除orig鏈表並插入到cur鏈表的最前端。

若a  支配於  b,  則將b 個體移除cur 鏈表並插入到 orig 鏈表的最前端,同時取cur 中的下一個個體作為 b 。

 

當遍歷orig 中的所有元素,此時 cur 中個體便是此時的非支配解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM