(C/C++学习)19.单目标遗传算法的C程序实现

说明:在学习生活中,经常会遇到各种各样的最优问题,其中最常见的就是求某个多维(多个自变量)函数在各个自变量各取何值时的最大值或最小值;例如求函数 f(x) = (x-5)2+(y-6)2+(z-7)2 的最小值,当然,这个函数很简单,很容易看出来,该函数的最小值为0,分别在三个自变量取5,6,7时取得最小值。但日常学习中的函数都是很复杂的,就算通过大量的计算,也不一定能准确地算出目标值以及在何时取得该目标值,因此,本文介绍一种基于单目标的遗传算法来解决此类问题。

注意:由于封装函数较多,为了清晰,函数名一般为其英文名,因此比较长,强烈建议电脑阅读。

1.遗传算法代码实现

遗传算法的相关概念,这里不多说,网上一大堆,这里只介绍本程序的实现过程,代码如下:

a.第一部分为主函数

  1 #include <iostream>
  2 #include <genetic.h>
  3 using namespace std;
  4 
  5 int main()
  6 {
  7     Genetic M;
  8     int Iteration = 0;
  9     //种群及重要参数初始化
 10     M.initiallize(M.Initialpop,Populationsize);
 11     cout<<"\n\t\t\t\t  The Genetic Algrithm System\n"<<endl;
 12     cout<<"\n\t\t\t\t\tThe Initial Pop:\n"<<endl;
 13     cout<<setw(20)<<"x"<<setw(20)<<"y"<<setw(20)<<"z"<<setw(20)<<"Fitness"<<endl<<endl;
 14     //获取种群适应度
 15     M.getfitnessofpop(M.Initialpop,Populationsize);
 16     //根据适应度排序
 17     M.sortpopbyfitness(M.Initialpop,Populationsize);
 18     //打印初始种群
 19     M.printpop(M.Initialpop,Populationsize);
 20     cout<<"\n\n\t\t\t\t\tThe Iteration Begins:\n"<<endl;
 21     cout<<setw(20)<<"Iteration"<<setw(20)<<"x"<<setw(20)<<"y"<<setw(20)<<"z"<<setw(20)<<"Fitness"<<endl<<endl;
 22     while(Iteration <= M.Iterationtimes)
 23     {
 24         //交叉
 25         M.crossover(M.Initialpop,M.Offspring,Populationsize);
 26         //求取种群适应度
 27         M.getfitnessofpop(M.Offspring,Populationsize);
 28         //根据适应度排序
 29         M.sortpopbyfitness(M.Offspring,Populationsize);
 30         //父子代结合
 31         M.combinationpop(M.Initialpop,M.Offspring,M.Combinationpop,Populationsize);
 32         //变异
 33         M.mutation(M.Combinationpop,Populationsize*2);
 34         //求取结合种群适应度
 35         M.getfitnessofpop(M.Combinationpop,Populationsize*2);
 36         //对结合种群排序
 37         M.sortpopbyfitness(M.Combinationpop,Populationsize*2);
 38         //选择较优个体
 39         M.selectbestpop(M.Combinationpop,M.Initialpop,Populationsize);
 40         //结果微调,精确算子
 41         M.getAccurateResult(M.Initialpop,Populationsize);
 42         //打印迭代过程中出现的最优个体
 43         M.printbestindivil(M.Initialpop,Populationsize,Iteration);
 44         Iteration++;
 45     }
 46     cout<<"\n\n"<<"The Last Population : \n"<<endl;
 47     cout<<setw(20)<<"Iteration"<<setw(20)<<"x"<<setw(20)<<"y"<<setw(20)<<"z"<<setw(20)<<"Fitness"<<endl<<endl;
 48     //打印最后一代的所有个体成员及其目标值
 49     M.printpop(M.Initialpop,Populationsize);
 50     cout<<"\n\n\n";
 51     return 0;
 52 }
 53 
 54 
View Code

 

