# Using genetic algorithm for intelligent course scheduling, I believe teachers will like it very much

Time：2022-5-11

Summary:Genetic algorithm is an AI model that simulates biological evolution based on natural selection process. It can search the optimal solution generation by generation in the simulated biological evolution process. This paper uses genetic algorithm to realize a simple program to schedule the course.

According to the definition of Baidu Encyclopedia, genetic algorithm is an AI model that simulates biological evolution based on natural selection process. It can search the optimal solution generation by generation in the simulated biological evolution process. Genetic algorithm can not solve the problem directly, but needs the help of coding rules to abstract the core elements of the problem as genes on the chromosome, and iteratively select excellent genes for reproduction through the process of gene crossover and mutation to generate the next generation until the optimal solution or satisfactory optimal solution is obtained. At present, genetic algorithm is widely used in operations research, machine learning, artificial intelligence and other fields.

## 1. Process diagram of genetic algorithm

The core task of genetic algorithm is to give the chromosome expression rules of the solution through the coding system. Firstly, a certain number of populations need to be initialized randomly, and the population is composed of a certain number of individuals. Each individual is actually a chromosome, and fitness can be calculated by rules. After the emergence of the first generation population, according to the evolutionary principle of survival of the fittest, generations evolve to produce excellent offspring.

In the evolution process of each generation, individuals are selected according to their fitness, and new populations are generated by crossover and mutation with the help of genetic operators of natural genetics. After decoding, the optimal individual in the last generation population can be used as the approximate optimal solution of the problem. The exit condition is generally to reach the maximum number of iterations, such as 10000 times. In addition, it is to go if the fitness is satisfied, such as 0.99. The basic flow diagram is as follows:

## 2. Curriculum requirements

The actual curriculum arrangement involves a large number of teachers, classes, classrooms, courses and other elements, so it is very complex. With the help of genetic algorithm, the optimal solution may not be obtained, but only the local optimal solution. However, using genetic algorithm to assist curriculum arrangement is still a very good means. Generally speaking, in the process of curriculum arrangement, several restrictions must be met, otherwise, the given curriculum arrangement is invalid. The specific instructions are as follows:

1. At the same time, only one course can be offered in a classroom;
2. There is a limit on the number of seats in a classroom, and the total number of students in class cannot exceed the number of seats in the classroom;
3. At the same time, students in the same teacher or class can only participate in one course, not multiple courses;
4. Classrooms are divided into multimedia classrooms and ordinary classrooms. Some courses need multimedia classrooms. Therefore, the classroom configuration must meet the course requirements;

If the above four restrictions are met, the given curriculum arrangement is effective, but please note that it is not necessarily optimal. It does not consider the optimization conditions. For example, if the same teacher follows multiple courses in one day, it is obviously a little overloaded, or the same course is opened multiple times in a row on the same day, which is a little unbearable for teachers and students.

## 3 element data structure in curriculum arrangement

As mentioned earlier, the course arrangement process involves elements such as teachers, classes (student groups), classrooms and courses. The data structure description of each element is given below:

Course:The implementation class name of the course object is course, which contains two fields: course ID and course name.
classroom:The implementation class name of the classroom object is room, which includes four fields: classroom ID, classroom name, number of seats and whether it is a multimedia classroom.
teacher:The implementation class of the teacher object is called Professor, which contains three fields: teacher ID, teacher name and all courses to be taught in the classroom.
Class:The implementation class of the course class object is called courseclass, which includes six fields: the course instructor, the course taught, the class in class, the number of seats required (the sum of the number of classes), whether multimedia classroom is required and the class duration. This class also provides the method groupsovlap (courseclass C) to judge whether there is class overlap between itself and parameter C. similarly, the method professoroverlaps (courseclass C) can judge whether there is teacher overlap between itself and parameter C.
Class:The implementation class name of the class object is studentgroup, which contains four fields: class ID, class name, class number and all courses that the class needs to attend.
Chromosome expression(chromosome representation): in order to apply genetic algorithm, we need to focus on how to use gene sequence to represent the solution of the problem. Generally speaking, gene sequence is a long series of ordered sequences. Here, multidimensional curriculum elements can be compressed into a one-dimensional array through dimension reduction, and the length of the array (hereinafter referred to as slot slots) is:

Class days a weekClass hours per dayNumber of classrooms

