在学习遗传算法时,参考了https://blog.csdn.net/kyq0417/article/details/84345094,在运行过程中,做了一些修改,以函数y=-x^2+5求最大值作为测试函数,验证了算法的正确性,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GeneticAlgorithm
{
internal class Program
{
///
/// 染色体
///
private class Chromosome
{
///
/// 用6bit对染色体进行编码
///
public int[] bits = new int[6];
/// <summary>
/// 适应值
/// </summary>
public int fitValue;
/// <summary>
/// 选择概率
/// </summary>
public double fitValuePercent;
/// <summary>
/// 累计概率
/// </summary>
public double probability;
public Chromosome Clone()
{
Chromosome c = new Chromosome();
for (int i = 0; i < bits.Length; i++)
{
c.bits[i] = bits[i];
}
c.fitValue = fitValue;
c.fitValuePercent = fitValuePercent;
c.probability = probability;
return c;
}
}
/// <summary>
/// 染色体组
/// </summary>
private static List<Chromosome> chromosomes = new List<Chromosome>();
private static List<Chromosome> chromosomesChild = new List<Chromosome>();
/// <summary>
/// 随机数产生器
/// </summary>
private static Random random = new Random();
/// <summary>
/// 选择算子方法
/// </summary>
private enum ChooseType
{
Bubble,//冒泡
Roulette,//轮盘赌
}
private static ChooseType chooseType = ChooseType.Roulette;
private static void Print(bool bLoadPercent = false)
{
Console.WriteLine("================================");
for (int i = 0; i < chromosomes.Count; i++)
{
Console.Write("第" + i + "条" + "bits:");
for (int j = 0; j < chromosomes[i].bits.Length; j++)
{
Console.Write(" " + chromosomes[i].bits[j]);
}
int x = DeCode(chromosomes[i].bits);
Console.Write(" x:" + x);
Console.Write(" y:" + chromosomes[i].fitValue);
if (bLoadPercent)
{
Console.Write(" 选择概率:" + chromosomes[i].fitValuePercent);
Console.Write(" 累计概率:" + chromosomes[i].probability);
}
Console.WriteLine();
}
Console.WriteLine("==========================================");
}
/// <summary>
/// 初始化
/// </summary>
private static void Init()
{
chromosomes.Clear();
//染色体数量
int length = 100;
Chromosome chromosome = new Chromosome();
for (int i = 0; i < length; i++)
{
for (int j = 0; j < chromosome.bits.Length; j++)
{
//随机出0或1
int bitValue = random.Next(0, 2);
chromosome.bits[j] = bitValue;
}
//获得十进制的值
int x = DeCode(chromosome.bits);
int y = GetFitValue(x);
chromosome.fitValue = y;
chromosomes.Add(chromosome);
}
}
/// <summary>
/// 解码(二进制转换)
/// </summary>
/// <param name="bits">染色体编码数组</param>
/// <returns>解码值</returns>
private static int DeCode(int[] bits)
{
int result = bits[5] * 16 + bits[4] * 8 + bits[3] * 4 + bits[2] * 2 + bits[1] * 1;
//正数
if (bits[0] == 0)
{
return result;
}
else
{
return -result;
}
}
/// <summary>
/// 获取fit值
/// </summary>
/// <param name="x">输入值</param>
/// <returns>fit值</returns>
private static int GetFitValue(int x)
{
//所求函数:y=-x^2+5
return -x * x + 5;
}
/// <summary>
/// 选择算子(基于轮盘赌法)
/// </summary>
private static void UpdateNext()
{
//获取适应值总和
double totalFitValue = 0;
for (int i = 0; i < chromosomes.Count; i++)
{
//适应度为负数的取0;
if (chromosomes[i].fitValue <= 0)
{
totalFitValue += 0;
}
else
{
totalFitValue += chromosomes[i].fitValue;
}
}
Console.WriteLine("totalFitValue" + totalFitValue);
//算出每个的fit percent;
for (int i = 0; i < chromosomes.Count; i++)
{
if (chromosomes[i].fitValue <= 0)
{
chromosomes[i].fitValuePercent = 0;
}
else
{
chromosomes[i].fitValuePercent = chromosomes[i].fitValue / totalFitValue;
}
Console.WriteLine("fitValuePercent " + i + ":" + chromosomes[i].fitValuePercent);
}
//计算累计概率
第一个的累计概率就是自己的概率
chromosomes[0].probability = chromosomes[0].fitValuePercent;
Console.WriteLine("probability 0" + chromosomes[0].probability);
double probability = chromosomes[0].probability;
for (int i = 1; i < chromosomes.Count; i++)
{
if (chromosomes[i].fitValuePercent != 0)
{
chromosomes[i].probability = chromosomes[i].fitValuePercent + probability;
probability = chromosomes[i].probability;
}
Console.WriteLine("probability " + i + ":" + chromosomes[i].probability);
}
chromosomesChild.Clear();
//优胜劣汰,种群更新
for (int i = 0; i < chromosomes.Count; i++)
{
double rand = random.NextDouble();
Console.WriteLine("挑选的rand" + rand);
if (rand < chromosomes[0].probability)
{
chromosomesChild.Add(chromosomes[0].Clone());
}
else
{
for (int j = 0; j < chromosomes.Count - 1; j++)
{
if (chromosomes[j].probability <= rand && rand <= chromosomes[j + 1].probability)
{
chromosomesChild.Add(chromosomes[j + 1].Clone());
break;
}
}
}
}
for (int i = 0; i < chromosomesChild.Count; i++)
{
chromosomes[i] = chromosomesChild[i];
}
//为下次种群更新做准备
chromosomesChild.Clear();
}
/// <summary>
/// 选择算子(基于冒泡法)
/// </summary>
private static void ChooseChromosome()
{
chromosomes.Sort((a, b) => { return b.fitValue.CompareTo(a.fitValue); });
}
/// <summary>
/// 交叉算子
/// </summary>
private static void CrossOperate()
{
/*bit[0]~bit[5]
* 3 000 110
* 3 001 010
* child1 000 010
* child2 001 110
*/
int rand1 = random.Next(0, 6);
int rand2 = random.Next(0, 6);
if (rand1 > rand2)
{
var t = rand1;
rand1 = rand2;
rand2 = t;
}
Console.WriteLine("交叉的rand" + rand1 + "-" + rand2);
for (int j = 0; j < chromosomes.Count - 1; j = j + 2)
{
for (int i = rand1; i < rand2; i++)
{
var t = chromosomes[j].bits[i];
chromosomes[j].bits[i] = chromosomes[j + 1].bits[i];
chromosomes[j + 1].bits[i] = t;
}
chromosomes[j].fitValue = GetFitValue(DeCode(chromosomes[j].bits));
chromosomes[j + 1].fitValue = GetFitValue(DeCode(chromosomes[j + 1].bits));
}
}
/// <summary>
/// 变异算子
/// </summary>
private static void VariationOperate()
{
int rand = random.Next(0, 50);
Console.WriteLine("判断变异的rand值:" + rand);
//1/50=0.02的概率进行变异
if (rand < 1)
{
Console.WriteLine("开始变异");
int row = random.Next(0, 4);//选择前三个染色体中的任意一个
int col = random.Next(0, 6);//被选染色体中的变异基因位
Console.WriteLine("变异的位置:第" + row + "条染色体,第" + col + "位基因位");
//0变成1,1变成0
if (chromosomes[row].bits[col] == 0)
{
chromosomes[row].bits[col] = 1;
}
else
{
chromosomes[row].bits[col] = 0;
}
chromosomes[row].fitValue = GetFitValue(DeCode(chromosomes[row].bits));
}
}
/// <summary>
/// 重新计算fit值
/// </summary>
private static void UpdateFitValue()
{
for (int i = 0; i < chromosomes.Count; i++)
{
chromosomes[i].fitValue = GetFitValue(DeCode(chromosomes[i].bits));
}
}
/// <summary>
/// 主函数入口
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Console.WriteLine("遗传算法");
Console.WriteLine("下面举例来说明遗传算法用以求函数最大值函数为y = -x*x+ 5的最大值,-31<=x<=31");
// f(x)=-x2+ 5
// 迭代次数;
int totalTime = 200;
Console.WriteLine("迭代次数为: " + totalTime);
//初始化;
Console.WriteLine("初始化: ");
Init();
// 输出初始化数据;
Print();
for (int i = 0; i < totalTime; i++)
{
Console.WriteLine("当前迭代次数: " + i);
重新计算fit值;;
//UpdateFitValue();
// 挑选染色体;
Console.WriteLine("挑选:");
switch (chooseType)
{
case ChooseType.Bubble:
// 排序;
Console.WriteLine("排序:");
ChooseChromosome();
break;
default:
//轮盘赌;
Console.WriteLine("轮盘赌:");
UpdateNext();
break;
}
Print(true);
//交叉得到新个体;
Console.WriteLine("交叉:");
CrossOperate();
Print();
//变异操作;
Console.WriteLine("变异:");
VariationOperate();
Print();
}
int maxfit = chromosomes[0].fitValue;
for (int i = 1; i < chromosomes.Count; i++)
{
if (chromosomes[i].fitValue > maxfit)
{
maxfit = chromosomes[i].fitValue;
}
}
Console.WriteLine("最大值为: " + maxfit);
Console.ReadLine();
}
}