b.第二部分为基因操作头文件

  1 #ifndef GENETIC_H
  2 #define GENETIC_H
  3 #include <time.h>
  4 #include <stdlib.h>
  5 #include <iomanip>
  6 #include <iostream>
  7 #include <math.h>
  8 using namespace std;
  9 #define Populationsize 16
 10 #define pi 3.1415926
 11 #define Accurate 0.001
 12 //精度越高要求迭代次数越大
 13 
 14 class Genetic
 15 {
 16 public:
 17     Genetic();
 18     typedef struct Individual
 19     {
 20         double x;
 21         double y;
 22         double z;
 23         double fitness;
 24     }Individuals;
 25     Individuals Initialpop[Populationsize];
 26     Individuals Offspring[Populationsize];
 27     Individuals Combinationpop[Populationsize*2];
 28     Individuals Bestindividual;
 29     double crossoverability;
 30     double mutationproability;
 31     double downlimit;
 32     double uplimit;
 33     double downlimit1;
 34     double uplimit1;
 35     double downlimit2;
 36     double uplimit2;
 37     int Iterationtimes;
 38 
 39     void initiallize(Individuals *Initialpop,int Populationsiz);
 40     void printpop(Individuals *Initialpop,int Populationsiz);
 41     double getfitnessofindiv(double x,double y,double z);
 42     void getfitnessofpop(Individuals *Initialpop,int Populationsiz);
 43     void sortpopbyfitness(Individuals *Initialpop,int Populationsiz);
 44     void crossover(Individuals *Initialpop,Individuals *offspring,int Populationsiz);
 45     void combinationpop(Individuals *Initialpop,Individuals *offspring,Individuals* Combinationpop,int populationsize);
 46     void mutation(Individuals *Initialpop,int population);
 47     void selectbestpop(Individuals* Combinationpo,Individuals *Initialpop,int population);
 48     void printbestindivil(Individuals* Initialpop,int populationsize, int Iteration);
 49     void getAccurateResult(Individuals* Initialpop,int population);
 50 };
 51 
 52 #endif // GENETIC_H
 53 
View Code


