private static List<List<string>> GetGroupExportList(int groupIndex, Individual individual, TimetableData ttData) { //output[row][col] List<List<string>> output = InitializeExportList(individual.Groups, ttData); //title output[0][0] = ttData.Groups[groupIndex].Name; //Fill in the data for (int day = 0; day < individual.Groups.GetLength(1); day++) { for (int block = 0; block < individual.Groups.GetLength(2); block++) { if (individual.Groups[groupIndex, day, block] != -1) { Course c = ttData.Courses[individual.Groups[groupIndex, day, block]]; if (individual.Courses[c.Index, day, block] != -1) { Room r = ttData.Rooms[individual.Courses[c.Index, day, block]]; output[block * 3 + 1][day + 1] = c.Name; output[block * 3 + 2][day + 1] = r.Name; for (int l = 0; l < c.Lecturers.Length; l++) { output[block * 3 + 3][day + 1] = output[block * 3 + 3][day + 1] + c.Lecturers[l].LastName + (l == c.Lecturers.Length - 1 ? "" : ", "); } } } } } return output; }
public static void ExportAllRooms(Individual individual, TimetableData ttData, string filePath) { List<List<string>> output = new List<List<string>>(); for (int room = 0; room < ttData.Rooms.Length; room++) { output.AddRange(GetRoomExportList(room, individual, ttData)); } WriteCSV(filePath, output); }
public static void ExportAllLecturers(Individual individual, TimetableData ttData, string filePath) { List<List<string>> output = new List<List<string>>(); for (int lecuterer = 0; lecuterer < ttData.Lecturers.Length; lecuterer++) { output.AddRange(GetLecturerExportList(lecuterer, individual, ttData)); } WriteCSV(filePath, output); }
public static void ExportAllGroups(Individual individual, TimetableData ttData, string filePath) { List<List<string>> output = new List<List<string>>(); for (int group = 0; group < ttData.Groups.Length; group++) { output.AddRange(GetGroupExportList(group, individual, ttData)); } WriteCSV(filePath, output); }
public static Individual Clone(Individual source) { Individual clone = new Individual(); clone.Courses = Clone(source.Courses); clone.Lecturers = Clone(source.Lecturers); clone.Rooms = Clone(source.Rooms); clone.Groups = Clone(source.Groups); return clone; }
public static void ExportAll(Individual individual, TimetableData ttData, string filePath) { List<List<string>> output = new List<List<string>>(); for (int group = 0; group < ttData.Groups.Length; group++) { output.AddRange(GetGroupExportList(group, individual, ttData)); } for (int lecuterer = 0; lecuterer < ttData.Lecturers.Length; lecuterer++) { output.AddRange(GetLecturerExportList(lecuterer, individual, ttData)); } for (int room = 0; room < ttData.Rooms.Length; room++) { output.AddRange(GetRoomExportList(room, individual, ttData)); } WriteCSV(filePath, output); }
/// <summary> /// Random fill the given individual /// </summary> /// <param name="individual">individual to be filled</param> /// <returns>success</returns> private bool RandomFillIndividual(Individual individual) { for (int courseIndex = 0; courseIndex < individual.Courses.GetLength(0); courseIndex++) { List<PlacementContainer> possibilities = GetPossibilitiesForCourse(courseIndex, individual); if (possibilities.Count <= 0) { //When no possibilities left, restart individual.Clear(); return false; } possibilities.Sort(SortPlacementContainerByBlock); List<PlacementContainer> subset = new List<PlacementContainer>(); if (ttData.Courses[courseIndex].IsDummy) { //choose possibility that is late subset.Add(possibilities[possibilities.Count - 1]); for (int i = possibilities.Count - 2; i >= 0; i--) { if (possibilities[i].block >= subset[0].block) subset.Add(possibilities[i]); else break; } } else { //choose possibility that is early subset.Add(possibilities[0]); for (int i = 1; i < possibilities.Count; i++) { if (possibilities[i].block >= subset[0].block) subset.Add(possibilities[i]); else break; } } int chosenPossibility = random.Next(0, subset.Count); for (int blockOffset = 0; blockOffset < ttData.Courses[courseIndex].NumberOfBlocks; blockOffset++) { individual.SetChromosome(courseIndex, subset[chosenPossibility].day, subset[chosenPossibility].block + blockOffset, subset[chosenPossibility].room, ttData.Courses[courseIndex].Group.Index, GetLecturerIndices(courseIndex)); } } return true; }
private static int GetCourseDiff(TimetableData ttData, Individual individual) { int numberOfCoursesExpected = 0; for (int c = 0; c < ttData.Courses.Length; c++) { numberOfCoursesExpected += ttData.Courses[c].NumberOfBlocks; } int numberOfCoursesFound = 0; for (int c = 0; c < individual.Courses.GetLength(0); c++) { for (int d = 0; d < individual.Courses.GetLength(1); d++) { for (int b = 0; b < individual.Courses.GetLength(2); b++) { if (individual.Courses[c, d, b] != -1) numberOfCoursesFound++; } } } return numberOfCoursesExpected - numberOfCoursesFound; }
private static int GetFreeDaysForLecturer(Individual individual, int lIndex, TimetableData ttData) { int freeDayCount = 0; for (int d = 0; d < individual.Lecturers.GetLength(1); d++) { if (ttData.Lecturers[lIndex].AvailableResearchDays.Contains(d)) { bool isFree = true; for (int b = 0; b < individual.Lecturers.GetLength(2); b++) { if (individual.Lecturers[lIndex, d, b] != -1) { isFree = false; } } if (isFree) freeDayCount++; } } return freeDayCount; }
private static int SortByFitness(Individual x, Individual y) { if (x.Fitness > y.Fitness) return -1; if (x.Fitness < y.Fitness) return +1; return 0; }
private void SortIndividuals(Individual[] individuals) { Array.Sort(individuals, SortByFitness); }
private void CalculateFitness(Individual[] individuals) { foreach (Individual individual in individuals) { CalculateFitness(individual); } }
/// <summary> /// Creates a mutation of the given individual /// </summary> /// <param name="individual"></param> /// <returns></returns> private Individual PerformMutation(Individual individual) { Individual mutation = Individual.Clone(individual); int chosenCourse = random.Next(0, mutation.Courses.GetLength(0)); List<PlacementContainer> possibilities = GetPossibilitiesForCourse(chosenCourse, mutation); if (possibilities.Count <= 0) return mutation; int chosenPossibility = random.Next(0, possibilities.Count); mutation.ClearChromosome(chosenCourse, ttData); List<int> lecturers = new List<int>(); foreach (Lecturer lecturer in ttData.Courses[chosenCourse].Lecturers) { lecturers.Add(lecturer.Index); } for (int blockOffset = 0; blockOffset < ttData.Courses[chosenCourse].NumberOfBlocks; blockOffset++) { mutation.SetChromosome(chosenCourse, possibilities[chosenPossibility].day, possibilities[chosenPossibility].block + blockOffset, possibilities[chosenPossibility].room, ttData.Courses[chosenCourse].Group.Index, lecturers); } return mutation; }
/// <summary> /// Checks if the placement for the course is valid /// </summary> /// <param name="course"></param> /// <param name="day"></param> /// <param name="block"></param> /// <param name="room"></param> /// <param name="individual"></param> /// <returns>Placement is valid</returns> private bool IsValidForCourse(int course, int day, int block, int room, Individual individual) { for (int blockOffset = 0; blockOffset < ttData.Courses[course].NumberOfBlocks; blockOffset++) { //block available at that day? foreach (DayOfWeek exceptionDay in ttData.Blocks[block + blockOffset].Exceptions) { if ((int)exceptionDay == day + 1) return false; } //Course already set? if (individual.Courses[course, day, block + blockOffset] != -1) return false; //Room already occupied? if (individual.Rooms[room, day, block + blockOffset] != -1) return false; //Lab? if (ttData.Courses[course].NeedsLab != ttData.Rooms[room].IsLab) return false; int test = ttData.Courses[course].Lecturers.Length; //Lecturers available? for (int neededLecturer = 0; neededLecturer < ttData.Courses[course].Lecturers.Length; neededLecturer++) { if (!ttData.Courses[course].Lecturers[neededLecturer].IsDummy) { if (individual.Lecturers[ttData.Courses[course].Lecturers[neededLecturer].Index, day, block + blockOffset] != -1) return false; } } //Group available? if (individual.Groups[ttData.Courses[course].Group.Index, day, block + blockOffset] != -1) return false; } //Researchdays restriction for lecturers foreach (Lecturer l in ttData.Courses[course].Lecturers) { int tmp = individual.Lecturers[l.Index, day, block]; individual.Lecturers[l.Index, day, block] = course; int freeDays = GetFreeDaysForLecturer(individual, l.Index, ttData); individual.Lecturers[l.Index, day, block] = tmp; if (freeDays < l.NeededNumberOfResearchDays) return false; } return true; }
/// <summary> /// Get a list of all possiblities for course placement /// </summary> /// <param name="course">course to inspect</param> /// <param name="individual">individual to be inspected</param> /// <returns>List of the possibilities</returns> private List<PlacementContainer> GetPossibilitiesForCourse(int course, Individual individual) { List<PlacementContainer> possibilities = new List<PlacementContainer>(); int neededNumberOfBlocks = ttData.Courses[course].NumberOfBlocks; for (int day = 0; day < individual.Courses.GetLength(1); day++) { for (int block = 0; block < individual.Courses.GetLength(2); block++) { if (block + neededNumberOfBlocks - 1 < individual.Courses.GetLength(2)) { for (int room = 0; room < individual.Rooms.GetLength(0); room++) { if (IsValidForCourse(course, day, block, room, individual)) { PlacementContainer c = new PlacementContainer(); c.day = day; c.block = block; c.room = room; possibilities.Add(c); } } } } } return possibilities; }
public static void ExportGroup(int groupIndex, Individual individual, TimetableData ttData, string filePath) { WriteCSV(filePath, GetGroupExportList(groupIndex, individual, ttData)); }
private void CalculateFitness(Individual individual) { int fitness = 0; for (int day = 0; day < numberOfDays; day++) { Dictionary<int, int> groupFirstBlock = new Dictionary<int, int>(); Dictionary<int, int> groupLastBlock = new Dictionary<int, int>(); Dictionary<int, int> groupBlockCount = new Dictionary<int, int>(); Dictionary<string, int> courseIdBlackList = new Dictionary<string, int>(); Dictionary<int, List<int>> courseBlockStartHours = new Dictionary<int, List<int>>(); for (int block = 0; block < ttData.Blocks.Length; block++) { for (int course = 0; course < individual.Courses.GetLength(0); course++) { if (individual.Courses[course, day, block] != -1) { //Courses should not appear more than once a day if (!courseIdBlackList.ContainsKey(ttData.Courses[course].Id)) courseIdBlackList[ttData.Courses[course].Id] = 0; courseIdBlackList[ttData.Courses[course].Id]++; if (courseIdBlackList[ttData.Courses[course].Id] > ttData.Courses[course].NumberOfBlocks) fitness -= 100; //Courses should start before 13:00 //Opposite for dummy courses fitness += (ttData.Blocks[block].Start.Hour - 13) * 25 * (ttData.Courses[course].IsDummy ? 1 : -1); //Roompreference if (ttData.Courses[course].RoomPreference != null) { if (individual.Courses[course, day, block] == ttData.Courses[course].RoomPreference.Index) fitness += 100; } //Measurements that are not applied on dummys if (!ttData.Courses[course].IsDummy) { //Store the first and last block of the group int group = ttData.Courses[course].Group.Index; if (!groupFirstBlock.ContainsKey(group)) groupFirstBlock.Add(group, block); if (!groupLastBlock.ContainsKey(group)) groupLastBlock.Add(group, block); if (!groupBlockCount.ContainsKey(group)) groupBlockCount.Add(group, 1); groupLastBlock[group] = block; groupBlockCount[group]++; //A course should not by-pass the lunch break at 13:00 //--> Store the start hours if (!courseBlockStartHours.ContainsKey(course)) courseBlockStartHours.Add(course, new List<int>()); courseBlockStartHours[course].Add(ttData.Blocks[block].Start.Hour); } } } } //Groups should not have gaps in their plan for (int group = 0; group < ttData.Groups.Length; group++) { if (groupFirstBlock.ContainsKey(group)) fitness -= (groupLastBlock[group] - groupFirstBlock[group] - groupBlockCount[group]) * 30; } //A course should not by-pass the lunch break at 13:00 foreach (var key in courseBlockStartHours.Keys) { int start = courseBlockStartHours[key][0]; int end = courseBlockStartHours[key][courseBlockStartHours[key].Count - 1]; if (start - 13 < 0 && !(end - 13 < 0)) fitness -= 50; } } for (int g = 0; g < individual.Groups.GetLength(0); g++) { for (int d = 0; d < individual.Groups.GetLength(1); d++) { int count = 0; for (int b = 0; b < individual.Groups.GetLength(2); b++) { if (individual.Groups[g, d, b] != -1) { if (!ttData.Courses[individual.Groups[g, d, b]].IsDummy) count++; } } //Increase fitness when a group gets a free day if (count == 0) fitness += 100; } } individual.Fitness = fitness; }
private static int GetCourseCountForGroup(int gIndex, Individual individual) { int count = 0; for (int d = 0; d < individual.Groups.GetLength(1); d++) { for (int b = 0; b < individual.Groups.GetLength(2); b++) { if (individual.Groups[gIndex, d, b] != -1) count++; } } return count; }
public static void ExportLecturer(int lecturerIndex, Individual individual, TimetableData ttData, string filePath) { WriteCSV(filePath, GetLecturerExportList(lecturerIndex, individual, ttData)); }
private static int GetCourseCountForLecturer(Individual individual, int lIndex) { int count = 0; for (int d = 0; d < individual.Lecturers.GetLength(1); d++) { for (int b = 0; b < individual.Lecturers.GetLength(2); b++) { if (individual.Lecturers[lIndex, d, b] != -1) count++; } } return count; }
public static void ExportRoom(int roomIndex, Individual individual, TimetableData ttData, string filePath) { WriteCSV(filePath, GetRoomExportList(roomIndex, individual, ttData)); }