C# 遗传算法 排课系统优化
本文将用C#语言来实现遗传算法对排课系统的优化,算法代码参考了洛荷大佬的Python实现基于遗传算法的排课优化,用C#实现后做了一个界面方便操作。
一、要求
- 导入学生(学号,姓名,性别),课程(课程号,课程时间,课容量),教师(教师工号,所教课程),教室(教室编号,教室容量)等基本信息;
- 用数据初步处理,根据数据表建立老师与学生班的对应关系矩阵;
- 用遗传算法对排课路径进行分析;
- 对不同项目进行约束(教室容量满足性约束,同一教师同一时段上课不可冲突性约束,同一学生同一时段上课不可冲突性约束,任意课时使用教室数不超过学校教室的总量约束等约束);
- 求出群体中最大的适应值及其个体;
- 设置罚值,淘汰不低质种群,求可行种群的目标函数值;
- 计算目标函数(输出课程权值,教学资源的充分利用,可见学生流动量最小,相邻授课间隔尽量均匀,同一课程尽量只用一个教室等)。
二、内容
编写软件,实现界面友好的系统设计,完成整个排课系统优化的过程。
要求:每个步骤中,要把所有功能均编写成模块调用形式,如:导入数据,表间建立联
系、约束条件选择,排课课表导出与显示。课表按不同班级用户导出,用户可以根据提示进行选择,进入相应算法调用实现计算。
三、分析流程图
四、具体步骤
1.导入数据并对数据进行初步处理;
2.设置基础参数:种群规模,突变的可能性,精英数目,执行次数。
3. 构造函数,初始化不同的种群(课程表的人数和教室数等);
4.通过随机方式产生多个求解问题的二进制染色体编码,选择适应度高的染色体。
5. 交叉操作:随机对两个对象交换不同位置的属性,返回列表。交叉操作采用分块小基因交叉算法,即每个班的课程单元只能在相同的班级进行交叉操作,而不能跨班(行)进行交叉。例如两个个体进行交叉时,只能个体1的1班行基因与个体2的1班行基因进行交换。这样的操作不会破坏班级对课程和课时的要求。
6.变异操作:随机对Schedule象中对的某个可改变属性在允许范围内进行随机加减,返回列表,变异的过程是针对每个染色体个体内部的,为保证每个班级的既定的课程课时所以同交叉相同,变异操作限制在每个班级的基因段中。
7.GA优化:进化,启动GA算法进行优化,返回最佳结果的索引和最佳冲突的分数。计算课表种群的冲突,返回最佳结果的索引,最佳冲突的分数,当被测试课表冲突为0的时候,这个课表就是个符合规定的课表当冲突为零时,按班级输出当前排课表。
五、理论基础
1、遗传算法的科学定义
遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
其主要特点是直接对结构对象进行操作,不存在求导和函数连续性的限定;具有内在的隐并行性和更好的全局寻优能力;采用概率化的寻优方法,不需要确定的规则就能自动获取和指导优化的搜索空间,自适应地调整搜索方向。
遗传算法以一种群体中的所有个体为对象,并利用随机化技术指导对一个被编码的参数空间进行高效搜索。其中,选择、交叉和变异构成了遗传算法的遗传操作;参数编码、初始群体的设定、适应度函数的设计、遗传操作设计、控制参数设定五个要素组成了遗传算法的核心内容。
2、遗传算法的执行过程
遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。
染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码。
初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。
六、代码实现
1、课程类
courseId代表课程号,classID代表班级号,teacherID代表教师号,这三个数据是从外部导入的,roomId代表教室号,weekDay代表星期,slot代表时间,这三个数据是随机生成的,通过遗传算法得到不冲突的结果。DeepClone()函数实现深度拷贝,RandomInit(int roomRange)生成随机的roomId,weekDay和slot。
[Serializable]
class Schedule : ICloneable
{
private int courseId; //课程号
private int classId; //班级号
private int teacherId; //教师号
private int roomId = 0; //教室
private int weekDay = 0; //星期
private int slot = 0; //时间
public int CourseId {
get => courseId; set => courseId = value; }
public int ClassId {
get => classId; set => classId = value; }
public int TeacherId {
get => teacherId; set => teacherId = value; }
public int RoomId {
get => roomId; set => roomId = value; }
public int WeekDay {
get => weekDay; set => weekDay = value; }
public int Slot {
get => slot; set => slot = value; }
//构造函数
public Schedule(int courseId, int classId, int teacherId) //课程表类包含的内容,包括课程号,班级号,教师ID
{
this.courseId = courseId;
this.classId = classId;
this.teacherId = teacherId;
}
#region 拷贝主体
/// <summary>
/// 深度拷贝
/// </summary>
public Schedule DeepClone()
{
using (Stream objectStream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(objectStream, this);
objectStream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(objectStream) as Schedule;
}
}
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
//随机匹配教室号和时间
public void RandomInit(int roomRange)
{
Random random = new Random();
this.RoomId = random.Next(1, roomRange + 1);
this.WeekDay = random.Next(1, 6);
this.Slot = random.Next(1, 6); //随机生成时间
}
public override string ToString()
{
return String.Format("课程号:{0}\n班级号:{1}\n教师号:{2}\n房间号:{3}",CourseId,ClassId,TeacherId,RoomId);
}
}
2、算法实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Course_scheduling_optimization
{
class GeneticOptimize
{
private int popsize; //种群规模
private double mutprob; //突变的可能性
private int elite; //精英数目
private int maxiter; //执行次数
private Random random = new Random(); //随机数,方便调用函数
//封装字段
public int Popsize {
get => popsize; set => popsize = value; }
public double Mutprob {
get => mutprob; set => mutprob = value; }
public int Elite {
get => elite; set => elite = value; }
public int Maxiter {
get => maxiter; set => maxiter = value; }
//默认构造函数
public GeneticOptimize()
{
this.popsize = 30;
this.mutprob = 0.3;
this.elite = 5;
this.maxiter = 100;
}
//构造函数
public GeneticOptimize(int popsize, double mutprob, int elite, int maxiter)
{
this.popsize = popsize;
this.mutprob = mutprob;
this.elite = elite;
this.maxiter = maxiter;
}
//随机初始化不同的种群
//schedules:List,课程表的人数
//roomRange:int,教室数
private List<List<Schedule>> InitPopulation(List<Schedule> schedules,int roomRange)
{
List<List<Schedule>> population = new List<List<Schedule