For example, the number of class days in a week is assumed to be 5, which means that the daily class duration is 12 hours from Monday to Friday. For example, the class starts at 8:00 in the morning and ends at 20:00 in the evening. For simplicity, the number of classrooms is assumed to be 2, so the total array length is 5 12 2 = 120, each element in this one-dimensional array can place course classes, and different course class combinations represent different course scheduling schemes. The course scheduling scheme can be represented by the following schematic diagram:

Note: the above slot represents an hour unit, and can also represent the location index of the course. It can point to the courseclass instance of the specific course class, indicating that the slot has a corresponding course arrangement.

## 4 fitness

Based on the above chromosome expression, we need to calculate the fitness of an individual. The calculation method is as follows:

1. Traverse the class information of each course in the one-dimensional array representing chromosome performance. If there is no overlap of multiple courses in the classroom at the same time, increase the fitness score.
2. Traverse the class information of each course in the one-dimensional array representing chromosome performance. If the multimedia requirements of the course match the classroom, then increase the fitness score.
3. Traverse the class information of each course in the one-dimensional array representing chromosome performance. If the total number of classes participating in the course is less than or equal to the number of seats in the classroom, increase the fitness score.
4. Traverse the class information of each course in the one-dimensional array representing chromosome performance. If the teacher will not teach in more than one classroom at the same time, the fitness score will be increased.
5. Traverse the class information of each course in the one-dimensional array representing chromosome performance. If the class will not study in multiple courses at the same time, increase the fitness score.

Whether the above five indicators that increase the fitness score meet or not can be expressed through additional data structures, that is, an array of inspection rules with indexes from 0 to 4, a total of five values. Overlapping courses are indicated by red R, non overlapping courses are indicated by green R. Whether there are enough seats in the classroom. If not, it is indicated by red S, otherwise it is indicated by green s. Whether the classroom matches the multimedia requirements of the course. If not, it is indicated by red L, otherwise it is indicated by green L. Whether the teachers in the course class have overlap. The overlap is indicated by red P, otherwise it is indicated by green P. Whether the classes in the course class overlap. The overlap is indicated by red g, otherwise it is indicated by green G. The fitness value of an individual is a float type value, which is equal to:

score/ ( number_of_classes * 5)

The range is 0 to 1. For the course scheduling scenario, the higher the fitness score, the better the solution. Therefore, the individual selection in the process of evolution should choose the individual with fitness score.

## 5 genetic algorithm simulation

For the course scheduling scenario, the higher the fitness score, the better the solution. Therefore, the individual selection in the process of evolution should choose the individual with fitness score. The following is the core code fragment of the evolution process (selection, crossover and mutation) simulated by the algorithm. Examples are as follows:

``````List<Schedule> offspring = new List<Schedule>();
offspring.resize(_replaceByGeneration);
for (int j = 0; j < _replaceByGeneration; j++)
{
//Random selection
Schedule p1 = _chromosomes[RandomNumbers.NextNumber() % _chromosomes.Count];
Schedule p2 = _chromosomes[RandomNumbers.NextNumber() % _chromosomes.Count];
//Cross
offspring[j] = p1.Crossover(p2);
//Variation
offspring[j].Mutation();
}``````

As can be seen from the above code, offspring is based on parameters_ Replacebygeneration to determine the size of the individual to evolve. For each evolutionary offspring, first select two parents P1 and P2 by random method, first through P1 Crossover (P2) obtains the offspring after the crossover operation, and then mutates them offspring [J] Mutation()。 The core code of cross operation is as follows:

``````public Schedule Crossover(Schedule parent2)
{
//Determine whether cross operation is required according to probability
if (RandomNumbers.NextNumber() % 100 > _crossoverProbability)
//Direct return
return new Schedule(this, false);
//Copy to generate a new chrome object
Schedule n = new Schedule(this, true);
int size = (int)_classes.Count;
//Intersection array initialization
List<bool> cp = new List<bool>();
for (int k = 0; k < size; k++)
{
}
//Randomly determine the intersection location
for (int i = _numberOfCrossoverPoints; i > 0; i--)
{
while (true)
{
int p = RandomNumbers.NextNumber() % size;
if (!cp[p])
{
cp[p] = true;
break;
}
}
}
Dictionary<CourseClass, int>.Enumerator it1 = _classes.GetEnumerator();
Dictionary<CourseClass, int>.Enumerator it2 = parent2._classes.GetEnumerator();
//Alternately cross produce new individuals with parent individual combinations
bool first = RandomNumbers.NextNumber() % 2 == 0;
for (int i = 0; i < size; i++)
{
it1.MoveNext();
it2.MoveNext();
if (first)
{
for (int j = it1.Current.Key.GetDuration() - 1; j >= 0; j--)
}
else
{
for (int j = it2.Current.Key.GetDuration() - 1; j >= 0; j--)
}
//Update courses alternately at intersections
if (cp[i])
first = !first;
}
//Calculate fitness
n.CalculateFitness();
//Return better offspring
return n;
}``````

