Click here to Skip to main content
11,928,985 members (61,719 online)
Click here to Skip to main content
Add your own
alternative version


227 bookmarked

Making a Class Schedule Using a Genetic Algorithm

, 22 Jan 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
How to make a class schedule using a genetic algorithm.



Making a class schedule is one of those NP hard problems. The problem can be solved using a heuristic search algorithm to find the optimal solution, but it only works for simple cases. For more complex inputs and requirements, finding a considerably good solution can take a while, or it may be impossible. This is where genetic algorithms come in to the game. In this article, I assume that you are familiar with the basic concepts of genetic algorithms, and I won't describe them in detail because it has been done so many times before.


When you make a class schedule, you must take into consideration many requirements (number of professors, students, classes and classrooms, size of classroom, laboratory equipment in classroom, and many others). These requirements can be divided into several groups by their importance. Hard requirements (if you break one of these, then the schedule is infeasible):

  • A class can be placed only in a spare classroom.
  • No professor or student group can have more then one class at a time.
  • A classroom must have enough seats to accommodate all students.
  • To place a class in a classroom, the classroom must have laboratory equipment (computers, in our case) if the class requires it.

Some soft requirements (can be broken, but the schedule is still feasible):

  • Preferred time of class by professors.
  • Preferred classroom by professors.
  • Distribution (in time or space) of classes for student groups or professors.

Hard and soft requirements, of course, depend on the situation. In this example, only hard requirements are implemented. Let's start by explaining the objects which makes a class schedule.

Objects of Class Schedule


The Professor class has an ID and the name of the professor. It also contains a list of classes that a professor teaches.

Students Group

The StudentsGroup class has an ID and the name of the student group, as well as the number of students (size of group). It also contains a list of classes that the group attends.


The Room class has an ID and the name of the classroom, as well as the number of seats and information about equipment (computers). If the classroom has computers, it is expected that there is a computer for each seat. IDs are generated internally and automatically.


The Course class has an ID and the name of the course.


