-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTimetableGA.java
203 lines (171 loc) · 7.9 KB
/
TimetableGA.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package chapter5;
import com.mysql.cj.protocol.Resultset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Don't be daunted by the number of classes in this chapter -- most of them are
* just simple containers for information, and only have a handful of properties
* with setters and getters.
*
* The real stuff happens in the GeneticAlgorithm class and the Timetable class.
*
* The Timetable class is what the genetic algorithm is expected to create a
* valid version of -- meaning, after all is said and done, a chromosome is read
* into a Timetable class, and the Timetable class creates a nicer, neater
* representation of the chromosome by turning it into a proper list of Classes
* with rooms and professors and whatnot.
*
* The Timetable class also understands the problem's Hard Constraints (ie, a
* professor can't be in two places simultaneously, or a room can't be used by
* two classes simultaneously), and so is used by the GeneticAlgorithm's
* calcFitness class as well.
*
* Finally, we overload the Timetable class by entrusting it with the "database
* information" generated here in initializeTimetable. Normally, that
* information about what professors are employed and which classrooms the
* university has would come from a database, but this isn't a book about
* databases so we hardcode it.
*
* @author bkanber
*
*/
public class TimetableGA {
public static void main(String[] args) {
// Get a Timetable object with all the available information.
Timetable timetable = initializeTimetable();
// Initialize GA
GeneticAlgorithm ga = new GeneticAlgorithm(100, 0.01, 0.9, 2, 5);
// Initialize population
Population population = ga.initPopulation(timetable);
// Evaluate population
ga.evalPopulation(population, timetable);
// Keep track of current generation
int generation = 1;
// Start evolution loop
while (ga.isTerminationConditionMet(generation, 1000) == false
&& ga.isTerminationConditionMet(population) == false) {
// Print fitness
System.out.println("G" + generation + " Best fitness: " + population.getFittest(0).getFitness());
// Apply crossover
population = ga.crossoverPopulation(population);
// Apply mutation
population = ga.mutatePopulation(population, timetable);
// Evaluate population
ga.evalPopulation(population, timetable);
// Increment the current generation
generation++;
}
// Print fitness
timetable.createClasses(population.getFittest(0));
System.out.println();
System.out.println("Solution found in " + generation + " generations");
System.out.println("Final solution fitness: " + population.getFittest(0).getFitness());
System.out.println("Clashes: " + timetable.calcClashes());
// Print classes
System.out.println();
Class classes[] = timetable.getClasses();
int classIndex = 1;
for (Class bestClass : classes) {
System.out.println("Class " + classIndex + ":");
System.out.println("Module: "
+ timetable.getModule(bestClass.getModuleId()).getModuleName());
System.out.println("Group: "
+ timetable.getGroup(bestClass.getGroupId()).getGroupId());
System.out.println("Room: "
+ timetable.getRoom(bestClass.getRoomId()).getRoomNumber());
System.out.println("Professor: "
+ timetable.getProfessor(bestClass.getProfessorId()).getProfessorName());
System.out.println("Time: "
+ timetable.getTimeslot(bestClass.getTimeslotId()).getTimeslot());
System.out.println("-----");
classIndex++;
}
}
/**
* Creates a Timetable with all the necessary course information.
*
* Normally you'd get this info from a database.
*
* @return
*/
private static Timetable initializeTimetable() {
// Create timetable
Timetable timetable = new Timetable();
// Set up rooms
timetable.addRoom(1, "A1", 15);
timetable.addRoom(2, "B1", 30);
timetable.addRoom(4, "D1", 20);
timetable.addRoom(5, "F1", 25);
// Set up timeslots
timetable.addTimeslot(1, "Mon 9:00 - 11:00");
timetable.addTimeslot(2, "Mon 11:00 - 13:00");
timetable.addTimeslot(3, "Mon 13:00 - 15:00");
timetable.addTimeslot(4, "Tue 9:00 - 11:00");
timetable.addTimeslot(5, "Tue 11:00 - 13:00");
timetable.addTimeslot(6, "Tue 13:00 - 15:00");
timetable.addTimeslot(7, "Wed 9:00 - 11:00");
timetable.addTimeslot(8, "Wed 11:00 - 13:00");
timetable.addTimeslot(9, "Wed 13:00 - 15:00");
timetable.addTimeslot(10, "Thu 9:00 - 11:00");
timetable.addTimeslot(11, "Thu 11:00 - 13:00");
timetable.addTimeslot(12, "Thu 13:00 - 15:00");
timetable.addTimeslot(13, "Fri 9:00 - 11:00");
timetable.addTimeslot(14, "Fri 11:00 - 13:00");
timetable.addTimeslot(15, "Fri 13:00 - 15:00");
// Set up professors
timetable.addProfessor(1, "Dr P Smith");
timetable.addProfessor(2, "Mrs E Mitchell");
timetable.addProfessor(3, "Dr R Williams");
timetable.addProfessor(4, "Mr A Thompson");
// Set up modules and define the professors that teach them
// timetable.addModule(1, "cs1", "Computer Science", new int[]{1, 2});
// timetable.addModule(2, "en1", "English", new int[]{1, 3});
// timetable.addModule(3, "ma1", "Maths", new int[]{1, 2});
// timetable.addModule(4, "ph1", "Physics", new int[]{3, 4});
// timetable.addModule(5, "hi1", "History", new int[]{4});
// timetable.addModule(6, "dr1", "Drama", new int[]{1, 4});
Connection conn = null;
PreparedStatement ps = null;
String query = "SELECT moduleId, moduleCode, module, professorIds from Course";
ResultSet rs = null;
try {
Class.forname("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/admin", "root", "");
ps = conn.prepareStatement(query);
rs = ps.executeQuery();
List<Module> moduleList = new ArrayList<Module>();
int index = 1;
while (rs.next()) {
Module module = null;
List<String> professorIdsStrList = Arrays.asList(rs.getString("professorIds").split("\\s*,\\s*"));
List<Integer> professorIdsIntList = professorIdsStrList.stream()
.map(s -> Integer.parseInt(s))
.collect(Collectors.toList());
module = new Module(rs.getInt("moduleId"), rs.getString("moduleCode"), rs.getString("module"), professorIdsIntList);
timetable.modules.put(index, module);
moduleList.add(module);
index++;
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
// Set up student groups and the modules they take.
timetable.addGroup(1, 10, new int[]{1, 3, 4});
timetable.addGroup(2, 30, new int[]{2, 3, 5, 6});
timetable.addGroup(3, 18, new int[]{3, 4, 5});
timetable.addGroup(4, 25, new int[]{1, 4});
timetable.addGroup(5, 20, new int[]{2, 3, 5});
timetable.addGroup(6, 22, new int[]{1, 4, 5});
timetable.addGroup(7, 16, new int[]{1, 3});
timetable.addGroup(8, 18, new int[]{2, 6});
timetable.addGroup(9, 24, new int[]{1, 6});
timetable.addGroup(10, 25, new int[]{3, 4});
return timetable;
}
}