It can be seen from the above code that_ Crossover probability refers to the probability of a crossover. It is not necessary to perform specific crossover operations every time the crossover operation is called. When the number randomly generated is greater than the set probability, the specific crossover operation can be carried out. The location of intersections is also generated randomly, and the number of intersections is determined by parameters_ Numberofcrossover points is given. The essence of cross operation is to randomly combine and exchange the course sets pointed to in the two parent classes, that is, exchange the course information and the index position of the course. The mutation process is relatively simple, that is, for individuals who need to implement mutation operation, when the mutation probability is met, randomly select a course and move it to another randomly selected slot (slots). The core code of variation process is as follows:

``````public void Mutation()
{
//Determine whether mutation is required according to probability
if (RandomNumbers.NextNumber() % 100 > _mutationProbability)
return;
int numberOfClasses = (int)_classes.Count;
int size = (int)_slots.Count;
//Random decision mutation
for (int i = _mutationSize; i > 0; i--)
{
int count = _classes.Count;
int mpos = RandomNumbers.NextNumber() % numberOfClasses;
int pos1 = 0;
Dictionary<CourseClass, int>.Enumerator it = _classes.GetEnumerator();
if (mpos == 0)
{
it.MoveNext();
}
for (; mpos > 0; it.MoveNext(), mpos--)
;
pos1 = it.Current.Value;
CourseClass cc1 = it.Current.Key;
//Randomly determine the index position of the course
int nr = Configuration.GetInstance().GetNumberOfRooms();
int dur = cc1.GetDuration();
int day = RandomNumbers.NextNumber() % DefineConstantsSchedule.DAYS_NUM;
int room = RandomNumbers.NextNumber() % nr;
int time = RandomNumbers.NextNumber() % (DefineConstantsSchedule.DAY_HOURS + 1 - dur);
int pos2 = day * nr * DefineConstantsSchedule.DAY_HOURS + room * DefineConstantsSchedule.DAY_HOURS + time;
for (int k = dur - 1; k >= 0; k--)
{
//Remove unnecessary courses
LinkedList<CourseClass> cl = _slots[pos1 + k];
for (LinkedList<CourseClass>.Enumerator it3 = cl.GetEnumerator(); it3.MoveNext(); )
{
if (it3.Current == cc1)
{
cl.Remove(it3.Current);
break;
}
}
//Move course to new slot location
}
//Update course location
_classes[cc1] = pos2;
}
CalculateFitness();
}``````

For course scheduling, we need to provide some basic data, such as teacher resources, classes, courses, classrooms, etc. The resource data template is given below:

``````#prof
id = 1
Name = Miss Li
#end

#prof
id = 2
Name = teacher Zhang
#end

#prof
id = 3
Name = Mr. Wang
#end

...

#course
id = 1
Name = web programming
#end

#course
id = 4
Name = E-commerce
#end

...

#course
id = 8
Name = database principle
#end

#room
name = C101
lab = false
size = 80
#end

#room
name = C102
lab = true
size = 90
#end
#group
id = 1
Name = e-commerce class 1
size = 22
#end

...

#group
id = 4
Name = accounting class 2
size = 27
#end

#class
professor = 1
course = 1
duration = 2
group = 1
group = 2
#end
...

#class
professor = 12
course = 8
duration = 2
group = 3
group = 4
#end``````

The individual chromosome phenotype in the initialization population is given below. The specific code is as follows. The population size can be given by parameters. Different individuals can be generated by calling makenewfromprototype() in a loop and added to the primary population. The core code of makenewfromprototype method is as follows:

``````public Schedule MakeNewFromPrototype()
{
//Number of slots
int size = (int)_slots.Count;
//Generate a new individual chromosome
Schedule newChromosome = new Schedule(this, true);
//Randomly obtain courseclass information
for (LinkedList<CourseClass>.Enumerator it = c.GetEnumerator(); it.MoveNext(); )
{
//Randomly obtain the course location
int nr = Configuration.GetInstance().GetNumberOfRooms();
int dur = (it.Current).GetDuration();
int day = RandomNumbers.NextNumber() % DefineConstantsSchedule.DAYS_NUM;
int room = RandomNumbers.NextNumber() % nr;
int time = RandomNumbers.NextNumber() % (DefineConstantsSchedule.DAY_HOURS + 1 - dur);
int pos = day * nr * DefineConstantsSchedule.DAY_HOURS + room * DefineConstantsSchedule.DAY_HOURS + time;
//Place the courseclass information on the random slot
for (int i = dur - 1; i >= 0; i--)
}
//Calculate fitness
newChromosome.CalculateFitness();
return newChromosome;
}``````

