""" Generates a larger, deliberately harder dummy CSV dataset under data/dummy/ so the timetable template generator has something non-trivial to schedule and render — more departments/batches/sections than the previous small dataset, tighter room and instructor contention (fewer rooms/instructors relative to demand), a second block, and mixed lecture durations (90 vs 120 minutes) so weaknesses in the scheduler surface as WARNINGs/conflicts instead of everything trivially fitting. Run once: python data/dummy/generate_dummy_data.py """ import csv import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) def write_csv(relative_path, header, rows): path = os.path.join(BASE_DIR, relative_path) os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(header) writer.writerows(rows) print(f"wrote {len(rows)} rows -> {path}") def main(): # ---- blocks: two blocks now, Block A (bigger) and Block B (smaller) ---- write_csv( "blocks/blocks.csv", ["block_id", "block_name"], [ ["A", "Block A"], ["B", "Block B"], ], ) # ---- rooms: deliberately tight relative to demand (see offerings # below) so room contention is real, spread across both blocks ---- write_csv( "blocks/rooms.csv", ["room_id", "room_name", "block_id", "room_type", "capacity"], [ ["A-101", "Room 101", "A", "classroom", 60], ["A-102", "Room 102", "A", "classroom", 60], ["A-103", "Room 103", "A", "classroom", 50], ["A-201", "Room 201", "A", "classroom", 60], ["A-L01", "Computer Lab 1", "A", "lab", 35], ["A-L02", "Computer Lab 2", "A", "lab", 35], ["B-101", "Room 101 (B)", "B", "classroom", 50], ["B-102", "Room 102 (B)", "B", "classroom", 50], ["B-L01", "Electronics Lab", "B", "lab", 30], ], ) # ---- departments / programs / batches: 3 departments, 2 programs # each, 2 sessions (25/26) -> 12 batches total (was 6) ---- department_programs = { "CS": ["BSCS", "BSSE"], "EE": ["BSEE", "BSCE"], "BBA": ["BBA", "BSAF"], } program_codes = { "BSCS": "021519", "BSSE": "021520", "BSEE": "031519", "BSCE": "031520", "BBA": "041519", "BSAF": "041520", } batches_25 = [] batches_26 = [] for department, programs in department_programs.items(): for program in programs: code = program_codes[program] batches_25.append([f"25{code}", department, program, "25"]) batches_26.append([f"26{code}", department, program, "26"]) write_csv( "batch_codes/25/batches.csv", ["batch_code", "department", "program", "session"], batches_25, ) write_csv( "batch_codes/26/batches.csv", ["batch_code", "department", "program", "session"], batches_26, ) all_batches = batches_25 + batches_26 # ---- courses ---- # course_id, course_name, credit_hours, lectures_per_week, # labs_per_week, is_general, lecture_room_id, lab_room_id, # lecture_duration_minutes # # Mixed lecture durations: most courses are 90-min x N/week, but a few # are the special "2 hours once a week" case (lecture_duration_minutes # 120, lectures_per_week 1). Labs vary 0/1/2 per week. Deliberately # more courses per department than the room/instructor pool can # comfortably absorb without contention. courses = [ # CS department courses ["CS101", "Programming Fundamentals", 4, 2, 1, "no", "A-101", "A-L01", 90], ["CS201", "Data Structures", 4, 2, 1, "no", "A-102", "A-L01", 90], ["CS301", "Operating Systems", 3, 1, 1, "no", "A-101", "A-L02", 120], ["CS302", "Database Systems", 4, 2, 2, "no", "A-102", "A-L02", 90], # EE department courses ["EE101", "Basic Electronics", 4, 2, 1, "no", "A-201", "A-L02", 90], ["EE201", "Digital Logic Design", 4, 2, 1, "no", "B-101", "B-L01", 90], ["EE301", "Signals and Systems", 3, 1, 0, "no", "B-102", "", 120], # BBA department courses ["BBA101", "Principles of Management", 3, 2, 0, "no", "B-101", "", 90], ["BBA201", "Financial Accounting", 3, 2, 0, "no", "B-102", "", 90], ["BBA301", "Marketing Management", 3, 1, 0, "no", "A-103", "", 120], # General (shared) courses ["GEN101", "Functional English", 3, 2, 0, "yes", "A-103", "", 90], ["GEN102", "Islamic Studies", 2, 1, 0, "yes", "A-103", "", 90], ["GEN103", "Pakistan Studies", 2, 1, 0, "yes", "B-101", "", 120], ] write_csv( "courses/courses.csv", [ "course_id", "course_name", "credit_hours", "lectures_per_week", "labs_per_week", "is_general", "lecture_room_id", "lab_room_id", "lecture_duration_minutes", ], courses, ) # ---- course offerings: course + section (batches in that section) + # instructor ---- # Deliberately tight instructor pool reused across many sections/ # courses (some instructors will end up wanted in overlapping slots), # forcing real contention in Phase 2/Phase 3. dept_courses = { "CS": ["CS101", "CS201", "CS301", "CS302"], "EE": ["EE101", "EE201", "EE301"], "BBA": ["BBA101", "BBA201", "BBA301"], } # Small pools relative to (department batches x courses) demand. dept_instructors = { "CS": ["1001", "1002", "1003"], "EE": ["1004", "1005"], "BBA": ["1007", "1008"], } offerings = [] section_letters = ["A", "B", "C", "D"] dept_section_counter = {"CS": 0, "EE": 0, "BBA": 0} for batch_code, department, program, session in all_batches: section_id = section_letters[dept_section_counter[department] % len(section_letters)] dept_section_counter[department] += 1 instr_pool = dept_instructors[department] for i, course_id in enumerate(dept_courses[department]): # Deliberately narrow instructor rotation (2-3 instructors # covering 3-4 courses per department) so the same instructor # teaches multiple courses/sections -> instructor contention. instr = instr_pool[i % len(instr_pool)] offerings.append([course_id, section_id, batch_code, instr]) # general courses: one offering per (course, session), section "ALL" # grouping every batch code sharing that session for session, batch_group in ( ("25", [b[0] for b in batches_25]), ("26", [b[0] for b in batches_26]), ): offerings.append(["GEN101", "ALL", "|".join(batch_group), "1002"]) offerings.append(["GEN102", "ALL", "|".join(batch_group), "1006"]) offerings.append(["GEN103", "ALL", "|".join(batch_group), "1006"]) write_csv( "courses/course_offering.csv", ["course_id", "section_id", "batch_codes", "instructor_code"], offerings, ) # ---- instructors (4-digit employee codes) ---- # Derived from the offerings above so it can never drift: one row per # unique (instructor, course, section) teaching assignment. instructor_names = { "1001": "Dr. Ahsan Raza", "1002": "Ms. Sana Tariq", "1003": "Mr. Bilal Khan", "1004": "Dr. Farah Iqbal", "1005": "Mr. Usman Ali", "1006": "Ms. Hira Shah", "1007": "Dr. Nadia Farooq", "1008": "Mr. Kamran Sheikh", } instructors = [] for course_id, section_id, batch_codes, instr_code in offerings: instructors.append([instr_code, instructor_names[instr_code], course_id, section_id]) write_csv( "instructor/instructors.csv", ["instructor_code", "instructor_name", "course_id", "section_id"], instructors, ) # ---- students (roll_no = batch_code-seq): 18 per batch (was 5) ---- students = [] for batch_code, department, program, session in all_batches: for seq in range(1, 19): roll_no = f"{batch_code}-{seq:03d}" students.append([roll_no, batch_code, f"Student {roll_no}"]) write_csv( "roll_no/students.csv", ["roll_no", "batch_code", "student_name"], students, ) print("\nDummy data generation complete.") if __name__ == "__main__": main()