c.第三部分为基因操作头文件相应的 cpp 文件

  1 #include "genetic.h"
  2 
  3 Genetic::Genetic()
  4 {
  5 
  6 }
  7 void Genetic::initiallize(Genetic::Individuals *Initialpop, int Populationsiz)
  8 {
  9     cout<<"Welcome To The Genetic Algrithm System......\n";
 10     cout<<"\nPls Follow The Steps To Complete Your Compution.....\n\n";
 11     cout<<"\nStep 1: Pls Make Sure The Function Have Been Modefied.....\n";
 12     cout<<"\nStep 2: Pls Input The Downlimit Of First Variation :";
 13     cin>>downlimit;
 14     cout<<"\nStep 3: Pls Input The Uplimit Of First Variation :";
 15     cin>>uplimit;
 16     cout<<"\nStep 4: Pls Input The Downlimit Of Second Variation :";
 17     cin>>downlimit1;
 18     cout<<"\nStep 5: Pls Input The Uplimit Of Second Variation :";
 19     cin>>uplimit1;
 20     cout<<"\nStep 6: Pls Input The Downlimit Of Third Variation :";
 21     cin>>downlimit2;
 22     cout<<"\nStep 7: Pls Input The Uplimit Of Third Variation :";
 23     cin>>uplimit2;
 24     cout<<"\nStep 8: Pls Input The Max Iteration Times Of The Caculate:";
 25     cin>>Iterationtimes;
 26     srand(time(NULL));
 27     crossoverability = 0.8;
 28     mutationproability = 0.1;
 29     for(int i=0; i<Populationsiz; i++)
 30     {
 31         Initialpop[i].x = downlimit + (rand()%50)/50.0*(uplimit-downlimit);
 32         Initialpop[i].y = downlimit1 + (rand()%50)/50.0*(uplimit1-downlimit1);
 33         Initialpop[i].z = downlimit2 + (rand()%50)/50.0*(uplimit2-downlimit2);
 34     }
 35 }
 36 
 37 void Genetic::printpop(Genetic::Individuals *Initialpop, int Populationsiz)
 38 {
 39     for(int i =0;i<Populationsiz;i++)
 40     {
 41         cout<<setw(20)<<setprecision(5)<<Initialpop[i].x<<setw(20)<<setprecision(5)
 42            <<Initialpop[i].y<<setw(20)<<setprecision(5)<<Initialpop[i].z<<setw(20)
 43           <<fixed<<setprecision(7)<<Initialpop[i].fitness<<endl;
 44     }
 45 }
 46 
 47 double Genetic::getfitnessofindiv(double x, double y, double z)
 48 {
 49     double result;
 50     result = -(x+12)*(x+12)-(y+7)*(y+7)-(z+10)*(z+10);
 51     return result;
 52 }
 53 
 54 void Genetic::getfitnessofpop(Genetic::Individuals *Initialpop, int Populationsiz)
 55 {
 56     for(int i = 0;i<Populationsiz;i++)
 57     {
 58         Initialpop[i].fitness = getfitnessofindiv(Initialpop[i].x,Initialpop[i].y,Initialpop[i].z);
 59     }
 60 }
 61 
 62 void Genetic::sortpopbyfitness(Genetic::Individuals *Initialpop, int Populationsiz)
 63 {
 64     for(int i = 0;i<Populationsiz;i++)
 65     {
 66         int idx = i;
 67         for(int j = i+1;j<Populationsiz;j++)
 68         {
 69             if(Initialpop[idx].fitness > Initialpop[j].fitness)
 70                 idx = j;
 71         }
 72         if(idx != i)
 73         {
 74             Individual temp = Initialpop[i];
 75             Initialpop[i] = Initialpop[idx];
 76             Initialpop[idx] = temp;
 77         }
 78     }
 79     Bestindividual = Initialpop[0];
 80 }
 81 
 82 void Genetic::crossover(Individuals *Initialpop,Individuals *offspring, int Populationsiz)
 83 {
 84     for(int i = 1;i<=Populationsiz;i++)
 85     {
 86         //保证适值为正
 87         Initialpop[Populationsiz-i].fitness += -Initialpop[0].fitness;
 88     }
 89     srand(time(NULL));
 90     Individuals parent[2];
 91     double temp = 0;
 92     double totalfitness = 0;
 93     double gradient[Populationsiz] = {0};
 94     for(int i = 0;i<Populationsiz;i++)
 95     {
 96         totalfitness += Initialpop[i].fitness;
 97     }
 98     for(int i = 0;i<Populationsiz;i++)
 99     {
100         temp += Initialpop[i].fitness;
101         gradient[i] = temp/totalfitness;
102     }
103     for(int i = 0;i<Populationsiz/2;i++)
104     {
105         for(int j = 0;j<2;j++)
106         {
107             double randgradient = rand()%1000/1000.0;
108             for(int k = 0;k<Populationsiz;k++)
109             {
110                 if(k == 0)
111                 {
112                     if(randgradient < gradient[0])
113                     {
114                         parent[j] = Initialpop[k];
115                     }
116                 }
117                 else
118                 {
119                     if(randgradient >= gradient[k-1] && randgradient < gradient[k])
120                     {
121                         parent[j] = Initialpop[k];
122                     }
123                 }
124             }
125         }
126         double Probability = rand()%1000/1000.0;
127         if(Probability < crossoverability)
128         {
129             double b = rand()%100/100.0;
130             if(b <= 0.5)
131             {
132                 double a = pow(2*b,1/21.0);
133                 offspring[2*i].x = ((1+a)*parent[0].x+(1-a)*parent[1].x)/2.0;
134                 offspring[2*i+1].x = ((1-a)*parent[0].x+(1+a)*parent[1].x)/2.0;
135                 offspring[2*i].y = ((1+a)*parent[0].y+(1-a)*parent[1].y)/2.0;
136                 offspring[2*i+1].y = ((1-a)*parent[0].y+(1+a)*parent[1].y)/2.0;
137                 offspring[2*i].z = ((1+a)*parent[0].y+(1-a)*parent[1].z)/2.0;
138                 offspring[2*i+1].z = ((1-a)*parent[0].y+(1+a)*parent[1].z)/2.0;
139 
140                 if(offspring[2*i].x < downlimit || offspring[2*i].x > uplimit
141                         || offspring[2*i+1].x < downlimit || offspring[2*i+1].x > uplimit
142                         || offspring[2*i].y < downlimit1 || offspring[2*i].y > uplimit1
143                         || offspring[2*i+1].y < downlimit1 || offspring[2*i+1].y > uplimit1
144                         || offspring[2*i].z < downlimit2 || offspring[2*i].z > uplimit2
145                         || offspring[2*i+1].z < downlimit2 || offspring[2*i+1].z > uplimit2)
146                 {
147                     i--;
148                 }
149 
150             }
151             else
152             {
153                 double a = pow(2*(1-b),-1/21.0);
154                 offspring[2*i].x = ((1+a)*parent[0].x+(1-a)*parent[1].x)/2.0;
155                 offspring[2*i+1].x = ((1-a)*parent[0].x+(1+a)*parent[1].x)/2.0;
156                 offspring[2*i].y = ((1+a)*parent[0].y+(1-a)*parent[1].y)/2.0;
157                 offspring[2*i+1].y = ((1-a)*parent[0].y+(1+a)*parent[1].y)/2.0;
158                 offspring[2*i].z = ((1+a)*parent[0].y+(1-a)*parent[1].z)/2.0;
159                 offspring[2*i+1].z = ((1-a)*parent[0].y+(1+a)*parent[1].z)/2.0;
160 
161                 if(offspring[2*i].x < downlimit || offspring[2*i].x > uplimit
162                         || offspring[2*i+1].x < downlimit || offspring[2*i+1].x > uplimit
163                         || offspring[2*i].y < downlimit1 || offspring[2*i].y > uplimit1
164                         || offspring[2*i+1].y < downlimit1 || offspring[2*i+1].y > uplimit1
165                         || offspring[2*i].z < downlimit2 || offspring[2*i].z > uplimit2
166                         || offspring[2*i+1].z < downlimit2 || offspring[2*i+1].z > uplimit2)
167                 {
168                     i--;
169                 }
170             }
171         }
172         else
173         {
174             offspring[2*i].x = downlimit + (rand()%50)/50.0*(uplimit-downlimit);
175             offspring[2*i].y = downlimit1 + (rand()%50)/50.0*(uplimit1-downlimit1);
176             offspring[2*i].z = downlimit2 + (rand()%50)/50.0*(uplimit2-downlimit2);
177 
178             offspring[2*i+1].x = downlimit + (rand()%50)/50.0*(uplimit-downlimit);
179             offspring[2*i+1].y = downlimit1 + (rand()%50)/50.0*(uplimit1-downlimit1);
180             offspring[2*i+1].z = downlimit2 + (rand()%50)/50.0*(uplimit2-downlimit2);
181         }
182     }
183 }
184 
185 void Genetic::combinationpop(Individuals *Initialpop,Individuals *offspring,Individuals *Combinationpop,int populationsize)
186 {
187     for(int i = 0;i<populationsize*2;i++)
188     {
189         if(i < populationsize)
190             Combinationpop[i] = Initialpop[i];
191         else
192             Combinationpop[i] = offspring[i-populationsize];
193     }
194 }
195 
196 void Genetic::mutation(Genetic::Individuals *Initialpop, int population)
197 {
198     srand(time(NULL));
199     for(int i = 0;i<population;i++)
200     {
201         double a = rand()%100/100.0;
202         if(a <= mutationproability)
203         {
204             Initialpop[i].x = downlimit + (rand()%50)/50.0*(uplimit-downlimit);
205             Initialpop[i].y = downlimit1 + (rand()%50)/50.0*(uplimit1-downlimit1);
206             Initialpop[i].z = downlimit2 + (rand()%50)/50.0*(uplimit2-downlimit2);
207         }
208     }
209 }
210 
211 void Genetic::selectbestpop(Individuals *Combinationpo,Individuals *Initialpop, int population)
212 {
213     for(int i = 0;i<population;i++)
214         Initialpop[i] = Combinationpo[population+i];
215 }
216 
217 void Genetic::printbestindivil(Genetic::Individuals *Initialpop, int populationsize,int Iteration)
218 {
219     cout<<"\r";
220     cout<<setw(20)<<Iteration<<setw(20)<<Initialpop[populationsize-1].x<<setw(20)
221        <<Initialpop[populationsize-1].y<<setw(20)<<Initialpop[populationsize-1].z
222       <<setw(20)<<Initialpop[populationsize-1].fitness;
223 }
224 
225 void Genetic::getAccurateResult(Genetic::Individuals *Initialpop, int population)
226 {
227     for(int j = 0;j<population;j++)
228     {
229         if(getfitnessofindiv(Initialpop[j].x*(1+Accurate),Initialpop[j].y,Initialpop[j].z)
230                 > Initialpop[j].fitness && Initialpop[j].x*(1+Accurate) <= uplimit &&
231                 Initialpop[j].x*(1+Accurate) >= downlimit)
232             Initialpop[j].x = Initialpop[j].x*(1+Accurate);
233         if(getfitnessofindiv(Initialpop[j].x*(1-Accurate),Initialpop[j].y,Initialpop[j].z)
234                 > Initialpop[j].fitness && Initialpop[j].x*(1-Accurate) >= downlimit &&
235                 Initialpop[j].x*(1-Accurate) <= uplimit)
236             Initialpop[j].x = Initialpop[j].x*(1-Accurate);
237         if(getfitnessofindiv(Initialpop[j].x,Initialpop[j].y*(1+Accurate),Initialpop[j].z)
238                 > Initialpop[j].fitness && Initialpop[j].y*(1+Accurate) <= uplimit1 &&
239                 Initialpop[j].y*(1+Accurate) >= downlimit1)
240             Initialpop[j].y = Initialpop[j].y*(1+Accurate);
241         if(getfitnessofindiv(Initialpop[j].x,Initialpop[j].y*(1-Accurate),Initialpop[j].z)
242                 > Initialpop[j].fitness && Initialpop[j].y*(1-Accurate) >= downlimit1 &&
243                 Initialpop[j].y*(1-Accurate) <= uplimit1)
244             Initialpop[j].y = Initialpop[j].y*(1-Accurate);
245         if(getfitnessofindiv(Initialpop[j].x,Initialpop[j].y,Initialpop[j].z*(1+Accurate))
246                 > Initialpop[j].fitness && Initialpop[j].z*(1+Accurate) <= uplimit2 &&
247                 Initialpop[j].z*(1+Accurate) >= downlimit2)
248             Initialpop[j].z = Initialpop[j].z*(1+Accurate);
249         if(getfitnessofindiv(Initialpop[j].x,Initialpop[j].y,Initialpop[j].z*(1-Accurate))
250                 > Initialpop[j].fitness && Initialpop[j].z*(1-Accurate) >= downlimit2 &&
251                 Initialpop[j].z*(1-Accurate) <= uplimit2)
252             Initialpop[j].z = Initialpop[j].z*(1-Accurate);
253 
254     }
255 
256 }
257 
258 
View Code

使用注意事项:

a.根据具体的目标函数修改评价函数方程,

b.根据具体的自变量的范围及其维数来设计初始化函数及相关的函数。

c.Accurate 参数用于当目标函数趋于稳定状态时的优化,即探测此时自变量该精度变化范围内的目标函数变化情况,从而获得更为优越的目标值。应注意的是,当要求精度越高时,该参数要求尽量小,同时迭代次数应该尽可能地高。

d.本例中涉及一个三维的单目标测试函数,使用源代码直接按照提示步骤输入相应的各个变量上下限及迭代次数即可。

基于C++改进的单目标遗传算法实现界面

捕获

★   测试函数最大值为 零  

posted @ 2018-12-30 22:21  退後。  阅读(580)  评论(0编辑  收藏  举报