On the UI, c# GDI + is used for drawing. Examples are as follows:

``````protected void paint(PaintEventArgs e)
{
string baseFile = AppDomain.CurrentDomain.BaseDirectory;
string filename = baseFile + "GaSchedule.cfg";
Configuration.GetInstance().ParseFile(ref filename);
Graphics gac = e.Graphics;
Rectangle clientRect = e.ClipRectangle;
try
{
this.Invoke((MethodInvoker)delegate
{
sx = -GetScrollPos(this.Handle, SB_HORZ);
sy = -GetScrollPos(this.Handle, SB_VERT);
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
sx = 0;
sy = 0;
}
Color newColor = System.Drawing.Color.FromArgb(49, 147, 120);
Color bzColor = System.Drawing.Color.FromArgb(49, 147, 120);
Color errorColor = System.Drawing.Color.FromArgb(206, 0, 0);
Brush bgBrush = System.Drawing.Brushes.White;
gac.FillRectangle(bgBrush, clientRect);
Font tableHeadersFont = new Font("Microsoft YaHei", 12);
Font tableTextFont = new Font("Microsoft YaHei", 10);
Font roomDescFont = new Font("Microsoft YaHei", 10);
Font criteriaFont = new Font("Microsoft YaHei", 12);
SolidBrush classBrush = new SolidBrush(Color.DarkOrchid);
classBrush.Color = Color.FromArgb(255, 255, 245);
SolidBrush overlapBrush = new SolidBrush(Color.DarkOrchid);
overlapBrush.Color = Color.FromArgb(255, 0, 0);
HatchBrush myHatchBrush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.Red,Color.Transparent);
int nr = Configuration.GetInstance().GetNumberOfRooms();
for (int k = 0; k < nr; k++)
{
for (int i = 0; i < ROOM_COLUMN_NUMBER; i++)
{
for (int j = 0; j < ROOM_ROW_NUMBER; j++)
{
int l = k % 2;
int m = k / 2;
if (i == 0 && j == 0)
{
Rectangle rect2 = new Rectangle(
sx+ROOM_MARGIN_WIDTH + ROOM_TABLE_WIDTH * l,
sy+ROOM_MARGIN_HEIGHT,
ROOM_CELL_WIDTH,
ROOM_CELL_HEIGHT);
gac.DrawRectangle(Pens.Black, rect2);
Rectangle rect3 = new Rectangle(rect2.X, rect2.Y + 8, rect2.Width, rect2.Height - 16);
string str;
str = string. Format ("Classroom: {0}", configuration. Getinstance() GetRoomById(k). GetName());
TextRenderer.DrawText(gac, str, roomDescFont, rect3, Color.FromArgb(0, 0, 0),
TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
}
if (i == 0 && j > 0)
{
string str = string.Format("{0} - {1}", 8 + j - 1, 8 + j);
Rectangle rect3 = new Rectangle(
sx + ROOM_MARGIN_WIDTH + ROOM_TABLE_WIDTH * l ,
sy + ROOM_MARGIN_HEIGHT + ROOM_CELL_HEIGHT * (j),
ROOM_CELL_WIDTH,
ROOM_CELL_HEIGHT);
TextRenderer.DrawText(gac, str, tableHeadersFont, rect3, Color.FromArgb(0, 0, 0),
TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
gac.DrawRectangle(Pens.Black, rect3);
}
if (j == 0 && i > 0)
{

String [] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
Rectangle rect3 = new Rectangle(
sx + ROOM_MARGIN_WIDTH + ROOM_TABLE_WIDTH * l + ROOM_CELL_WIDTH * (i),
sy + ROOM_MARGIN_HEIGHT,
ROOM_CELL_WIDTH,
ROOM_CELL_HEIGHT);

TextRenderer.DrawText(gac, days[i - 1], tableHeadersFont, rect3, Color.FromArgb(0, 0, 0),
TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
gac.DrawRectangle(Pens.Black, rect3);
}

}
}
}
if (_schedule != null)
{
Dictionary<CourseClass, int> classes = _schedule.GetClasses();
int ci = 0;
for (Dictionary<CourseClass, int>.Enumerator it = classes.GetEnumerator(); it.MoveNext(); ci += 5)
{
CourseClass c = it.Current.Key;
int p = it.Current.Value;
int t = p % (nr * DAY_HOURS);
int d = p / (nr * DAY_HOURS) + 1;
int r = t / DAY_HOURS;
t = t % DAY_HOURS + 1;
int l = r % 2;
int m = r / 2;
Rectangle rect = new Rectangle(
sx + ROOM_TABLE_WIDTH * l + ROOM_MARGIN_WIDTH + d * ROOM_CELL_WIDTH ,
sy + ROOM_TABLE_HEIGHT * m + ROOM_MARGIN_HEIGHT + t * ROOM_CELL_HEIGHT ,
ROOM_CELL_WIDTH ,
c.GetDuration() * ROOM_CELL_HEIGHT);
string str = string.Format("{0}\n({1})\n", c.GetCourse().GetName(), c.GetProfessor().GetName());
for (LinkedList<StudentsGroup>.Enumerator it2 = c.GetGroups().GetEnumerator(); it2.MoveNext(); )
{
str += (it2.Current).GetName();
str += "/";
}
str=str.TrimEnd('/');
if (c.IsLabRequired())
STR + = "[multimedia]";
gac.FillRectangle(classBrush, rect);
gac.DrawRectangle(Pens.Black, rect);
TextRenderer.DrawText(gac, str, tableTextFont, rect, Color.FromArgb(0, 0, 0), TextFormatFlags.WordBreak);
if (!_schedule.GetCriteria()[ci + 0])
{
bzColor = errorColor;
TextRenderer.DrawText(gac, "R", tableTextFont, new Point(rect.Left, rect.Bottom - 20), bzColor);
gac.FillRectangle(myHatchBrush, rect);
}
else
{
TextRenderer.DrawText(gac, "R", tableTextFont, new Point(rect.Left, rect.Bottom - 20), bzColor);
}
bzColor = newColor;
if (!_schedule.GetCriteria()[ci + 1])
{
bzColor = errorColor;
TextRenderer.DrawText(gac, "S", tableTextFont, new Point(rect.Left + 10, rect.Bottom - 20), bzColor);
}
else
{
TextRenderer.DrawText(gac, "S", tableTextFont, new Point(rect.Left + 10, rect.Bottom - 20), bzColor);
}
bzColor = newColor;
if (!_schedule.GetCriteria()[ci + 2])
{
bzColor = errorColor;
TextRenderer.DrawText(gac, "L", tableTextFont, new Point(rect.Left + 20, rect.Bottom -20), bzColor);
}
else
{
TextRenderer.DrawText(gac, "L", tableTextFont, new Point(rect.Left + 20, rect.Bottom - 20), bzColor);
}
bzColor = newColor;
if (!_schedule.GetCriteria()[ci + 3])
{
bzColor = errorColor;
TextRenderer.DrawText(gac, "P", tableTextFont, new Point(rect.Left + 30, rect.Bottom -20), bzColor);
}
else
{
TextRenderer.DrawText(gac, "P", tableTextFont, new Point(rect.Left + 30, rect.Bottom -20), bzColor);
}
bzColor = newColor;
if (!_schedule.GetCriteria()[ci + 4])
{
bzColor = errorColor;
TextRenderer.DrawText(gac, "G", tableTextFont, new Point(rect.Left + 40, rect.Bottom - 20), bzColor);
}
else
{
TextRenderer.DrawText(gac, "G", tableTextFont, new Point(rect.Left + 40, rect.Bottom - 20), bzColor);
}
}
}
}``````

After execution, after multiple iterations of genetic algorithm, the UI interface displayed is as follows:

In the intermediate link, the iterative process in which the feasible solution cannot be obtained may display the following interface:

Since there are two courses on [8-10] and [9-11] on Monday, they occupy the same classroom at the same timeTherefore, a red twill is displayed on the UI, and R (room) is red. So far, we have basically realized a genetic algorithm implemented in c# language to carry out simple course scheduling operation. Finally, this blog referencehttps://www.codeproject.com/a…A penny.

Click follow to learn about Huawei’s new cloud technology for the first time~

## Log operation class test

/// /// Log operation class /// public class LogWriteqw { #region constant /// /// General log lock /// private static object lockLog = new object(); /// /// Status log lock /// private static object lockState = new object(); /// /// Exception status lock /// private static object lockError = new object(); #endregion   #region operations […]