###### tags: `計算智慧與規劃` `期末專題`
# GA 程式碼
[TOC]
### 程式碼可更改的地方
- line 72 in GaRosenbrock_1 : 可更改選擇、交配、突變的方法設定
### 每個測資的最佳方法
- MFE 20000
- Eil51.txt

- Eil76.txt

- Pr76.txt

- St70.txt

- Oliver30.txt

### 選擇
- 競賽 Tournament
- 俄羅斯輪盤 Roulette_Wheel
- 精英 Elitism Selection
> 從 父母+孩子 中挑出前幾名作為下一代的父母,剩下染色體直接淘汰
- 缺點:因為不容易發生突變,所以容易變成局部最佳解
> 但是為什麼不容易發生突變呢?[name=陳琪樺]
- truncation selection
### 交配
- Alfa_Extension_Arithmetic_X
- Arithmetic_X
- Partially matched crossover(PMX)
> 適用於整數不重複的染色體
> [參考資料](https://medium.com/qiubingcheng/%E4%BB%A5python%E5%AF%A6%E4%BD%9C%E5%9F%BA%E5%9B%A0%E6%BC%94%E7%AE%97%E6%B3%95-genetic-algorithm-ga-%E4%B8%A6%E8%A7%A3%E6%B1%BA%E5%B7%A5%E4%BD%9C%E6%8C%87%E6%B4%BE%E5%95%8F%E9%A1%8C-job-assignment-problem-jap-b0d7c4ad6d0f)
### 突變
- 高斯 Gaussian_Mutation
- General_Mutation
- Uniform_Variance_Mutation
### 程式碼
:::spoiler GA 程式碼
```csharp=
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using Metaheuristic;
// 會印出最好的, 和染色體的樣子
namespace GA_Lib_23fun
{
class Program_gbest : GA //Rosenbrock Problem Solver Class
{
int functionNumber; //函數編號
int numDimensions; //維度數
int ShekelM = 5;
int startfunction = 23; //start
int numRepetitiveRuns = 5; //重複執行次數
int numFunctions = 1; //函數的數量=1; > 1 需另存每一函數之Gbest
double dimensionsLowerBound; //變數的下限
double dimensionsUpperBound; //變數的上限
double processTime; //使用時間
double[] tempFunctionAllGlobalBestFitness1;
double[,] ShekelAijMatrix = new double[4, 10] { { 4, 1, 8, 6, 3, 2, 5, 8, 6, 7 }, { 4, 1, 8, 6, 7, 9, 5, 1, 2, 3.6 }, { 4, 1, 8, 6, 3, 2, 3, 8, 6, 7 }, { 4, 1, 8, 6, 7, 9, 3, 1, 2, 3.6 } };
double[] ShekelCiMatrix = new double[10] { 0.1, 0.2, 0.2, 0.4, 0.4, 0.6, 0.3, 0.7, 0.5, 0.5 };
double[] bestSolutionAverages = new double[24]; //所有Best Solution的平均
double[] bestSolutionSDs = new double[24]; //所有Best Solution的標準差
double[] functionAverageProcessTime = new double[24]; //所有的平均使用時間
double[] functionBestSolutions = new double[24]; //所有Best Solution中最佳的
string functionName; //函數名稱
string[] functionNames = new string[24]; //所有函數名稱
static void Main(string[] args)
{
Console.WriteLine("Start main function");
Program_gbest ga = new Program_gbest(); //建立Program的實體
ga.tempFunctionAllGlobalBestFitness1 = new double[ga.numRepetitiveRuns];
//將計算後的結果寫入檔案
StreamWriter fileWriter = new StreamWriter("GA-23Function_Gbest4.csv");
fileWriter.WriteLine("Function(Dim), Best, Average, Std, Time(s)");
Stopwatch stopWatch = new Stopwatch(); //建立計時器
Console.WriteLine("Function(Dim), Best, Average, Std, Time(s)");
string[] reader = File.ReadAllLines("Normailization仁武_2019.csv"); // 例子: Normailization鳳山_2020.csv
int N = reader.Length; // 總共幾筆資料
data = new double[N, 11]; // data大小: N*11 (時間不算)
// 資料存進 data
for (int i = 0; i < N; i++)
{
string[] a = reader[i].Split(',');
for (int j = 1; j < 12; j++)
{
data[i, j - 1] = Convert.ToDouble(a[j]); // 注意型態 (double)
}
}
//ga.startfunction 決定要開啟哪個函式
for (int function = ga.startfunction; function < ga.numFunctions + ga.startfunction; function++)
{ //對於23個function
stopWatch.Reset(); //將計算的時間歸零
stopWatch.Start(); //開始計算時間
ga.InitFunction(function + 1); //呼叫初始函數設定變數內容,問題初始化 因為每個函式的維度、上下限皆不同
ga.functionNames[function] = ga.functionName; //紀錄函數名稱
ga.bestSolutionAverages[function] = 0;
ga.processTime = 0;
double[] tempFunctionAllGlobalBestFitness = new double[ga.numRepetitiveRuns]; //初始化所有gbest的暫存地點
ga.functionBestSolutions[function] = Double.MaxValue; //因為是最小化問題,所以將gbest先設定為最大化
for (int run = 0; run < ga.numRepetitiveRuns; run++)
{ //每一個function各執行ga.numRepetitiveRuns次
Console.WriteLine(ga.functionName + "第" + (run + 1) + "次執行");
//開始執行GA計算該function的GBestFitness
ga.Init(20, ga.numDimensions, ga.dimensionsLowerBound, ga.dimensionsUpperBound, GAOption.EncodingType.Real, GAOption.RepeatableOption.Repeatable); //演算法初始化
ga.SetStrategy(GAOption.Select.Tournament, GAOption.Crossover.RealNumber.Alfa_Extension_Arithmetic_X, GAOption.Mutation.RealNumber.Uniform_Variance_Mutation); //選擇、交配、突變的方法設定在此
// (設定初代數目, 交配律, 突變律)
ga.Run(160000, 0.8, 0.1);
//執行結束
tempFunctionAllGlobalBestFitness[run] = ga.GBestFitness; //紀錄每一次的GBestFitness
ga.tempFunctionAllGlobalBestFitness1[run] = ga.GBestFitness;
//fileWriter.WriteLine(ga.tempFunctionAllGlobalBestFitness1[run]);
ga.bestSolutionAverages[function] += ga.GBestFitness; //將每一次的GBestFitness紀錄下來,後面可用來計算10次的平均
if (ga.GBestFitness < ga.functionBestSolutions[function])
{ //紀錄最小(最佳)的GBestFitness
ga.functionBestSolutions[function] = ga.GBestFitness;
}
}
stopWatch.Stop(); //停止計算時間
ga.processTime = (double)(stopWatch.Elapsed.TotalMilliseconds / 1000); //紀錄每一個function執行10次的總時間
Console.WriteLine("process time: " + ga.processTime);
ga.bestSolutionAverages[function] /= ga.numRepetitiveRuns; //計算平均的GBestFitness
ga.bestSolutionSDs[function] = sd(tempFunctionAllGlobalBestFitness); //計算10次GBestFitness的標準差
ga.functionAverageProcessTime[function] = ga.processTime / ga.numRepetitiveRuns; //計算執行10次的平均時間
}
//寫出內容
for (int function = ga.startfunction; function < ga.numFunctions + ga.startfunction; function++)
{
Console.WriteLine(ga.functionNames[function] + ", " + ga.functionBestSolutions[function] + ", " + ga.bestSolutionAverages[function] + ", " + ga.bestSolutionSDs[function] + ", " + ga.functionAverageProcessTime[function]);
fileWriter.WriteLine(ga.functionNames[function] + "," + ga.functionBestSolutions[function] + "," + ga.bestSolutionAverages[function] + "," + ga.bestSolutionSDs[function] + "," + ga.functionAverageProcessTime[function]);
Console.WriteLine();
//*******************寫出最佳解GBest內容*****************************
Console.WriteLine("Best solution found: " + ga.GBest.Length);
for (int i = 0; i < ga.GBest.Length; i++)
{
//
Console.Write("{0}, ", ga.GBest[i]);
}
fileWriter.WriteLine("Best solution found: ");
for (int i = 0; i < ga.GBest.Length; i++)
{
fileWriter.Write("{0},", ga.GBest[i]);
}
//**************************************************
}
fileWriter.Close();
//寫入檔案結束
Console.Read();
}
public static double sd(double[] fit)
{
double sum = 0.0;
double average;
for (int i = 0; i < fit.Length; i++)
{
sum += fit[i];
}
average = sum / fit.Length;
sum = 0.0;
for (int i = 0; i < fit.Length; i++)
{
sum += (Math.Pow(fit[i] - average, 2));
}
return Math.Pow(sum / fit.Length, 0.5);
}
// 算分方式
public static double[,] data;
public override double Fitness(double[] pos)
{
double fitness = 0;
double total = 0.0;
int times = 800; // 總共取幾組資料
if (functionNumber == 1)
{ //Easom
double ePow = -Math.Pow(pos[0] - Math.PI, 2) - Math.Pow(pos[1] - Math.PI, 2);
double sum = 0;
fitness = -Math.Cos(pos[0]) * Math.Cos(pos[1]) * Math.Pow(Math.E, ePow);
/* Circle
double ePow = Math.Sqrt(Math.Pow(pos[0], 2) + Math.Pow(pos[1], 2) + Math.Pow(pos[2], 2));
fitness = Math.Abs(ePow-1);
*/
}
else if (functionNumber == 2)
{ //Shubert
double fitness1 = 0, fitness2 = 0;
for (int j = 1; j <= 5; j++)
{
fitness1 = fitness1 + j * Math.Cos((j + 1) * pos[0] + j);
fitness2 = fitness2 + j * Math.Cos((j + 1) * pos[1] + j);
}
fitness = fitness1 * fitness2;
}
else if (functionNumber == 3 | functionNumber == 10 | functionNumber == 15 | functionNumber == 20)
{ //Rosenbrock
for (int j = 0; j < numDimensions - 1; j++)
{
fitness = fitness + 100 * Math.Pow(pos[j + 1] - Math.Pow(pos[j], 2), 2) + Math.Pow(pos[j] - 1, 2);
}
}
else if (functionNumber == 4 | functionNumber == 13 | functionNumber == 18 | functionNumber == 23)
{ //Zakharov
double fitness1 = 0, fitness2 = 0;
for (int j = 0; j < numDimensions; j++)
{
fitness1 = fitness1 + Math.Pow(pos[j], 2);
fitness2 = fitness2 + 0.5 * (j + 1) * pos[j];
}
fitness = fitness1 + Math.Pow(fitness2, 2) + Math.Pow(fitness2, 4);
}
else if (functionNumber == 5 | functionNumber == 9 | functionNumber == 14 | functionNumber == 19)
{ //Sphere
for (int j = 0; j < numDimensions; j++)
{
fitness = fitness + Math.Pow(pos[j], 2);
}
}
else if (functionNumber == 6 | functionNumber == 7 | functionNumber == 8)
{ //Shekel
double sum;
for (int n = 0; n < ShekelM; n++)
{
sum = 0;
for (int j = 0; j < numDimensions; j++)
{
sum = sum + Math.Pow(pos[j] - ShekelAijMatrix[j, n], 2);
}
fitness = fitness + 1 / (sum + ShekelCiMatrix[n]);
}
fitness = -fitness;
}
else if (functionNumber == 11 | functionNumber == 16 | functionNumber == 21)
{ //Rastrigin
for (int j = 0; j < numDimensions; j++)
{
//fitness = fitness + Math.Pow(pos[j], 2) - (10 * Math.Cos(2 * Math.PI * pos[j])) + 10;
fitness = fitness + pos[j];
}
//fitness = -1.0*fitness;
}
else if (functionNumber == 0 | functionNumber == 17 | functionNumber == 22)
{ //Griewank
double fitness1 = 0;
double fitness2 = 1;
for (int j = 0; j < numDimensions; j++)
{
fitness1 = fitness1 + Math.Pow(pos[j], 2);
fitness2 = fitness2 * Math.Cos(pos[j] / Math.Sqrt(j + 1));
}
fitness = fitness1 / 4000 - fitness2 + 1;
}
else if (functionNumber == 24)
{
Random random = new Random();
for (int time = 0; time < times; time++)
{
//Console.WriteLine("{0} times", time);
int rd = random.Next(0, data.GetLength(0)); // 亂數
//Console.WriteLine("-----------{0}-----------", rd + 1);
double[] tmp = new double[11];
for (int t = 0; t < 11; t++)
{
tmp[t] = data[rd, t];
}
double answer = data[rd, 10];
double fit = 0;
for (int t = 0; t < pos.Length - 1; t++)
{
fit += pos[t] * tmp[t];
}
fit = fit - pos[pos.Length - 1];
fit = Math.Abs(fit - answer);
total += fit;
}
fitness = total / times;
}
return fitness;
}
// 寫function 的地方
public void InitFunction(int number)
{
switch (number)
{
//2 numDimensions------------------------------
case (1):
//Easom(2)
/* this.functionName = "Easom(2)";
this.functionNumber = 1;
this.numDimensions = 2;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -10;
*/
/* this.functionName = "Circle(3)";
this.functionNumber = 1;
this.numDimensions = 3;
this.dimensionsUpperBound = 5;
this.dimensionsLowerBound = -5;
*/
this.functionName = "Permutation(10)";
this.functionNumber = 1;
this.numDimensions = 10;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = 1;
break;
case (2):
//Shubert(2)
this.functionName = "Shubert(2)";
this.functionNumber = 2;
this.numDimensions = 2;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -10;
break;
case (3):
//Rosenbrock(2)
this.functionName = "Rosenbrock(2)";
this.functionNumber = 3;
this.numDimensions = 2;
this.dimensionsUpperBound = 30;
this.dimensionsLowerBound = -30;
break;
case (4):
//Zakharov(2)
this.functionName = "Zakharov(2)";
this.functionNumber = 4;
this.numDimensions = 2;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -5;
break;
//3 numDimensions------------------------------
case (5):
//De Joung(3)
this.functionName = "De Joung(3)";
this.functionNumber = 5;
this.numDimensions = 3;
this.dimensionsUpperBound = 5.12;
this.dimensionsLowerBound = -5.12;
break;
//4 numDimensions------------------------------
case (6):
//Shekel(4,5)
this.functionName = "Shekel(4.5)";
this.functionNumber = 6;
this.numDimensions = 4;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = 0;
this.ShekelM = 5;
break;
case (7):
//Shekel(4,7)
this.functionName = "Shekel(4.7)";
this.functionNumber = 7;
this.numDimensions = 4;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = 0;
this.ShekelM = 7;
break;
case (8):
//Shekel(4,10)
this.functionName = "Shekel(4.10)";
this.functionNumber = 8;
this.numDimensions = 4;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = 0;
//this.dimensionsUpperBound = 10;
//this.dimensionsLowerBound = 0;
this.ShekelM = 10;
break;
//10 numDimensions------------------------------
case (9):
//Sphere(10)
this.functionName = "Sphere(10)";
this.functionNumber = 9;
this.numDimensions = 10;
this.dimensionsUpperBound = 100;
this.dimensionsLowerBound = -100;
break;
case (10):
//Rosenbrock(10)
this.functionName = "Rosenbrock(10)";
this.functionNumber = 10;
this.numDimensions = 10;
this.dimensionsUpperBound = 30;
this.dimensionsLowerBound = -30;
break;
case (11):
//Rastrigin(10)
this.functionName = "Rastrigin(10)";
this.functionNumber = 11;
this.numDimensions = 10;
this.dimensionsUpperBound = 5.12;
this.dimensionsLowerBound = -5.12;
break;
case (12):
//Griewank(10)
this.functionName = "Griewank(10)";
this.functionNumber = 12;
this.numDimensions = 10;
this.dimensionsUpperBound = 600;
this.dimensionsLowerBound = -600;
break;
case (13):
//Zakharov(10)
this.functionName = "Zakharov(10)";
this.functionNumber = 13;
this.numDimensions = 10;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -5;
break;
//20 numDimensions------------------------------
case (14):
//Sphere(20)
this.functionName = "Sphere(20)";
this.functionNumber = 14;
this.numDimensions = 20;
this.dimensionsUpperBound = 100;
this.dimensionsLowerBound = -100;
break;
case (15):
//Rosenbrock(20)
this.functionName = "Rosenbrock(20)";
this.functionNumber = 15;
this.numDimensions = 20;
this.dimensionsUpperBound = 30;
this.dimensionsLowerBound = -30;
break;
case (16):
//Rastrigin(20)
this.functionName = "Rastrigin(20)";
this.functionNumber = 16;
this.numDimensions = 20;
this.dimensionsUpperBound = 5.12;
this.dimensionsLowerBound = -5.12;
break;
case (17):
//Griewank(20)
this.functionName = "Griewank(20)";
this.functionNumber = 17;
this.numDimensions = 20;
this.dimensionsUpperBound = 600;
this.dimensionsLowerBound = -600;
break;
case (18):
//Zakharov(20)
this.functionName = "Zakharov(20)";
this.functionNumber = 18;
this.numDimensions = 20;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -5;
break;
//30 numDimensions------------------------------
case (19):
//Sphere(30)
this.functionName = "Sphere(30)";
this.functionNumber = 19;
this.numDimensions = 30;
this.dimensionsUpperBound = 100;
this.dimensionsLowerBound = -100;
break;
case (20):
//Rosenbrock(30)
this.functionName = "Rosenbrock(30)";
this.functionNumber = 20;
this.numDimensions = 30;
this.dimensionsUpperBound = 30;
this.dimensionsLowerBound = -30;
break;
case (21):
//Rastrigin(30)
this.functionName = "Rastrigin(30)";
this.functionNumber = 21;
this.numDimensions = 30;
this.dimensionsUpperBound = 5.12;
this.dimensionsLowerBound = -5.12;
break;
case (22):
//Griewank(30)
this.functionName = "Griewank(30)";
this.functionNumber = 22;
this.numDimensions = 30;
this.dimensionsUpperBound = 600;
this.dimensionsLowerBound = -600;
break;
case (23):
//Zakharov(30)
this.functionName = "Zakharov(30)";
this.functionNumber = 23;
this.numDimensions = 30;
this.dimensionsUpperBound = 10;
this.dimensionsLowerBound = -5;
break;
case (24):
//Our(30)
this.functionName = "OurFirst(01)";
this.functionNumber = 24;
this.numDimensions = 11; //10的變因 + 1個誤差值
this.dimensionsUpperBound = 1;
this.dimensionsLowerBound = 0;
break;
default:
break;
}
}
}
}
```