def create(nodes, mapping): nonlocal max_happiness nonlocal ret nonlocal k if nodes == []: mm = convert_dictionary(mapping) #if mapping not in rooms and is_valid_solution(mm, G, s, len(mapping)): #rooms.append(mapping) room_k = len(mapping) if is_valid_solution(mm, G, s, room_k): happiness = calculate_happiness(mm, G) if happiness > max_happiness: max_happiness = happiness ret = mm k = room_k return pp = nodes[0] r = 0 n = copy.deepcopy(nodes) n.remove(pp) for room in mapping: m = copy.deepcopy(mapping) m[room] = m[room] + [pp] mm = convert_dictionary(m) if is_valid_solution(mm, G, s, len(m)): create(n, m) r += 1 m = copy.deepcopy(mapping) m[r] = [pp] create(n, m)
def solve_happy(G, s, prob): """ Args: G: networkx.Graph s: stress_budget Returns: D: Dictionary mapping for student to breakout room r e.g. {0:2, 1:0, 2:1, 3:2} k: Number of breakout rooms """ # TODO: your code here! best_D_so_far = {} best_k_so_far = 1 best_H_so_far = 0.0 n = nx.number_of_nodes(G) for k in range(1, n + 1): curr_D = {} smax = s/k G_happy = G.copy() while nx.number_of_nodes(G_happy) > k: i = np.random.geometric(p=prob, size = 1).item(0) # sort edges by decreasing happiness sorted_happiness = sorted(G_happy.edges(data=True), key=lambda y: (y[2]["happiness"], -y[2]["stress"]), reverse=True) #i = random.randint(0, len(sorted_happiness)) if len(sorted_happiness) == 0: break #need to merge nodes A and B i = i % len(sorted_happiness) n1, n2, _ = sorted_happiness[i] if G_happy.nodes[n1].get("stress", 0) + G_happy.nodes[n2].get("stress", 0) + G_happy.edges[n1, n2]["stress"] <= smax: merge(G_happy, n1, n2) else: G_happy.remove_edge(n1,n2) if nx.number_of_nodes(G_happy) == k: room = 0 for node in list(G_happy.nodes): if isinstance(node, int): temp = [node] else: temp = node.split(' ') temp = [int(x) for x in temp] curr_D[room] = temp room += 1 curr_D = convert_dictionary(curr_D) else: continue if is_valid_solution(curr_D, G, s, k): if calculate_happiness(curr_D, G) > best_H_so_far: best_D_so_far = curr_D best_k_so_far = k best_H_so_far = calculate_happiness(curr_D, G) # # pass return best_D_so_far, best_k_so_far
def greedy_happystress(G, G_cop, s, rooms): dic = {} current_room = 0 while G_cop.nodes and current_room < rooms: dic[current_room] = room_maker(G, G_cop, s / rooms) current_room += 1 return convert_dictionary(dic)
def gamble_solve(G, s, num_open_rooms, reps=100, limit = -1): """ Gambles by randomly assigning students to rooms and checking optimality and stress levels Works specifically for input #1 type - can be modified by changin num_open_rooms to randint - can be modified adding checks before h > best_h to check stress_max val per room ToDo: - Refactor to use methods in utils.py - Make sure truly gamble solution """ students = list(G.nodes) #num_open_rooms = int(math.ceil(len(students)/2)) best_h = -1 best_rooms = [] count = 0 while (count < reps): rooms = [] for _ in range(num_open_rooms): rooms.append([]) temp_students = students.copy() rooms = random_assign(temp_students, rooms, limit) temp_d = utils.convert_list_to_dictionary(rooms) dict = utils.convert_dictionary(temp_d) valid = utils.is_valid_solution(dict, G, s, num_open_rooms) h = utils.calculate_happiness(dict, G) if ((valid) and (h > best_h)): best_rooms = [] room_temp = rooms.copy() for i in range(len(rooms)): best_rooms += [rooms[i].copy()] best_h = h elif (not valid): count = count - 1 count = count + 1 return best_rooms.copy(), best_h
def kcluster_beef(G, s): best = {} best_happiness = 0 for i in range(1, len(G.nodes)): local_best = {} j = 0 valid = 0 total_combos = [] while j <= 1000: if (not valid) and j >= 100: j = 1000 init_centroids = random.sample(range(0, len(list(G.nodes))), i) if (len(total_combos) < comb(len(G.nodes), i)): while (init_centroids in total_combos): init_centroids = random.sample( range(0, len(list(G.nodes))), i) total_combos.append(init_centroids) classes = making_classes_beef(init_centroids, G, s / i) for c in classes: d = making_dic(c) dic = convert_dictionary(d) if is_valid_solution(dic, G, s, i): valid = 1 local_best[calculate_happiness(dic, G)] = dic if len(local_best) != 0: local = max(local_best.keys()) if len(best) != 0: if best_happiness < local: best_happiness = local best = local_best[local] else: best_happiness = local best = local_best[local] j += 1 h = calculate_happiness(best, G) return best
def greedy_solve_1(G, s): """ Probably open 1 room, add as many possible students w/o exceeding stress level, then if s_level exceeded, remove all students, open 2 rooms, repeat - Remember to sort students (or sort edgelist or somt) and break ties by happiness Helpful utils: utils.is_valid_solution(D, G, s, rooms) utils.convert_dictionary(room_to_student) utils.calculate_stress_for_room(arr, G) utils.calculate_happiness_for_room(arr, G) """ #Iterate by opening 1 breakout room at a time, up to n breakout rooms room_to_students_to_return = {} max_happy = -1 for i in range(1, len(list(G.nodes)) + 1): room_to_students = {} for j in range(i): room_to_students[j] = [] #print("room_to_students: ", room_to_students) #Make copy of graph (so we can use actual graph later on as reference) G_copy = nx.Graph(G) #Create edgeList pairs of students sorted by stress/happiness stress_edgeList = sorted(G_copy.edges, key=lambda x: G_copy.edges[x]["stress"], reverse = True) happy_edgeList = sorted(G_copy.edges, key=lambda x: G_copy.edges[x]["happiness"], reverse = True) #dictionary of happiness values to list of all students that have same happiness value happy_dict = {} for edge in happy_edgeList: #print("edge: ", edge) #print("happiness: ", G_copy.edges[edge]["happiness"]) if G_copy.edges[edge]["happiness"] in happy_dict: happy_dict[G_copy.edges[edge]["happiness"]] += [edge] else: happy_dict[G_copy.edges[edge]["happiness"]] = [] happy_dict[G_copy.edges[edge]["happiness"]] += [edge] assigned_students = [] #Assign students until all pairings are broken or assigned (i.e. all students in rooms) while (len(assigned_students) < len(list(G.nodes))): #Take happiest pair and try to assign them to rooms to maximize happiness #print(happy_dict) student_pair = None """ for key in sorted(happy_dict.keys()): #print("key: ", key) #print("happy_dict[key]: ", happy_dict[key]) if (len(happy_dict[key]) > 0): student_pair = random.sample(happy_dict[key], 1) #print(student_pair[0]) happy_dict[key].remove(student_pair[0]) #student_pair = happy_edgeList.pop(0) if (not student_pair): print("here") for key in sorted(happy_dict.keys()): print("key: ", key) if (len(happy_dict[key]) > 0): print("happy_dict[key]: ", happy_dict[key]) break student_pair = student_pair[0] """ pop_amt = min(len(happy_edgeList), 10) if (pop_amt <= 0): break student_pair = happy_edgeList.pop(random.randint(0, pop_amt-1)) #print("num assigend students: ", len(assigned_students)) #print("student_pair: ", student_pair) #print("happy val: ", G_copy.edges[student_pair]["happiness"]) student0 = student_pair[0] student1 = student_pair[1] #Check if students have been assigned student0_assigned = (student0 in assigned_students) student1_assigned = (student1 in assigned_students) #If students are already assigned (whether in same or diff room), go to next happiest pair if (student0_assigned and student1_assigned): #print("here0") continue #Check which room the students are in, if they have already been asigned to a room room_of_student0 = -1 room_of_student1 = -1 for room in room_to_students: if student0 in room_to_students[room]: room_of_student0 = room if student1 in room_to_students[room]: room_of_student1 = room #If student0 assigned, try to put student1 in same room, else put in room that causes least stress if (student0_assigned): #print("here1") room_to_students[room_of_student0] += [student1] assigned_students += [student1] valid0 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (valid0): continue #Can't put student1 in same room, so try to put in diff room room_to_students[room_of_student0].remove(student1) assigned_students.remove(student1) min_stress1 = float('inf') min_room1 = -1 for room in room_to_students: room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress1 = utils.calculate_stress_for_room(room_to_students[room], G) #check if solution is valid when adding students to this room valid1 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress1 < min_stress1 and valid1): min_stress1 = temp_stress1 min_room1 = room room_to_students[room].remove(student1) if (min_room1 >= 0): room_to_students[min_room1] += [student1] assigned_students += [student1] else: # at this point, student1 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so try opening more rooms #print("I got here2, assigned_students = ", assigned_students) break #continue #If student1 assigned, try to put student0 in same room, else put in room that causes least stress if (student1_assigned): #print("here2") room_to_students[room_of_student1] += [student0] assigned_students += [student0] valid1 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (valid1): continue #Can't put student1 in same room, so try to put in diff room room_to_students[room_of_student1].remove(student0) assigned_students.remove(student0) min_stress0 = float('inf') min_room0 = -1 for room in room_to_students: room_to_students[room] += [student0] #check if adding students to this room causes minimum stress (disruption?) temp_stress0 = utils.calculate_stress_for_room(room_to_students[room], G) #check if solution is valid when adding students to this room valid0 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress0 < min_stress0 and valid0): min_stress0 = temp_stress0 min_room0 = room room_to_students[room].remove(student0) if (min_room0 >= 0): room_to_students[min_room0] += [student0] assigned_students += [student0] else: # at this point, student1 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so try opening more rooms #print("I got here4, assigned_students = ", assigned_students) break #continue if (not student1_assigned and not student0_assigned): #print("here5") #If neither student assigned, put both into the breakout room that creates least stress #If putting them into a breakout room together always creates invalid solution, consider putting them into seperate rooms min_stress = float('inf') min_room = -1 for room in room_to_students: room_to_students[room] += [student0] room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress = utils.calculate_stress_for_room(room_to_students[room], G) #check if solution is valid when adding students to this room valid = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress < min_stress and valid): min_stress = temp_stress min_room = room room_to_students[room].remove(student0) room_to_students[room].remove(student1) if (min_room >= 0): room_to_students[min_room] += [student0] room_to_students[min_room] += [student1] assigned_students += [student0] assigned_students += [student1] continue #if putting students together in breakout room still causes excess stress, put them in diff rooms min_stress0 = float('inf') min_room0 = -1 for room in room_to_students: room_to_students[room] += [student0] #check if adding students to this room causes minimum stress (disruption?) temp_stress0 = utils.calculate_stress_for_room(room_to_students[room], G) #check if solution is valid when adding students to this room valid0 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress0 < min_stress0 and valid0): min_stress0 = temp_stress0 min_room0 = room room_to_students[room].remove(student0) min_stress1 = float('inf') min_room1 = -1 for room in room_to_students: room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress1 = utils.calculate_stress_for_room(room_to_students[room], G) #check if solution is valid when adding students to this room valid1 = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress1 < min_stress1 and valid1): min_stress1 = temp_stress1 min_room1 = room room_to_students[room].remove(student1) if (min_room1 >= 0): room_to_students[min_room1] += [student1] assigned_students += [student1] if (min_room0 >= 0): room_to_students[min_room0] += [student0] assigned_students += [student0] else: # at this point, student0 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so try opening more rooms #print("I got here, assigned_students = ", assigned_students) break #continue #print("here3") valid_sol = utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, i) happy = utils.calculate_happiness(utils.convert_dictionary(room_to_students), G) if (len(assigned_students) < len(list(G.nodes))): #print(room_to_students) happy = float('-inf') #print("room_to_students: ", room_to_students) print("happy for ", i, " rooms: ", happy) if (happy > max_happy and valid_sol): max_happy = happy room_to_students_to_return = {} for room in room_to_students: room_to_students_to_return[room] = room_to_students[room].copy() #print("here4") return room_to_students_to_return
def gamble_solve_with_greedy(G, s, i, limit=-1, reps=100): """ Gambles by randomly assigning students to rooms and checking optimality and stress levels Works specifically for input #1 type - can be modified by changin num_open_rooms to randint - can be modified adding checks before h > best_h to check stress_max val per room Methods to use: - random_assign(students, rooms, limit_per_room = -1): """ students = list(G.nodes) #num_open_rooms = int(math.ceil(len(students)/2)) best_h = -1 best_rooms = [] count = 0 while (count < reps): rooms = [] for _ in range(i): rooms.append([]) temp_students = students.copy() rooms = random_assign(temp_students, rooms, limit) room_to_students = utils.convert_list_to_dictionary(rooms) G_copy = nx.Graph(G) assigned_students = [i+1 for i in range(50)] happy_dict = {} happy_edgeList = [] #sorted(G_copy.edges, key=lambda x: G_copy.edges[x]["happiness"], reverse = True) happy_edgeList = greedy_solver_2.remove_students_greedy(G, G_copy, s, room_to_students, happy_dict, assigned_students, happy_edgeList) #ToDo: Modify greedy_2 to take in optional parameters of rooms, other stuff thats initialized @ start room_to_students = greedy_solver_2.greedy_solve_2(G, s, assigned_students, room_to_students, happy_edgeList) dict = utils.convert_dictionary(room_to_students) valid = utils.is_valid_solution(dict, G, s, num_open_rooms) h = utils.calculate_happiness(dict, G) if ((valid) and (h > best_h)): best_rooms = [] room_temp = rooms.copy() for i in range(len(rooms)): best_rooms += [rooms[i].copy()] best_h = h #elif (not valid): #count = count - 1 count = count + 1 return best_rooms.copy(), best_h
def remove_students_greedy(G, G_copy, s, room_to_students, value_dict, assigned_students, value_edgeList, alpha, beta): # Check which rooms exceed stress limit #print("in remove_students_greedy") counter = 0 while True: #print("here: ", counter) room_numbers_that_exceed_stress = [] for room in room_to_students: s_room = utils.calculate_stress_for_room(room_to_students[room], G) if (s_room >= (s / (len(room_to_students))) ): #ToDo: should this be i or i+1? Think of 50 room case room_numbers_that_exceed_stress += [room] # From the rooms that exceed stress limit, remove students until all stress limit not exceeded removed_students = [] for room in room_numbers_that_exceed_stress: s_room = utils.calculate_stress_for_room(room_to_students[room], G) while (s_room >= (s / (len(room_to_students)))): min_stress = float("inf") student_to_remove = -1 for i in range(len(room_to_students[room])): student = room_to_students[room].pop(i) if (utils.calculate_stress_for_room( room_to_students[room], G) < min_stress): min_stress = utils.calculate_stress_for_room( room_to_students[room], G) student_to_remove = student room_to_students[room].insert(i, student) room_to_students[room].remove(student_to_remove) removed_students += [student_to_remove] s_room = utils.calculate_stress_for_room( room_to_students[room], G) for i in range(len(removed_students) - 1): for j in range(i + 1, len(removed_students)): edge = (removed_students[i], removed_students[j]) if (edge[0] == edge[1]): continue #print(edge) value_edgeList += [edge] val = alpha * G_copy.edges[edge][ "happiness"] - beta * G_copy.edges[edge]["happiness"] if val in value_dict: value_dict[val] += [edge] else: value_dict[val] = [] value_dict[val] += [edge] value_edgeList = sorted( value_edgeList, key=lambda x: alpha * G_copy.edges[x][ "happiness"] - beta * G_copy.edges[x]["happiness"], reverse=True) for student in removed_students: assigned_students.remove(student) #open another room if (len(room_to_students) < 50): room_to_students[len(room_to_students)] = [] counter += 1 if (utils.is_valid_solution(utils.convert_dictionary(room_to_students), G, s, len(room_to_students))): #print("why you always breakin") #print("This is valid? wyd: ", room_to_students) #print("How did you get this kinda happiness?: ", utils.calculate_happiness(utils.convert_dictionary(room_to_students), G)) #print("Did you assign everyone tho: ", assigned_students) #print("Did you assign everyone tho pt 2: ", len(assigned_students)) break #print("done with remove_students_greedy") return value_edgeList
def greedy_solve_5(G, s, alpha, beta, pop_limit=5): """ Probably open 1 room, add as many possible students w/o exceeding stress level, then if s_level exceeded, remove students that cause most stress, open 2 room, repeat - Remember to sort students (or sort edgelist or somt) and break ties by happiness - Will probably need algo to determine which student causes most stress in given room Helpful Utils: - utils.calculate_stress_for_room(arr, G) """ #Iterate by opening 1 breakout room at a time, up to n breakout rooms room_to_students_to_return = {} max_happy = -1 assigned_students = [] i = 1 room_to_students = {} for j in range(i): room_to_students[j] = [] #print("room_to_students: ", room_to_students) #Make copy of graph (so we can use actual graph later on as reference) G_copy = nx.Graph(G) #Create edgeList pairs of students sorted by stress/happiness stress_edgeList = sorted(G_copy.edges, key=lambda x: G_copy.edges[x]["stress"]) happy_edgeList = sorted(G_copy.edges, key=lambda x: G_copy.edges[x]["happiness"], reverse=True) value_edgeList = sorted(G_copy.edges, key=lambda x: alpha * G_copy.edges[x]["happiness"] - beta * G_copy.edges[x]["stress"], reverse=True) #Todo: Maybe sort/solve based on some values/prioerities i.e. a * happy - b * stress, a & b can be constants passed in or randInts #dictionary of happiness values to list of all students that have same happiness value value_dict = {} for edge in value_edgeList: #print("edge: ", edge) #print("happiness: ", G_copy.edges[edge]["happiness"]) val = alpha * G_copy.edges[edge]["happiness"] - beta * G_copy.edges[ edge]["stress"] if val in value_dict: value_dict[val] += [edge] else: value_dict[val] = [] value_dict[val] += [edge] while (len(assigned_students) < len(list(G.nodes))): stress_edgeList = sorted(stress_edgeList, key=lambda x: G_copy.edges[x]["stress"], reverse=True) happy_edgeList = sorted(happy_edgeList, key=lambda x: G_copy.edges[x]["happiness"], reverse=True) value_edgeList = sorted( G_copy.edges, key=lambda x: alpha * G_copy.edges[x][ "happiness"] - beta * G_copy.edges[x]["stress"], reverse=True) #dictionary of happiness values to list of all students that have same happiness value value_dict = {} for edge in value_edgeList: #print("edge: ", edge) #print("happiness: ", G_copy.edges[edge]["happiness"]) val = alpha * G_copy.edges[edge][ "happiness"] - beta * G_copy.edges[edge]["stress"] if val in value_dict: value_dict[val] += [edge] else: value_dict[val] = [] value_dict[val] += [edge] #Assign students until all pairings are broken or assigned (i.e. all students in rooms) while (len(assigned_students) < len(list(G.nodes))): #Take happiest pair and try to assign them to rooms to maximize happiness #print(happy_dict) student_pair = None """ for key in sorted(happy_dict.keys()): #print("key: ", key) #print("happy_dict[key]: ", happy_dict[key]) if (len(happy_dict[key]) > 0): student_pair = random.sample(happy_dict[key], 1) #print(student_pair[0]) happy_dict[key].remove(student_pair[0]) #student_pair = happy_edgeList.pop(0) # No more student pairs – shouldn't really hit this point tho?? if (not student_pair): print("here") #for key in sorted(happy_dict.keys()): #print("key: ", key) #if (len(happy_dict[key]) > 0): #print("happy_dict[key]: ", happy_dict[key]) break student_pair = student_pair[0] """ #Todo: Does this always pick happiest? pop_amt = min(len(value_edgeList), pop_limit) if (pop_amt <= 0): break #print("assigned_students: ", assigned_students) #print("room_to_students: ", room_to_students) #print("happy_edgeList: ", happy_edgeList) student_pair = value_edgeList.pop(random.randint( 0, pop_amt - 1)) # ToDo: Maybe increase this value to 5 - 10? #print("num assigend students: ", len(assigned_students)) #print("student_pair: ", student_pair) #print("happy val: ", G_copy.edges[student_pair]["happiness"]) student0 = student_pair[0] student1 = student_pair[1] #Check if students have been assigned student0_assigned = (student0 in assigned_students) student1_assigned = (student1 in assigned_students) #If students are already assigned (whether in same or diff room), go to next happiest pair if (student0_assigned and student1_assigned): #print("here0") continue #Check which room the students are in, if they have already been asigned to a room room_of_student0 = -1 room_of_student1 = -1 for room in room_to_students: if student0 in room_to_students[room]: room_of_student0 = room if student1 in room_to_students[room]: room_of_student1 = room #If student0 assigned, try to put student1 in same room, else put in room that causes least stress if (student0_assigned): #print("here1") #print("room_of_student0: ", room_of_student0) room_to_students[room_of_student0] += [student1] assigned_students += [student1] valid0 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (valid0): continue #Can't put student1 in same room, so try to put in diff room room_to_students[room_of_student0].remove(student1) assigned_students.remove(student1) min_stress1 = float('inf') min_room1 = -1 for room in room_to_students: room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress1 = utils.calculate_stress_for_room( room_to_students[room], G) #check if solution is valid when adding students to this room valid1 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress1 < min_stress1 and valid1): min_stress1 = temp_stress1 min_room1 = room room_to_students[room].remove(student1) if (min_room1 >= 0): room_to_students[min_room1] += [student1] assigned_students += [student1] else: # at this point, student1 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so try opening more rooms #print("I got here2, assigned_students = ", assigned_students) #break value_edgeList = remove_students_greedy( G, G_copy, s, room_to_students, value_dict, assigned_students, value_edgeList, alpha, beta) continue #If student1 assigned, try to put student0 in same room, else put in room that causes least stress if (student1_assigned): #print("here2") #print("room_of_student1: ", room_of_student1) room_to_students[room_of_student1] += [student0] assigned_students += [student0] valid1 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (valid1): continue #Can't put student1 in same room, so try to put in diff room room_to_students[room_of_student1].remove(student0) assigned_students.remove(student0) min_stress0 = float('inf') min_room0 = -1 for room in room_to_students: room_to_students[room] += [student0] #check if adding students to this room causes minimum stress (disruption?) temp_stress0 = utils.calculate_stress_for_room( room_to_students[room], G) #check if solution is valid when adding students to this room valid0 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress0 < min_stress0 and valid0): min_stress0 = temp_stress0 min_room0 = room room_to_students[room].remove(student0) if (min_room0 >= 0): room_to_students[min_room0] += [student0] assigned_students += [student0] else: # at this point, student1 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so try opening more rooms #print("I got here4, assigned_students = ", assigned_students) #break value_edgeList = remove_students_greedy( G, G_copy, s, room_to_students, value_dict, assigned_students, value_edgeList, alpha, beta) continue if (not student1_assigned and not student0_assigned): #print("here5") #If neither student assigned, put both into the breakout room that creates least stress #If putting them into a breakout room together always creates invalid solution, consider putting them into seperate rooms min_stress = float('inf') min_room = -1 for room in room_to_students: room_to_students[room] += [student0] room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress = utils.calculate_stress_for_room( room_to_students[room], G) #check if solution is valid when adding students to this room valid = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress < min_stress and valid): min_stress = temp_stress min_room = room room_to_students[room].remove(student0) room_to_students[room].remove(student1) if (min_room >= 0): room_to_students[min_room] += [student0] room_to_students[min_room] += [student1] assigned_students += [student0] assigned_students += [student1] continue #if putting students together in breakout room still causes excess stress, put them in diff rooms min_stress0 = float('inf') min_room0 = -1 for room in room_to_students: room_to_students[room] += [student0] #check if adding students to this room causes minimum stress (disruption?) temp_stress0 = utils.calculate_stress_for_room( room_to_students[room], G) #check if solution is valid when adding students to this room valid0 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress0 < min_stress0 and valid0): min_stress0 = temp_stress0 min_room0 = room room_to_students[room].remove(student0) min_stress1 = float('inf') min_room1 = -1 for room in room_to_students: room_to_students[room] += [student1] #check if adding students to this room causes minimum stress (disruption?) temp_stress1 = utils.calculate_stress_for_room( room_to_students[room], G) #check if solution is valid when adding students to this room valid1 = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, i) if (temp_stress1 < min_stress1 and valid1): min_stress1 = temp_stress1 min_room1 = room room_to_students[room].remove(student1) if (min_room1 >= 0): room_to_students[min_room1] += [student1] assigned_students += [student1] if (min_room0 >= 0): room_to_students[min_room0] += [student0] assigned_students += [student0] else: #continue # at this point, student0 cant be assigned to any room without causing excess stress, # so this solution/number of breakout rooms cannot work, so remove students # that cause stress level to exceed room stress level, put them back into # happiness edgelist and dictionary, and then continue from there value_edgeList = remove_students_greedy( G, G_copy, s, room_to_students, value_dict, assigned_students, value_edgeList, alpha, beta) #print("I got here, assigned_students = ", assigned_students) #break continue #print("here3") valid_sol = utils.is_valid_solution( utils.convert_dictionary(room_to_students), G, s, len(room_to_students)) happy = utils.calculate_happiness( utils.convert_dictionary(room_to_students), G) if (len(assigned_students) < len(list(G.nodes))): #print(room_to_students) happy = float('-inf') #print("room_to_students: ", room_to_students) #print("room_to_students: ", room_to_students) #print("happy: ", happy) if (happy > max_happy and valid_sol): max_happy = happy room_to_students_to_return = {} for room in room_to_students: room_to_students_to_return[room] = room_to_students[room].copy( ) elif (not valid_sol): value_edgeList = remove_students_greedy( G, G_copy, s, room_to_students, value_dict, assigned_students, value_edgeList, alpha, beta) #elif ((happy < max_happy) and (len(room_to_students) < 50)): #happy_dict = remove_students_greedy(G, G_copy, s, room_to_students, happy_dict, assigned_students, happy_edgeList) #else: #break if (len(value_edgeList) <= 0): break #print("here4") print("happy for ", len(room_to_students), " rooms: ", max_happy) return room_to_students_to_return
def solve(G, s): """ Args: G: networkx.Graph s: stress_budget Returns: D: Dictionary mapping for student to breakout room r e.g. {0:2, 1:0, 2:1, 3:2} k: Number of breakout rooms """ # we are originally starting k off as 1, we will continually add groups until we have a valid assignment num_groups = 1 stress_limit = s / num_groups curr_room = 0 room_to_student = {0: []} students_left = [] # initially, all students are still left unmatched num_students = G.order() for i in range(num_students): students_left.append(i) while students_left: room = room_to_student[curr_room] if not room: # current room is empty best_pair = find_best_pair(G, students_left, stress_limit) if best_pair == -1: # there exist no pairs that satisfy the current stress limit, cannot form any more groups for student in students_left: room_to_student[curr_room] = [student] students_left.remove(student) curr_room += 1 num_groups = len(room_to_student) curr_room = num_groups - 1 else: # there exists a best pair that satisfies the current stress limit students_left.remove(best_pair[0]) students_left.remove(best_pair[1]) room.append(best_pair[0]) room.append(best_pair[1]) else: # current room is not empty new_member = find_best_addition(G, students_left, stress_limit, room) if new_member == -1: # we cannot add anyone to the current group num_groups += 1 stress_limit = s / num_groups curr_room += 1 for i in range(len(room_to_student)): trim_group(G, students_left, stress_limit, room_to_student[i]) room_to_student[curr_room] = [] else: # we can add someone to the current group room.append(new_member) students_left.remove(new_member) return convert_dictionary(room_to_student), curr_room + 1, room_to_student