CourseClass holds a reference to the course to which the class belongs, a reference to the professor who teaches, and a list of student groups that attend the class. It also stores how many seats (sum of student groups' sizes) are needed in the classroom, if the class requires computers in the classroom, and the duration of the class (in hours).


The first thing we should consider when we deal with a genetic algorithm is how to represent our solution in such a way that it is feasible for genetic operations such as crossover and mutation. Also, we should know how to specify how good our solution is. In other words, we should be able to calculate the fitness value of our solution.


How can we represent the chromosome for a class schedule? Well, we need a slot (time-space slot) for each hour (we assume that time is in one hour granules), for every room, every day. Also, we assume that classes cannot begin before 9am, and should finish before or at 9pm (12 hours total), and working days are from Monday to Friday (5 days total). We can use an std::vector with a size 12*5*number_of_rooms. The slot should be an std::list because during the execution of our algorithm, we allow multiple classes during the same time-space slot. There is an additional hash map which is used to obtain the first time-space slot at which a class begins (its position in vector) from the address of the class' object. Each hour of a class has a separate entry in the vector, but there is only one entry per class in the hash map. For instance, if a class starts at 1pm and lasts for three hours, it has entries in the 1pm, 2pm, and 3pm slots.

Class Schedule Chromosome Representation

Figure 1 - Chromosome Representation

Chromosomes are represented by the Schedule class, and it stores the representation of a class schedule in these two attributes:

// Time-space slots, one entry represent one hour in one classroom
vector<list<CourseClass*>> _slots;

// Class table for chromosome
// Used to determine first time-space slot used by class
hash_map<CourseClass*, int> _classes;

Additionally, the chromosome should store its fitness value and the parameters which are used by genetic operations.

The fitness value is stored here:

// Fitness value of chromosome
float _fitness;

// Flags of class requiroments satisfaction
vector<bool> _criteria;

Chromosome parameters:

// Number of crossover points of parent's class tables
int _numberOfCrossoverPoints;

// Number of classes that is moved randomly by single mutation operation
int _mutationSize;

// Probability that crossover will occure
int _crossoverProbability;

// Probability that mutation will occure
int _mutationProbability;


Now we need to assign a fitness value to the chromosome. As I previously said, only hard requirements are used to calculate the fitness of a class schedule. This is how we do it:

  • Each class can have 0 to 5 points.
  • If a class uses a spare classroom, we increment its score.
  • If a class requires computers and it is located in the classroom with them, or it doesn't require them, we increment the score of the class.
  • If a class is located in a classroom with enough available seats, guess what, we increment its score.
  • If a professor has no other classes at the time, we increment the class's score once again.
  • The last thing that we check is if any of the student groups that attend the class has any other class at the same time, and if they don't, we increment the score of the class.
  • If a class breaks a rule at any time-space slot that it occupies, its score is not incremented for that rule.
  • The total score of a class schedule is the sum of points of all classes.
  • The fitness value is calculated as schedule_score/maximum_score, and maximum_score is number_of_classes*5.

The fitness values are represented by single-precision floating point numbers (float) in the range 0 to 1.


A crossover operation combines data in the hash maps of two parents, and then it creates a vector of slots according to the content of the new hash map. A crossover 'splits' hash maps of both parents in parts of random size. The number of parts is defined by the number of crossover points (plus one) in the chromosome's parameters. Then, it alternately copies parts form parents to the new chromosome, and forms a new vector of slots.

Class Schedule Crossover Operation

Figure 2 - Crossover operation
// Performes crossover operation using to chromosomes
// and returns pointer to offspring
Schedule* Crossover(const Schedule& parent2) const;


A mutation operation is very simple. It just takes a class randomly and moves it to another randomly chosen slot. The nmber of classes which are going to be moved in a single operation is defined by the mutation size in the chromosome's parameters.

// Performs mutation on chromosome
void Mutation();


The genetic algorithm is fairly simple. For each generation, it performs two basic operations:

  1. Randomly selects N pairs of parents from the current population and produces N new chromosomes by performing a crossover operation on the pair of parents.
  2. Randomly selects N chromosomes from the current population and replaces them with new ones. The algorithm doesn't select chromosomes for replacement if it is among the best chromosomes in the population.

And, these two operations are repeated until the best chromosome reaches a fitness value equal to 1 (meaning that all classes in the schedule meet the requirement). As mentioned before, the genetic algorithm keeps track of the M best chromosomes in the population, and guarantees that they are not going to be replaced while they are among the best chromosomes.

// Genetic algorithm
class Algorithm


    // Population of chromosomes
    vector<Schedule*> _chromosomes;

    // Inidicates wheahter chromosome belongs to
    // best chromosome group
    vector<bool> _bestFlags;

    // Indices of best chromosomes
    vector<int> _bestChromosomes;

    // Number of best chromosomes currently saved in
    // best chromosome group
    int _currentBestSize;

    // Number of chromosomes which are replaced in
    // each generation by offspring
    int _replaceByGeneration;

    // Pointer to algorithm observer
    ScheduleObserver* _observer;

    // Prototype of chromosomes in population
    Schedule* _prototype;

    // Current generation
    int _currentGeneration;

    // State of execution of algorithm
    AlgorithmState _state;

    // Synchronization of algorithm's state
    CCriticalSection _stateSect;

    // Pointer to global instance of algorithm
    static Algorithm* _instance;

    // Synchronization of creation and destruction
    // of global instance
    static CCriticalSection _instanceSect;


    // Returns reference to global instance of algorithm
    static Algorithm& GetInstance();

    // Frees memory used by gloval instance
    static void FreeInstance();

    // Initializes genetic algorithm
    Algorithm(int numberOfChromosomes,
        int replaceByGeneration,
        int trackBest,
        Schedule* prototype,
        ScheduleObserver* observer);

    // Frees used resources

    // Starts and executes algorithm
    void Start();

    // Stops execution of algoruthm
    void Stop();

    // Returns pointer to best chromosomes in population
    Schedule* GetBestChromosome() const;

    // Returns current generation
    inline int GetCurrentGeneration() const { return _currentGeneration; }

    // Returns pointe to algorithm's observer
    inline ScheduleObserver* GetObserver() const { return _observer; }


    // Tries to add chromosomes in best chromosome group
    void AddToBest(int chromosomeIndex);

    // Returns TRUE if chromosome belongs to best chromosome group
    bool IsInBest(int chromosomeIndex);

    // Clears best chromosome group
    void ClearBest();



The ScheduleObserver class handles the events that are triggered by the genetic algorithm. This class sends messages to the view window of the application. Also, you can block the caller's thread until the execution of the algorithm is not finished or stopped, by calling the WaitEvent() method.

// Handles event that is raised
// when algorithm finds new best chromosome
void NewBestChromosome(const Schedule& newChromosome);

// Handles event that is raised when state
// of execution of algorithm is changed
void EvolutionStateChanged(AlgorithmState newState);

// Block caller's thread until algorithm finishes execution
inline void WaitEvent() //...

If you plan to change the NewBestChromosome method, keep in mind that if you want to keep the best chromosome to display it, you must make a hard copy (by using the MakeCopy method of the Schedule class), because the algorithm can delete that chromosome in the next generation.


Configuration File

Types of objects:

  1. professor (#prof tag) - describes a professor.
  2. course (#course tag) - describes a course.
  3. room (#room tag) - describes a room.
  4. group (#group tag) - describes a students group.
  5. course class (#class tag) - describes a class, and binds the professor, course, and students group.

Each object begins with its tag and finishes with the #end tag, all tags must be in separate lines. In the body of an object, each line contains only one key and value pair (attribute) separated by an = character. Each attribute should be specified just one time, except for the group attribute in the #group object which can have multiple group attributes. Tag and key names are case sensitive. Here is a list of the objects' attributes:

  1. #prof
    • id (number, required) - ID of the professor.
    • name (string, required) - name of the professor.
  2. #course
    • id (number, required) - ID of the course.
    • name (string, required) - name of the course.
  3. #room
    • name (string, required) - name of the room.
    • size (number, required) - number of seats in the room.
    • lab (boolean, optional) - indicates if the room is a lab (has computers); if not specified, the default value is false.
  4. #group
    • id (number, required) - ID of the students group.
    • name (string, required) - name of the students group.
    • size (number, required) - number of students in the group.
  5. #class
    • professor (number, required) - ID of a professor; binds a professor to a class.
    • course (number, required) - ID of a course; binds a course to a class.
    • group (number, required) - ID of a students group; binds the students group to a class; each class can be bound to multiple students groups.
    • duration (number, optional) - duration of class (in hours); if not specified, the default value is 1.
    • lab (boolean, optional) - if the class requires computers in a room; if not specified, the default value is false.

Note that the professor, students group, and course objects must be defined before they are bound to a course class object.

Example of a Configuration File

    id = 1
    name = John Smith

    id = 1
    name = Introduction to Programming

    name = R1
    lab = true
    size = 24

    id = 1
    name = 1O1
    size = 19

    professor = 1
    course = 1
    duration = 2
    group = 1
    group = 2

    professor = 1
    course = 1
    duration = 3
    group = 1
    lab = true

    professor = 1
    course = 1
    duration = 3
    group = 2
    lab = true

Parsing a Configuration

Parsing of a configuration file is done by the Configuration class. The ParseFile method opens and parses a configuration file. It searches for object tags and calls the appropriate method for a parsing object. The ParseFile method also clears a previously parsed object.

    void ParseFile(char* fileName);


    Professor* ParseProfessor(ifstream& file);
    StudentsGroup* ParseStudentsGroup(ifstream& file);
    Course* ParseCourse(ifstream& file);
    Room* ParseRoom(ifstream& file);
    CourseClass* ParseCourseClass(ifstream& file);

To parse a file:

Configuration::GetInstance().ParseFile( "GaSchedule.cfg" );

Parsed objects are kept in a hash map except for course classes, so they can be accessed easily and fast.


    hash_map<int, Professor*> _professors;
    hash_map<int, StudentsGroup*> _studentGroups;
    hash_map<int, Course*> _courses;
    hash_map<int, Room*> _rooms;

    list<CourseClass*> _courseClasses;

The Configuration class also contains the methods for retrieving the parsed information and objects.

    inline Professor* GetProfessorById(int id) //...
    inline int GetNumberOfProfessors() const //...

    inline StudentsGroup* GetStudentsGroupById(int id) //...
    inline int GetNumberOfStudentGroups() const //...

    inline Course* GetCourseById(int id) //...
    inline int GetNumberOfCourses() const //...

    inline Room* GetRoomById(int id) //...
    inline int GetNumberOfRooms() const //...

    inline const list<CourseClass*>& GetCourseClasses() const //...
    inline int GetNumberOfCourseClasses() const //...

Additional Information

This article is written based on this text but with a different license.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Mladen Janković
Software Developer
Serbia Serbia
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionConfiguration file problem ! Help needed asap. Pin
Member 107032202-Apr-14 21:07
memberMember 107032202-Apr-14 21:07 
QuestionC# code Pin
Rostyslav Zhalivtsiv1-Apr-14 5:45
memberRostyslav Zhalivtsiv1-Apr-14 5:45 
QuestionRoom selection for courses Pin
saknet13-Mar-14 2:04
membersaknet13-Mar-14 2:04 
Questionplanned room selection of courses Pin
saknet13-Mar-14 2:02
membersaknet13-Mar-14 2:02 
Questionhelp! Pin
Member 1048661627-Jan-14 2:04
memberMember 1048661627-Jan-14 2:04 
AnswerRe: help! Pin
Member 1044615728-May-14 10:30
memberMember 1044615728-May-14 10:30 
QuestionGreat algorithm.. Understand the concept... But don't understand crossover. Pin
Mike Wazowski9-Dec-13 19:53
memberMike Wazowski9-Dec-13 19:53 
Questionayuda lo mas pronto posible Pin
Lourdes Aurora NiñoHuertas14-Oct-13 13:10
memberLourdes Aurora NiñoHuertas14-Oct-13 13:10 
QuestionC# code Pin
Member 1032946112-Oct-13 3:12
memberMember 1032946112-Oct-13 3:12 
AnswerRe: C# code Pin
Mladen Janković12-Oct-13 6:56
memberMladen Janković12-Oct-13 6:56 
GeneralRe: C# code Pin
Member 1044615722-Jun-14 21:02
memberMember 1044615722-Jun-14 21:02 
AnswerRe: C# code Pin
Member 769934916-Feb-14 4:26
memberMember 769934916-Feb-14 4:26 
QuestionMaking this in java, needing the algorithm/pseudocode. Anyone? Pin
Mike Wazowski25-Sep-13 20:35
memberMike Wazowski25-Sep-13 20:35 
QuestionAyuda para implementar en visual c# 2010 Pin
Member 102505514-Sep-13 19:20
memberMember 102505514-Sep-13 19:20 
Questionhelp me Pin
Member 1023566227-Aug-13 7:11
memberMember 1023566227-Aug-13 7:11 
Questionwhat type of method implemented,please answer the question Pin
mwashahi10-Aug-13 3:58
membermwashahi10-Aug-13 3:58 
Questionworking with even and odd week Pin
Jotache2129-Jul-13 19:05
memberJotache2129-Jul-13 19:05 
QuestionJava source code Pin
mandarmaheshwarjog27-Jul-13 21:42
membermandarmaheshwarjog27-Jul-13 21:42 
AnswerRe: Java source code Pin
mwashahi31-Jul-13 13:10
membermwashahi31-Jul-13 13:10 
GeneralRe: Java source code Pin
som083-Apr-15 2:41
membersom083-Apr-15 2:41 
GeneralRe: Java source code Pin
Member 1190539912-Aug-15 17:00
memberMember 1190539912-Aug-15 17:00 
QuestionC# implementation Pin
bhuvnesht2616-Jul-13 17:44
memberbhuvnesht2616-Jul-13 17:44 
Questionproblem in Configuration file and Fitness function Pin
mwashahi14-Jun-13 2:33
membermwashahi14-Jun-13 2:33 
QuestionRe: problem in Configuration file and Fitness function Pin
Member 107032202-Apr-14 4:58
memberMember 107032202-Apr-14 4:58 
QuestionC# and more dimentions Pin
Wierdbeard656-Jun-13 7:43
memberWierdbeard656-Jun-13 7:43 
AnswerRe: C# and more dimentions Pin
Mladen Janković6-Jun-13 13:36
memberMladen Janković6-Jun-13 13:36 
Questioncode Pin
lortcort4520-Mar-13 7:28
memberlortcort4520-Mar-13 7:28 
Questionhelp for code in java for Time table Pin
Titus Sid12-Feb-13 3:40
memberTitus Sid12-Feb-13 3:40 
AnswerRe: help for code in java for Time table Pin
Timbobhé Diallo7-Jun-14 7:34
memberTimbobhé Diallo7-Jun-14 7:34 
GeneralRe: help for code in java for Time table Pin
Member 1102505922-Sep-14 11:03
memberMember 1102505922-Sep-14 11:03 
GeneralMy vote of 5 Pin
huseyinyagli6-Feb-13 4:09
memberhuseyinyagli6-Feb-13 4:09 
QuestionC# Implimentation Pin
Pravin.bgholap1022-Jan-13 1:54
memberPravin.bgholap1022-Jan-13 1:54 
GeneralMy vote of 5 Pin
Fouriza15-Jul-12 4:42
memberFouriza15-Jul-12 4:42 
QuestionContact Pin
atsnyr26-Jun-12 5:20
memberatsnyr26-Jun-12 5:20 
GeneralMy vote of 5 Pin
nvntung14-Jun-12 23:40
membernvntung14-Jun-12 23:40 
Questionplz read this, New Idea Pin
Member 889805711-Jun-12 3:28
memberMember 889805711-Jun-12 3:28 
Questioncode c# Pin
elhamrohani21-May-12 7:51
memberelhamrohani21-May-12 7:51 
QuestionNeed ur help in changing constraints Pin
adeel anwar5-Apr-12 1:21
memberadeel anwar5-Apr-12 1:21 
QuestionMutation question Pin
mr.nothing4-Apr-12 10:28
membermr.nothing4-Apr-12 10:28 
AnswerRe: Mutation question Pin
Mladen Jankovic4-Apr-12 23:05
memberMladen Jankovic4-Apr-12 23:05 
GeneralMy vote of 5 Pin
manoj kumar choubey28-Mar-12 0:50
membermanoj kumar choubey28-Mar-12 0:50 
QuestionCompiling Problem Pin
cethint11-Mar-12 10:57
membercethint11-Mar-12 10:57 
SuggestionRe: Compiling Problem Pin
Corey W20-Mar-12 8:50
memberCorey W20-Mar-12 8:50 
GeneralRe: Compiling Problem Pin
cethint25-Mar-12 11:08
membercethint25-Mar-12 11:08 
GeneralRe: Compiling Problem Pin
Silver Rhy29-Nov-12 4:22
memberSilver Rhy29-Nov-12 4:22 
GeneralMy vote of 5 Pin
Yazılım Uzmanı Selcuk12-Jan-12 13:47
memberYazılım Uzmanı Selcuk12-Jan-12 13:47 
GeneralRe: My vote of 5 Pin
cethint12-Mar-12 6:16
membercethint12-Mar-12 6:16 
GeneralMy vote of 5 Pin
Behzadkh200610-Oct-11 10:36
memberBehzadkh200610-Oct-11 10:36 
QuestionMladen Jankovic pls help me Pin
makerhappy5-Sep-11 5:48
membermakerhappy5-Sep-11 5:48 
Questionparallelization Pin
Member 789818428-Jun-11 15:39
memberMember 789818428-Jun-11 15:39 
good day mladen,
can i use your code as basis for the sequential implementation and benchmark of my study?... and can i use part of your code to be implemented in parallel GA using CUDA... and can you help me if i hit a wall during my implementation.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.151126.1 | Last Updated 22 Jan 2008
Article Copyright 2008 by Mladen Janković
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid