def create_random_timetable(n_classes, n_days, n_slots, n_maxlecsperslot, req_all): timetable_np = np.empty( (n_classes, n_days, n_slots, n_maxlecsperslot)) * np.nan theory_roomgroup = np.zeros((n_days, n_slots)) lab_roomgroup = np.zeros((n_days, n_slots)) req_all['isAssigned'] = False f_batch_can_overlap = da.initialize('batchcanoverlap').astype(int) batch_sets = get_groups_of_batches(f_batch_can_overlap) max_tries = n_days * n_slots for c in (set(req_all.classId)): # First take one class req_class = req_all[(req_all['batchId'] != '-') & (req_all['classId'] == c)] for s in (set(req_class.subjectId)): req_subject = req_class[(req_class['subjectId'] == s)] for h in (set(req_subject.totalHrs)): req_hrs = req_subject[(req_subject['totalHrs'] == h)] for x in batch_sets: req_batchset = set(req_hrs['batchId'].astype(int)) if (req_batchset < set(x) ): #Then we can schedule that group of batches req_set = req_hrs.index #1. Get the requirements r_day = random.randint(0, n_days - 1) #2. Get the day and slot r_slot = random.randint(0, n_slots - 1) for i in req_set: #Schedule each of these requirements if (is_slot_available(req_all, timetable_np, c, r_day, r_slot, i, theory_roomgroup, lab_roomgroup)): timetable_np, theory_roomgroup, lab_roomgroup = assign( timetable_np, int(c), r_day, r_slot, i, req_all, theory_roomgroup, lab_roomgroup) req_all.set_value(i, 'isAssigned', True) req_single = req_all[req_all['isAssigned'] == False] for c in (set(req_single.classId)): # First take one class req_forgivenclass = req_single.loc[ req_single['classId'] == c] # List all the requirements for that class in req_forgivenclass req_forgivenclass = req_forgivenclass.sort('eachSlot', ascending=False) req_set = req_forgivenclass.index for req in (req_set): # Schedule each of these requirements notassigned = 1 n_tries = 0 while (notassigned == 1 and n_tries < max_tries): # Keep on scheduling till not found n_tries = n_tries + 1 r_day = random.randint(0, n_days - 1) r_slot = random.randint(0, n_slots - 1) if (is_slot_available(req_all, timetable_np, c, r_day, r_slot, req, theory_roomgroup, lab_roomgroup)): timetable_np, theory_roomgroup, lab_roomgroup = assign( timetable_np, int(c), r_day, r_slot, req, req_all, theory_roomgroup, lab_roomgroup) req_all.set_value(req, 'isAssigned', True) notassigned = 0 return timetable_np
def class_batch_overlap(timetable, req_all): """Calculates overlaps for theory classes and (non allowed) overlaps for batches and increments cost accordingly""" class_cost = 0 batch_cost = 0 n_classes, n_days, n_slots, n_max_lec_per_slot = timetable.shape f_batch_can_overlap = da.initialize('batchcanoverlap') for cl in range(n_classes): for day in range(n_days): for slot in range(n_slots): class_list = [] batch_list = [] slot_array = timetable[cl, day, slot, :] # Make 2 lists-class_list having all classes in the sub-slot & batch-list having all batches in sub-slot # Classes have category 'T' and Batches have category 'L' for sub_slot in slot_array: if not np.isnan(sub_slot): req = req_all.loc[req_all.index == sub_slot] if req.iloc[0][ 'category'] == 'T': # Class clash can be removed class_list.append(req.iloc[0]['classId']) elif req.iloc[0]['category'] == 'L': batch_list.append(req.iloc[0]['batchId']) # If the same class is repeated in the class_list for the same sub-slot, increment cost if len( class_list ) > 1: # Cost will be incremented only if multiple classes in same sub-slot for class_id in class_list: class_cost = class_cost + class_list.count( class_id) - 1 if len( batch_list ) > 1: # Cost will be incremented only if multiple batches in same sub-slot for batch_id in batch_list: # In case same batch is slotted more than once in sub slot batch_cost = batch_cost + batch_list.count( batch_id) - 1 # 1. Consider first batch in batch_list. # 2. Get all batches that are allowed to overlap # 3. Loop over all batches in batch_list. If any batch does'nt belong to this list, cost incremented batch_id = batch_list[0] batches_can_overlap = f_batch_can_overlap[ f_batch_can_overlap['batchId'] == batch_id] batches_all = batches_can_overlap[ batches_can_overlap.columns[ 2: 3]] # get batch_can_overlap column batches_all_list = batches_all['batchOverlapId'].tolist() batches_all_list.append(batch_id) for batch in batch_list: if batch not in batches_all_list: batch_cost += 1 return class_cost + batch_cost
def get_room_groups(lab_group, theory_group): "Forms 2 groups of rooms. lab_group contains rooms with roomCount < 25, all others in theory_group" f_room = da.initialize('room') for i in range(len(f_room)): if (f_room.iloc[i]['roomCount'] > 25): theory_group.append(f_room.iloc[i]['roomId']) else: lab_group.append(f_room.iloc[i]['roomId'])
def test_class_batch_overlap(timetable, req_all): """Calculates overlaps for theory classes and (non allowed) overlaps for batches and increments cost accordingly. Inconsistencies in data are handled""" class_cost = 0 batch_cost = 0 n_classes, n_days, n_slots, n_max_lec_per_slot=timetable.shape f_batch_can_overlap = da.initialize('batchcanoverlap'); # Get from database classId, batchId, overlapClassId, overlapBatchId f_overlapping_batches_with_classId = da.execquery("SELECT bc.classId, bc.batchId, bca.classId as 'overlapClassId', bca.batchId as 'overlapBatchId' FROM batchClass bc, batchClass bca, batchCanOverlap bo WHERE bc.batchId = bo.batchId AND bca.batchId = bo.batchOverlapId "); for cl in range(n_classes): for day in range(n_days): for slot in range(n_slots): class_list = [] batch_list = [] slot_array = timetable[cl,day,slot,:] # Make 2 lists-class_list having all classes in the sub-slot & batch-list having all batches in sub-slot # Classes have category 'T' and Batches have category 'L' for sub_slot in slot_array: if not np.isnan(sub_slot): req = req_all.loc[req_all.index == sub_slot] if req.iloc[0]['category'] == 'T': class_list.append(req.iloc[0]['classId']) elif req.iloc[0]['category'] == 'L': batch_list.append(req.iloc[0]['batchId']) # If the same class is repeated in the class_list for the same sub-slot, increment cost if len(class_list) > 1 : # Cost will be incremented only if multiple classes in same sub-slot for class_id in class_list: class_cost = class_cost + class_list.count(class_id) - 1 if len(batch_list)>1: # Cost will be incremented only if multiple batches in same sub-slot for batch_id in batch_list: # In case same batch is slotted more than once in sub slot batch_cost = batch_cost + batch_list.count(batch_id) - 1 # 1. Consider first batch in batch_list. # 2. Get all batches that are allowed to overlap # 3. Loop over all batches in batch_list. If any batch does'nt belong to this list, cost incremented batch_id = batch_list[0] #batches_can_overlap = f_batch_can_overlap[f_batch_can_overlap['batchId'] == batch_id] #batches_all = batches_can_overlap[batches_can_overlap.columns[2:3]] # get batch_can_overlap colum #batches_all_list = batches_all['batchOverlapId'].tolist() #batches_all_list.append(batch_id) for batch in batch_list: overlap_allowed = t.get_overlapping_batch_list(f_overlapping_batches_with_classId, cl, batch); if (len(overlap_allowed) > 0): if batch not in overlap_allowed: batch_cost += 1 # print("ClassId: ", cl, "Batch: ", batch, "Batch_all_lsit:", overlap_allowed, "batch_cost: ", batch_cost, "class_cost: ", class_cost); #print("Final cost: ", class_cost + batch_cost); return class_cost + batch_cost
classes_tobe_scheduled = set(req_all.classId); #n_classes = len(classes_tobe_scheduled); n_classes = 14 #print(n_classes); # Create room groups -- used in cost claculations and final room allocation lab_group = [] theory_group = [] m.get_room_groups(lab_group, theory_group); max_theory = len(theory_group); max_lab = len(lab_group); # Select initial solution tt_initial = m.generate_random_tt(req_all, n_days, n_slots, n_lec_per_slot, n_classes); print("Initial TT"); #print(tt_initial[2, :, :, :]) print("Initial cost:") print(cf.get_cost(tt_initial, req_all, n_days, n_slots, max_theory, max_lab)); tt_new =m.swap_neighbourhood(tt_initial, req_all, n_days, n_slots, n_lec_per_slot); print("Changed TT"); #print(tt_new[2, :, :, :]) print("Changed cost:") print(cf.get_cost(tt_new, req_all, n_days, n_slots, max_theory, max_lab)); f_batch_can_overlap = da.initialize('batchcanoverlap'); print(f_batch_can_overlap);