這其實是上個禮拜就完成的了,但由於上個禮拜沒有開會
這周三才開的會,然后確認了算法的正確性了,今天有時間就來記錄下
這個也是基於IEEE的論文寫的
花的時間比較多,而且,也是我寫過的最大的一個算法了
先用我自己的語言來描述下整體的算法吧:
一開始當然是初始化種群P了(在這里可以同時初始化一個種群Q)
先把P和Q歸並到R
然后構造邊界集F,也就是快速非支配的排序(這是個重點以及難點)
構造完了新的邊界集之后就要產生新的種群P了
這一步過程中,要對每一層進行擁擠距離的計算(為了保持特種的多樣性)
擁擠距離的計算也是個難點+重點
對於需要計算的最后一層,還要進行一層偏序關系的排序來進行選取
P構造好了,就要通過P生成Q了
這里,首先要采用二元錦標賽選擇產生NP/2個個體(NP是種群大小)
然后通過雜交變異生成新的個體(隨機數小於0.9進行SBX,即雜交,否則變異)
雜交是兩個個體產生兩個個體的,變異是一個個體產生一個個體
當Q的數量達到了NP之后,第一輪迭代結束
整個算法流程大概是這樣吧,最后我跑出的結果還行
收斂和分布都還可以,還要等用matlab繪圖之后看最后的結果了
下面就直接貼代碼了
這次為了自己能記清(太大了,思路總不清晰),我大部分地方都加了注釋了
#include<cstdio> #include<cstring> #include<cmath> #include<cmath> #include<ctime> #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; const int NP=200; const int INF=~0U>>2; const double upper=1.0; const double lower=0.0; const int D=30; const int G=2000; const int problem=2; const double cc=20.0; const double mm=20.0; struct individual{ double xreal[D+10]; double fitness[problem+2]; int num_bedominated; int set_dominated[2*NP+10]; int num_dominated; int rank; double distance; friend bool operator < (const individual&a,const individual&b){ return a.distance>b.distance; } }; individual P[NP+10]; individual Q[NP+10]; individual R[2*NP+10]; struct Front{ individual ind[2*NP+10]; int num; }F[2*NP+10]; void output_pop(individual P[]){ for(int i=0;i<NP;i++){ if(P[i].xreal[0]>1.0){ cout<<i<<" "; for(int j=0;j<5;j++) cout<<P[i].xreal[j]<<" "; cout<<endl; } } } void init_xreal(individual &P){ for(int i=0;i<D;i++) P.xreal[i]=rand()/(RAND_MAX+0.0); } void calc_fitness_ZDT1(individual &P){ P.fitness[0]=P.xreal[0]; double tmp=0.0; for(int i=1;i<D;i++) tmp+=P.xreal[i]; double g_x=1.0+9*tmp/(D-1); P.fitness[1]=g_x*(1.0-sqrt(P.xreal[0]/g_x)); /*if(P.fitness>1.0){ ; }*/ //printf("--%f %f\n",P.fitness[0],P.fitness[1]); } void init_population(individual pop[],int N){ for(int i=0;i<N;i++){ pop[i].distance=0.0; init_xreal(pop[i]); calc_fitness_ZDT1(pop[i]); } } void mergePQ(individual R[],individual P[],individual Q[]){ for(int i=0;i<NP;i++) R[i]=P[i]; for(int i=NP;i<2*NP;i++) R[i]=Q[i-NP]; } bool is_dominated(individual pop[],int p,int q){ if(pop[p].fitness[0]<=pop[q].fitness[0]&& pop[p].fitness[1]<=pop[q].fitness[1]){ if(pop[p].fitness[0]<pop[q].fitness[0]|| pop[p].fitness[1]<pop[q].fitness[1]) return true; } return false; } int fast_nondominated_sort(individual pop[],int N){ int F_num=0; int number[2*NP+10]={0}; for(int p=0;p<N;p++){ int num_dominated=0; int num_bedominated=0; for(int q=0;q<N;q++){ if(p==q)continue; if(is_dominated(pop,p,q)){ pop[p].set_dominated[num_dominated++]=q; }else if(is_dominated(pop,q,p)){ num_bedominated++; } } number[p]=num_bedominated; pop[p].num_dominated=num_dominated; pop[p].num_bedominated=num_bedominated; if(num_bedominated==0){ pop[p].rank=0; F[0].ind[F_num++]=pop[p]; } } F[0].num=F_num; int m=0; while(F[m].num!=0){ F_num=0; for(int p=0;p<F[m].num;p++){ //printf("p: %d\n",p); individual &ind=F[m].ind[p]; //printf("num_domi: %d\n",ind.num_dominated); for(int q=0;q<ind.num_dominated;q++){ int nq=pop[ ind.set_dominated[q] ].num_bedominated; nq--; int id=ind.set_dominated[q]; number[id]--; nq=number[id]; if(nq==0){ pop[ ind.set_dominated[q] ].rank=m+1; F[m+1].ind[F_num++]=pop[ ind.set_dominated[q] ]; } } } F[++m].num=F_num; } return m; } bool cmp0(individual a,individual b){ return a.fitness[0]<b.fitness[0]; } bool cmp1(individual a,individual b){ return a.fitness[1]<b.fitness[1]; } void crowding_distance_assignment(individual pop[],int N){ for(int i=0;i<N;i++)pop[i].distance=0; for(int pro=0;pro<problem;pro++){ switch(pro){ case 0:sort(pop,pop+N,cmp0);break; case 1:sort(pop,pop+N,cmp1);break; } pop[0].distance=pop[N-1].distance=INF+0.0; for(int i=1;i<N-1;i++) pop[i].distance += ( pop[i+1].fitness[pro] - pop[i-1].fitness[pro] ) / ( pop[N-1].fitness[pro] - pop[0].fitness[pro] ); } } bool cmp(individual a,individual b){ if(a.rank<b.rank) return true; else if(a.rank==b.rank && a.distance>b.distance) return true; return false; } void BitwiseMutation_for_BinaryCoded(const individual P[],individual tmp[]){ int index,a,b; bool flag[NP+10]={0}; for(int i=0;i<NP/2;i++){ while(true){ a=rand()%NP; if(flag[a])continue; break; } while(true){ b=rand()%NP; if(b==a)continue; if(flag[b])continue; break; } if(cmp(P[a],P[b])) index=a; else index=b; flag[index]=true; tmp[i]=P[index]; } } double judge(double x){ if(x<0.0) x=0.0; else if(x>1.0) x=1.0; return x; } void SBX_(individual Q[],individual tmp[],int&j){ double u,beta; int a,b; a=rand()%(NP/2); while(true){ b=rand()%(NP/2); if(a==b)continue; break; } individual inda=tmp[a]; individual indb=tmp[b]; for(int i=0;i<D;i++){ //while(true){ u=rand()/(RAND_MAX+1.0); //if(u==0.0)continue; //break; //} if(u<0.5) beta=pow(2*u,1/(cc+1)); else beta=1/pow(2*(1-u),1/(cc+1)); double y1=0.5*((1-beta)*inda.xreal[i]+(1+beta)*indb.xreal[i]); double y2=0.5*((1+beta)*inda.xreal[i]+(1-beta)*indb.xreal[i]); //cout<<"y1: "<<y1<<" y2: "<<y2<<endl; Q[j].xreal[i]=judge(y1); Q[j+1].xreal[i]=judge(y2); } calc_fitness_ZDT1(Q[j]); calc_fitness_ZDT1(Q[j+1]); //j+=2; } void polynomial_mutation(individual Q[],individual tmp[],int&j){ int a=rand()%(NP/2); double rk,beta; individual ind=tmp[a]; double rate=1.0/D; for(int i=0;i<D;i++){ double random=rand()/(RAND_MAX+1.0); if(random>=rate) { Q[j].xreal[i]=tmp[a].xreal[i]; continue; } rk=rand()/(RAND_MAX+1.0); if(rk<0.5) beta=pow(2*rk,1/(mm+1))-1.0; else beta=1.0-pow(2*(1.0-rk),1/(mm+1)); double y=ind.xreal[i]+(upper-lower)*beta; Q[j].xreal[i]=judge(y); } calc_fitness_ZDT1(Q[j]); //j++; } void mamk_new_pop(const individual P[],individual Q[]){ individual tmp[NP]; BitwiseMutation_for_BinaryCoded(P,tmp); for(int i=0;i<NP;i++){ double r=rand()/(RAND_MAX+0.0); //cout<<r<<endl; if(r<0.9){ SBX_(Q,tmp,i); }else polynomial_mutation(Q,tmp,i); } } int main(){ freopen("nsga2.out","w",stdout); srand((unsigned int)time(NULL)); init_population(P,NP); init_population(Q,NP); for(int gen=0;gen<G;gen++){ //printf("gen: %d\n",gen); mergePQ(R,P,Q); int m=fast_nondominated_sort(R,2*NP); int num_P=0; int i=0; while(num_P+F[i].num<=NP){ crowding_distance_assignment(F[i].ind,F[i].num); //printf("%d\n",F[i].num); for(int j=0;j<F[i].num;j++) P[num_P++]=F[i].ind[j]; //printf("num_P: %d\n",num_P); i++; } //printf("gen1: %d\n",gen); //crowding_distance_assignment(F[i].ind,F[i].num); if(num_P<NP){ crowding_distance_assignment(F[i].ind,F[i].num); //cout<<F[i].num<<endl; //sort(F[i].ind,F[i].ind+F[i].num,cmp); sort(F[i].ind,F[i].ind+F[i].num); int tmp=num_P; for(int j=0;j<NP-tmp;j++) P[num_P++]=F[i].ind[j]; } //cout<<num_P<<endl; //output_pop(P); mamk_new_pop(P,Q); //output_pop(P); } for(int i=0;i<NP;i++)printf("%f %f\n",P[i].fitness[0],P[i].fitness[1]); /*puts(""); for(int i=0;i<NP;i++)calc_fitness_ZDT1(P[i]); for(int i=0;i<NP;i++)printf("%f %f\n",P[i].fitness[0],P[i].fitness[1]);*/ for(int i=0;i<NP;i++){ cout<<i<<" "; for(int j=0;j<D;j++) cout<<P[i].xreal[j]<<" "; cout<<endl; } printf("time: %.6f\n",(double)clock()/CLOCKS_PER_SEC); //system("pause"); return 0; }
