Commit b0af85eb authored by P.R.K Peramuna's avatar P.R.K Peramuna

Time table generator

parent c2c44ca2
{
"cells": [
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import numpy as np \n",
"import pandas as pd\n",
"import datetime as dt"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"available_times = {\n",
" \"monday\":[\n",
" \"04:00-6:00\",\n",
" \"16:00-21:00\"\n",
" ],\n",
" \"tuesday\":[\n",
" \"04:00-6:00\",\n",
" \"16:00-21:00\"\n",
" ],\n",
" \"wednesday\":[\n",
" \"04:00-6:00\",\n",
" \"18:00-21:00\"\n",
" ],\n",
" \"thursday\":[\n",
" \"04:00-6:00\",\n",
" \"14:00-21:00\"\n",
" ],\n",
" \"friday\":[\n",
" \"04:00-6:00\",\n",
" \"16:00-21:00\"\n",
" ],\n",
" \"saturday\":[\n",
" \"06:00-18:00\"\n",
" ],\n",
" \"sunday\":[\n",
" \"06:00-18:00\"\n",
" ]\n",
" }\n",
"\n",
"\n",
"student_details = [\n",
" {\n",
" \"Subject name & PDF\":\"English for academic purpose (EAP)\",\n",
" \"Credit points\":3,\n",
" \"Student Level\":\"Easy\",\n",
" \"Total Chapters\":6,\n",
" \"Studied Already\":5\n",
" },\n",
" {\n",
" \"Subject name & PDF\":\"Infromation system & data modeling (ISDM)\",\n",
" \"Credit points\":4,\n",
" \"Student Level\":\"Easy\",\n",
" \"Total Chapters\":8,\n",
" \"Studied Already\":6.75\n",
" },\n",
" {\n",
" \"Subject name & PDF\":\"Internet & web technologies (IWT)\",\n",
" \"Credit points\":4,\n",
" \"Student Level\":\"Average\",\n",
" \"Total Chapters\":9,\n",
" \"Studied Already\":5\n",
" },\n",
" {\n",
" \"Subject name & PDF\":\"Object oriented concepts (OOC)\",\n",
" \"Credit points\":4,\n",
" \"Student Level\":\"Hard\",\n",
" \"Total Chapters\":7,\n",
" \"Studied Already\":7\n",
" },\n",
" {\n",
" \"Subject name & PDF\":\"Software process modeling (SPM)\",\n",
" \"Credit points\":3,\n",
" \"Student Level\":\"Hard\",\n",
" \"Total Chapters\":5,\n",
" \"Studied Already\":3\n",
" }\n",
" ]"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def find_available_hours_per_week(available_time_dict):\n",
" available_hours = {}\n",
" for day in available_time_dict.keys():\n",
" available_hour_per_day = 0\n",
" for time in available_time_dict[day]:\n",
" start_time = time.split('-')[0]\n",
" end_time = time.split('-')[1]\n",
" start_time = dt.datetime.strptime(start_time, '%H:%M')\n",
" end_time = dt.datetime.strptime(end_time, '%H:%M')\n",
" available_hour_per_day += (end_time - start_time).seconds/3600\n",
"\n",
" available_hours[day] = available_hour_per_day\n",
" return available_hours\n",
"\n",
"def map_time_slot(duration):\n",
" # map each half hour to a number, so a day should have 0 - 48 \n",
" # eg : duration - '06:00-18:00'\n",
"\n",
" start_time = duration.split('-')[0]\n",
" end_time = duration.split('-')[1]\n",
"\n",
" start_time = dt.datetime.strptime(start_time, '%H:%M')\n",
" end_time = dt.datetime.strptime(end_time, '%H:%M')\n",
"\n",
" time_starter = dt.datetime.strptime('00:00', '%H:%M')\n",
" idx_tracker = []\n",
"\n",
" idx = 0\n",
" while True:\n",
" if time_starter >= start_time and time_starter < end_time:\n",
" idx_tracker.append(idx)\n",
" time_starter += dt.timedelta(minutes=30)\n",
" idx += 1\n",
" if time_starter >= dt.datetime.strptime('23:59', '%H:%M'):\n",
" break\n",
"\n",
" return idx_tracker\n",
"\n",
"def map_idx_to_time(idx):\n",
" time_starter = dt.datetime.strptime('00:00', '%H:%M')\n",
" for i in range(idx):\n",
" time_starter += dt.timedelta(minutes=30)\n",
" start_time = time_starter.strftime('%H:%M')\n",
" end_time = (time_starter + dt.timedelta(minutes=30)).strftime('%H:%M')\n",
" return f\"{start_time}-{end_time}\"\n",
"\n",
"def find_available_slots_per_week(available_time_dict):\n",
" available_slots = {}\n",
" for day in available_time_dict.keys():\n",
" available_slots_per_day = []\n",
" for time in available_time_dict[day]:\n",
" available_slots_per_day += map_time_slot(time)\n",
" available_slots[day] = available_slots_per_day\n",
" return available_slots\n",
"\n",
"def extract_all_slots(available_times):\n",
" slot_dict = find_available_slots_per_week(available_times)\n",
" all_slots = []\n",
" for dat, slots in slot_dict.items():\n",
" for slot in slots:\n",
" all_slots.append(f\"{dat}_{slot}\")\n",
" return all_slots\n",
"\n",
"def reward_per_module(\n",
" student_details,\n",
" level_mapping = {\n",
" 'Easy': 0,\n",
" 'Average': 1,\n",
" 'Hard': 2\n",
" }):\n",
" df = pd.DataFrame(student_details)\n",
" df['Student Level'] = df['Student Level'].map(level_mapping)\n",
"\n",
" CreditPoints = df['Credit points'].values\n",
" StudentLevel = df['Student Level'].values\n",
" StudentLevel = [int(i) + 1 for i in StudentLevel]\n",
"\n",
" TotalChapters = df['Total Chapters'].values\n",
" StudiedAlready = df['Studied Already'].values\n",
"\n",
" ChapterScore = (TotalChapters - StudiedAlready) / TotalChapters\n",
"\n",
" reward = (CreditPoints * StudentLevel) * ChapterScore\n",
" reward = reward / np.sum(reward)\n",
"\n",
" modules = df['Subject name & PDF'].values\n",
" return dict(zip(modules, reward))\n",
"\n",
"def q_learning():\n",
" Q = np.zeros([7, 48])\n",
"\n",
" gamma = 0.8\n",
" alpha = 0.9\n",
"\n",
" num_episodes = 1000\n",
"\n",
" for i in range(num_episodes):\n",
" s = 0\n",
"\n",
" while s < 6:\n",
" a = np.argmax(Q[s, :] + np.random.randn(1, 48) * (1. / (i + 1)))\n",
"\n",
" s_prime = s + 1\n",
" r = 1\n",
"\n",
" Q[s, a] = Q[s, a] + alpha * (r + gamma * np.max(Q[s_prime, :]) - Q[s, a])\n",
" s = s_prime\n",
"\n",
" return Q\n",
"\n",
"def assign_slots_per_week(available_times, student_details):\n",
" module_weights = reward_per_module(student_details)\n",
" all_slots = extract_all_slots(available_times)\n",
" module_weights = {k : int(v * len(all_slots)) for k, v in module_weights.items()}\n",
" # sort the modules based on weights\n",
" module_weights = {k: v for k, v in sorted(module_weights.items(), key=lambda item: item[1], reverse=True)}\n",
" module_weights[list(module_weights.keys())[-1]] = (len(all_slots) - sum(module_weights.values())) + module_weights[list(module_weights.keys())[-1]]\n",
"\n",
" all_slots_cp = all_slots.copy()\n",
" all_slots_cp = np.array(all_slots_cp)\n",
"\n",
" assign_slots = {}\n",
" for module, weight in module_weights.items():\n",
" Q = q_learning()\n",
" rand_idxs = np.random.choice(len(all_slots_cp), weight, replace=False)\n",
" module_json = {}\n",
" for idx in rand_idxs:\n",
" slopt_details = all_slots_cp[idx]\n",
" day, splot_id = slopt_details.split('_')\n",
" if day not in module_json.keys():\n",
" module_json[day] = []\n",
" module_json[day].append(int(splot_id))\n",
" \n",
" all_slots_cp = np.delete(all_slots_cp, rand_idxs)\n",
" assign_slots[module] = module_json\n",
"\n",
" for module, slots in assign_slots.items():\n",
" for day, slot_ids in slots.items():\n",
" # sort the slot ids in ascending order\n",
" slot_ids = sorted(slot_ids)\n",
" assign_slots[module][day] = slot_ids\n",
" assign_slots[module][day] = [map_idx_to_time(i) for i in slot_ids]\n",
"\n",
" return assign_slots"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# find_available_hours_per_week(available_times)\n",
"# find_available_slots_per_week(available_times)\n",
"# extract_all_slots(available_times)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'Internet & web technologies (IWT)': {'wednesday': ['05:00-05:30',\n",
" '05:30-06:00',\n",
" '18:00-18:30',\n",
" '18:30-19:00',\n",
" '19:00-19:30',\n",
" '20:00-20:30',\n",
" '20:30-21:00'],\n",
" 'sunday': ['07:00-07:30',\n",
" '07:30-08:00',\n",
" '08:00-08:30',\n",
" '08:30-09:00',\n",
" '09:30-10:00',\n",
" '10:30-11:00',\n",
" '11:00-11:30',\n",
" '13:00-13:30',\n",
" '13:30-14:00',\n",
" '14:00-14:30',\n",
" '15:30-16:00',\n",
" '16:30-17:00'],\n",
" 'thursday': ['04:00-04:30',\n",
" '04:30-05:00',\n",
" '05:00-05:30',\n",
" '05:30-06:00',\n",
" '16:00-16:30',\n",
" '17:00-17:30',\n",
" '17:30-18:00',\n",
" '18:30-19:00',\n",
" '19:00-19:30',\n",
" '19:30-20:00',\n",
" '20:00-20:30',\n",
" '20:30-21:00'],\n",
" 'friday': ['04:30-05:00',\n",
" '16:00-16:30',\n",
" '16:30-17:00',\n",
" '17:00-17:30',\n",
" '19:00-19:30',\n",
" '19:30-20:00',\n",
" '20:30-21:00'],\n",
" 'monday': ['04:00-04:30',\n",
" '04:30-05:00',\n",
" '05:00-05:30',\n",
" '16:00-16:30',\n",
" '16:30-17:00',\n",
" '17:00-17:30',\n",
" '17:30-18:00',\n",
" '18:30-19:00',\n",
" '19:00-19:30',\n",
" '19:30-20:00',\n",
" '20:00-20:30',\n",
" '20:30-21:00'],\n",
" 'tuesday': ['04:00-04:30',\n",
" '05:30-06:00',\n",
" '17:30-18:00',\n",
" '19:00-19:30',\n",
" '19:30-20:00',\n",
" '20:00-20:30',\n",
" '20:30-21:00'],\n",
" 'saturday': ['06:00-06:30',\n",
" '06:30-07:00',\n",
" '07:30-08:00',\n",
" '08:00-08:30',\n",
" '08:30-09:00',\n",
" '09:00-09:30',\n",
" '09:30-10:00',\n",
" '10:30-11:00',\n",
" '11:30-12:00',\n",
" '13:00-13:30',\n",
" '14:30-15:00',\n",
" '15:30-16:00',\n",
" '16:00-16:30',\n",
" '17:30-18:00']},\n",
" 'Software process modeling (SPM)': {'tuesday': ['05:00-05:30',\n",
" '16:00-16:30',\n",
" '16:30-17:00',\n",
" '17:00-17:30',\n",
" '18:30-19:00'],\n",
" 'saturday': ['12:30-13:00', '14:00-14:30', '16:30-17:00', '17:00-17:30'],\n",
" 'sunday': ['06:30-07:00',\n",
" '09:00-09:30',\n",
" '10:00-10:30',\n",
" '11:30-12:00',\n",
" '12:00-12:30',\n",
" '12:30-13:00',\n",
" '14:30-15:00',\n",
" '16:00-16:30',\n",
" '17:00-17:30'],\n",
" 'wednesday': ['04:30-05:00'],\n",
" 'thursday': ['14:00-14:30', '16:30-17:00'],\n",
" 'friday': ['05:30-06:00', '18:30-19:00', '20:00-20:30']},\n",
" 'Infromation system & data modeling (ISDM)': {'friday': ['05:00-05:30',\n",
" '18:00-18:30'],\n",
" 'sunday': ['06:00-06:30', '15:00-15:30'],\n",
" 'tuesday': ['04:30-05:00', '18:00-18:30'],\n",
" 'saturday': ['10:00-10:30', '13:30-14:00', '15:00-15:30'],\n",
" 'wednesday': ['04:00-04:30', '19:30-20:00'],\n",
" 'thursday': ['18:00-18:30']},\n",
" 'English for academic purpose (EAP)': {'thursday': ['14:30-15:00',\n",
" '15:00-15:30',\n",
" '15:30-16:00'],\n",
" 'friday': ['04:00-04:30', '17:30-18:00'],\n",
" 'saturday': ['07:00-07:30', '11:00-11:30', '12:00-12:30'],\n",
" 'monday': ['18:00-18:30'],\n",
" 'sunday': ['17:30-18:00']},\n",
" 'Object oriented concepts (OOC)': {'monday': ['05:30-06:00']}}"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"assign_slots_per_week(available_times, student_details)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "tf210",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.16"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment