说明:在学习生活中,经常会遇到各种各样的最优问题,其中最常见的就是求某个多维(多个自变量)函数在各个自变量各取何值时的最大值或最小值;例如求函数 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<<" The Genetic Algrithm System "<<endl; 12 cout<<" The Initial Pop: "<<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<<" The Iteration Begins: "<<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<<" "<<"The Last Population : "<<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<<" "; 51 return 0; 52 } 53 54
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
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...... "; 10 cout<<" Pls Follow The Steps To Complete Your Compution..... "; 11 cout<<" Step 1: Pls Make Sure The Function Have Been Modefied..... "; 12 cout<<" Step 2: Pls Input The Downlimit Of First Variation :"; 13 cin>>downlimit; 14 cout<<" Step 3: Pls Input The Uplimit Of First Variation :"; 15 cin>>uplimit; 16 cout<<" Step 4: Pls Input The Downlimit Of Second Variation :"; 17 cin>>downlimit1; 18 cout<<" Step 5: Pls Input The Uplimit Of Second Variation :"; 19 cin>>uplimit1; 20 cout<<" Step 6: Pls Input The Downlimit Of Third Variation :"; 21 cin>>downlimit2; 22 cout<<" Step 7: Pls Input The Uplimit Of Third Variation :"; 23 cin>>uplimit2; 24 cout<<" Step 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<<" "; 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
使用注意事项:
a.根据具体的目标函数修改评价函数方程,
b.根据具体的自变量的范围及其维数来设计初始化函数及相关的函数。
c.Accurate 参数用于当目标函数趋于稳定状态时的优化,即探测此时自变量该精度变化范围内的目标函数变化情况,从而获得更为优越的目标值。应注意的是,当要求精度越高时,该参数要求尽量小,同时迭代次数应该尽可能地高。
d.本例中涉及一个三维的单目标测试函数,使用源代码直接按照提示步骤输入相应的各个变量上下限及迭代次数即可。
★★★基于C++改进的单目标遗传算法实现界面★★★★
★★★ 测试函数最大值为 零 ★★★