def trim_group(G, students_left, stress_limit, group): curr_stress = calculate_stress_for_room(group, G) while (curr_stress > stress_limit): best_removal = 0 removed = group[0] for x in range(len(group)): student = group[x] group.remove(student) happiness = calculate_happiness_for_room(group, G) stress = calculate_stress_for_room(group, G) if stress == 0: removed = student group.append(student) break if ((happiness / stress) > best_removal): best_removal = happiness / stress removed = student # print("best_removal: " + str(best_removal)) # print("removed: " + str(removed)) group.append(student) group.remove(removed) students_left.append(removed) curr_stress = calculate_stress_for_room(group, G)
def findopt(G_new, G, s, groups, curr_stress): """ mutates the networkx graphs 'G' and 'groups', and returns the increase in total stress. """ students = G_new.number_of_nodes() max_value = 0 merge_nodes = ('a', 'a') # Check all edges, find the best one to merge new_stress_capacity = s / (groups.number_of_nodes() - 1 ) # new stress capacity if a # merge is made remaining_stress = new_stress_capacity - curr_stress for edge in list(G_new.edges): i = edge[0] j = edge[1] if G_new.get_edge_data(i, j) is not None: edge_happiness = G_new.get_edge_data(i, j)['happiness'] edge_stress = G_new.get_edge_data(i, j)['stress'] if edge_stress <= remaining_stress: value = heuristic(edge_stress, edge_happiness, remaining_stress) if value > max_value: max_value = value merge_nodes = (i, j) else: continue # Calculate the increase in stress i, j = merge_nodes[0], merge_nodes[1] if i == 'a' or j == 'a': return 'done' old_stress = calculate_stress_for_room(groups.nodes[i]['ppl'], G) copy = groups.copy() copy.nodes[i]['ppl'] += copy.nodes[j]['ppl'] if calculate_stress_for_room(copy.nodes[i]['ppl'], G) > G.number_of_nodes() \ / s: return 0 else: groups.nodes[i]['ppl'] += groups.nodes[j]['ppl'] groups.remove_node(j) new_stress = calculate_stress_for_room(groups.nodes[i]['ppl'], G) # Merge the 2 nodes from chosen edge, update G l1 = list(G_new.edges(i)) l1.remove((i, j)) l2 = list(G_new.edges(j)) l2.remove((j, i)) n = len(l1) for i in range(n): G_new.get_edge_data(l1[i][0], l1[i][1])['happiness'] += \ G_new.get_edge_data(l2[i][0], l2[i][1])['happiness'] G_new.get_edge_data(l1[i][0], l1[i][1])['stress'] += \ G_new.get_edge_data(l2[i][0], l2[i][1])['stress'] G_new.remove_node(j) return 0
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 """ g_new = G.copy() groups = nx.Graph() # Graph to store groupings of students for i in range(G.number_of_nodes()): groups.add_node(i, ppl=[i]) curr_stress = 0 # Total stress from room assignment max_stress, remaining_stress = s, s while remaining_stress >= 0: # While remaining stress is greater than 0 curr_stress = findopt(g_new, G, s, groups, curr_stress) if curr_stress == 'done': break for node in list(groups.nodes): curr_stress += calculate_stress_for_room(groups.nodes[node]['ppl'], G) max_stress = s / groups.number_of_nodes() remaining_stress = max_stress - curr_stress k = groups.number_of_nodes() # Convert the groupings into a dictionary d = dict() nodes = list(groups.nodes) for i in range(k): for student in groups.nodes[nodes[i]]['ppl']: d[student] = i d = dict(sorted(d.items(), key=lambda x: x[0])) return d, k
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 """ D = {} for i in G.nodes: D[i] = 0 rooms = 1 while not is_valid_solution(D, G, s, rooms): # print(rooms) for i in range(rooms): people_in_room_i = [ person for person in D.keys() if D[person] == i ] while calculate_stress_for_room(people_in_room_i, G) > s / rooms: person_to_take_out = people_in_room_i[random.randrange( 0, len(people_in_room_i) - 1, 1)] D[person_to_take_out] = i + 1 if (i + 1) > rooms - 1: rooms = rooms + 1 people_in_room_i.remove(person_to_take_out) return D, rooms
def solve_naive(G, s): vertex_list = list(G.nodes) N = len(vertex_list) best_happiness = 0 config = {} numRooms = 0 for n, p in enumerate(partition(list(range(20))), 1): isValid = True for room in p: if calculate_stress_for_room(room, G) > s / len(p): isValid = False break print(n) if not isValid: continue D = {} for i in range(len(p)): for j in p[i]: D[j] = i happiness = calculate_happiness(D, G) if happiness > best_happiness: best_happiness = happiness config = D numRooms = len(p) return config, numRooms
def solve_greedy(G, s): vertex_list = list(G.nodes) N = len(vertex_list) # iterate through all possible values of number of rooms for k in range(1, N+1): solution = {} # key:value => (vertex, room) room_to_vertices = {} # key:value => (room number, vertices) # Assume all vertices are on their own for i in range(len(vertex_list)): solution[i] = i room_to_vertices[i] = [i] edges = sorted(G.edges(data=True), key = sortOrder, reverse = True) # edges = sorted(G.edges(data=True), key=lambda t: t[2].get('happiness'), reverse = True) # sort by highest happiness for e in edges: # get current room numbers room_v = solution[e[0]] room_u = solution[e[1]] # see if the pair is already in the same room if room_u == room_v: continue # attempt to merge room merged_room = room_to_vertices[room_v] + room_to_vertices[room_u] # if it does not satisfy stress constraints, abort if calculate_stress_for_room(merged_room, G) > s / k: continue # actually merge for v in room_to_vertices[room_u]: solution[v] = room_v room_to_vertices[room_v] = merged_room room_to_vertices.pop(room_u) # print(calculate_happiness(solution, G)) # check to see if we should update if the constraint on the # of rooms is satisfied; if so, return the result if len(room_to_vertices) <= k: result = {} length = len(room_to_vertices) for i in range(length): vertices = room_to_vertices.pop(list(room_to_vertices.keys())[0]) for v in vertices: result[v] = i return result, length
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 """ # TODO: your code here! D = {} rooms = {} k = G.number_of_nodes() for i in range(G.number_of_nodes()): D[i] = i rooms[i] = [i] changed = [] for i in range(G.number_of_nodes()-2): for j in range(G.number_of_nodes()): if j in list(rooms): max_happy = 0 min_stress = s / (len(rooms) - 1) curr_min_stress = min_stress reee = 0 for asdf in list(G[j]): if calculate_stress_for_room(rooms[D[j]] + [asdf], G) < min_stress and (calculate_stress_for_room(rooms[D[j]] + [asdf], G) < curr_min_stress or calculate_happiness_for_room(rooms[D[j]] + [asdf], G) > max_happy): max_happy = calculate_happiness_for_room(rooms[D[j]] + [asdf], G) curr_min_stress = calculate_stress_for_room(rooms[D[j]] + [asdf], G) reee = asdf if reee and reee not in changed: changed.append(reee) D[reee] = j rooms[j].append(reee) del rooms[reee] return D, len(rooms)
def move(index): room = rooms[index] # if room satisfies stress requirement if calculate_stress_for_room(room, G) <= s / len(rooms): return # person to be removed kick = process(index) # remove person rooms[index].remove(kick) # create new room if necessary if index == len(rooms) - 1: rooms.append([]) # add person to new room rooms[index + 1].append(kick) # check next room for validity move(index + 1)
def find_best_addition(G, students_left, stress_limit, group): max_ratio = 0 max_addition = -1 for x in range(len(students_left)): group.append(students_left[x]) happiness = calculate_happiness_for_room(group, G) stress = calculate_stress_for_room(group, G) if stress == 0: return students_left[x] if (stress < stress_limit and (happiness / stress) > max_ratio): max_addition = students_left[x] max_ratio = happiness / stress # print(max_addition) # print(max_ratio) group.remove(students_left[x]) return max_addition
def solve(G, s, swap): """ 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! rooms = [list(G.nodes)] def move(index): room = rooms[index] # if room satisfies stress requirement if calculate_stress_for_room(room, G) <= s / len(rooms): return # person to be removed kick = process(index) # remove person rooms[index].remove(kick) # create new room if necessary if index == len(rooms) - 1: rooms.append([]) # add person to new room rooms[index + 1].append(kick) # check next room for validity move(index + 1) def process(index): r = rooms[index] ret = {} for i in r: ret[i] = 0 for j in r: if i == j: continue if swap == 0: ret[i] += G.edges[i,j]["happiness"] - G.edges[i,j]["stress"] elif swap == 1: ret[i] += G.edges[i,j]["happiness"] else: ret[i] -= G.edges[i,j]["stress"] return min(ret, key = lambda x: ret[x]) finished = False while not finished: finished = True for i in range(len(rooms)): room = rooms[i] if calculate_stress_for_room(room, G) > s / len(rooms): move(i) finished = False break D = {} for i in range(len(rooms)): r = rooms[i] for n in r: D[n] = i k = len(rooms) ret = D max_happiness = calculate_happiness(ret, G) improved = True # print("before", max_happiness) # def search_local(depth): # nonlocal D # nonlocal k # nonlocal improved # nonlocal max_happiness # nonlocal ret # if depth == 0: # return # for i in D: # for j in D: # if i == j: # continue # D[i], D[j] = D[j], D[i] # kkk = len(set(D.values())) # if is_valid_solution(D, G, s, kkk): # happy = calculate_happiness(D, G) # if happy > max_happiness: # k = kkk # max_happiness = happy # ret = {} # for key in D: # ret[key] = D[key] # improved = True # search_local(depth - 1) # D[i], D[j] = D[j], D[i] # temp, D[i] = D[i], D[j] # kkk = len(set(D.values())) # if is_valid_solution(D, G, s, kkk): # happy = calculate_happiness(D, G) # if happy > max_happiness: # k = kkk # max_happiness = happy # ret = {} # for key in D: # ret[key] = D[key] # improved = True # search_local(depth - 1) # D[i] = temp while improved: improved = False # search_local(2) # D = ret for i in D: for j in D: if i == j: continue D[i], D[j] = D[j], D[i] kkk = len(set(D.values())) if is_valid_solution(D, G, s, kkk): if calculate_happiness(D, G) > max_happiness: max_happiness = calculate_happiness(D, G) ret = {} for key in D: ret[key] = D[key] improved = True k = kkk D[i], D[j] = D[j], D[i] temp, D[i] = D[i], D[j] kkk = len(set(D.values())) if is_valid_solution(D, G, s, kkk): if calculate_happiness(D, G) > max_happiness: max_happiness = calculate_happiness(D, G) ret = {} for key in D: ret[key] = D[key] improved = True k = kkk D[i] = temp D = ret # print("after:", max_happiness) return ret, k, max_happiness
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 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
# assert len(sys.argv) == 2 # path = sys.argv[1] # G, s = read_input_file(path) # D, k = solve(G, s) # assert is_valid_solution(D, G, s, k) # print("Total Happiness: {}".format(calculate_happiness(D, G))) # write_output_file(D, 'outputs/small-1.out') # For testing a folder of inputs to create a folder of outputs, you can use glob (need to import it) if __name__ == '__main__': inputs = glob.glob('inputs/*') for input_path in inputs: print(input_path) output_path = 'outputs/' + basename(normpath(input_path))[:-3] + '.out' G, s = read_input_file(input_path) D, k, room_to_student = solve(G, s) print() print(room_to_student) print("# of rooms: " + str(k)) print("stress limit: " + str(s / k)) for i in range(k): print( str(i) + ": " + str(calculate_stress_for_room(room_to_student[i], G))) print() assert is_valid_solution(D, G, s, k) happiness = calculate_happiness(D, G) write_output_file(D, output_path)
def solve_helper(G, s, ratio_num, happiness_num, stress_num): """ 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 """ N = len(G.nodes()) # another idea: get the best edges for each person, and iterate through some of them to connect together for k in range(5, N+1): G_copy = copy.deepcopy(G) i = 0 # room counter solution = {} # key:value => (vertex, room) while True: if i == k: break v = choice(list(G_copy.nodes())) # if len(G_copy.nodes()) == 1: # v = list(G_copy.nodes())[0] # else: # edges = sorted(G_copy.edges(data=True), key = sortOrder, reverse = True) # v = edges[0][0] best_ratios = sorted(G_copy.edges(v, data = True), key = sortOrder, reverse = True)[:ratio_num] highest_happiness = sorted(G_copy.edges(v, data=True), key=lambda t: t[2].get('happiness'), reverse = True)[:happiness_num] lowest_stress = sorted(G_copy.edges(v, data=True), key=lambda t: t[2].get('stress'))[:stress_num] # best_ratios_vertices = [] # highest_happiness_vertices = [] # lowest_stress_vertices = [] # if len(best_ratios) != 0: best_ratios_vertices = set([i[1] for i in best_ratios]) # if len(highest_happiness) != 0: highest_happiness_vertices = set([i[1] for i in highest_happiness]) # if len(lowest_stress) != 0: lowest_stress_vertices = set([i[1] for i in lowest_stress]) vertices = best_ratios_vertices.union(highest_happiness_vertices).union(lowest_stress_vertices) subsets = findsubsets(vertices) best_merged_room = [v] largest_happiness = 0 for subset in subsets: merged_room = [v] for vertex in subset: merged_room.append(vertex) # if it does not satisfy stress constraints, abort if calculate_stress_for_room(merged_room, G) > s / k: continue happiness = calculate_happiness_for_room(merged_room, G) if happiness > largest_happiness: largest_happiness = happiness best_merged_room = merged_room for v in best_merged_room: solution[v] = i i += 1 G_copy.remove_nodes_from(best_merged_room) if not G_copy.nodes(): return solution, i