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 read_output_file(path, G, s): """ Parses and validates an output file :param path: str, a path :param G: the input graph corresponding to this output :return: networkx Graph is the output is well formed, AssertionError thrown otherwise """ with open(path, "r") as fo: nodes = set() rooms = set() D = {} lines = fo.read().splitlines() fo.close() for line in lines: tokens = line.split() assert len(tokens) == 2 #validate node node = int(tokens[0]) assert tokens[0].isdigit() and 0 <= node < len(G) nodes.add(node) #validate rooms room = int(tokens[1]) assert tokens[0].isdigit() and 0 <= room < len(G) rooms.add(room) D[node] = room assert len(nodes) == len(G) assert utils.is_valid_solution(D, G, s, len(rooms)) return D
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(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 """ if G.size(weight='stress') <= s: return {t: 0 for t in list(G.nodes)}, 1 max_happiness = 0.0 best_d = {} for node in list(G.nodes): best_d[node] = node # Write out every single solution. Check each solution's validity. If valid, compute happiness. n = len(list(G.nodes)) for a in range(n): for b in range(n): for c in range(n): for d in range(n): for e in range(n): for f in range(n): for g in range(n): for h in range(n): for i in range(n): for j in range(n): sol = { 0: a, 1: b, 2: c, 3: d, 4: e, 5: f, 6: g, 7: h, 8: i, 9: j } k = len(set(sol.values())) if is_valid_solution(sol, G, s, k): happy = calculate_happiness( sol, G) if happy > max_happiness: max_happiness = happy best_d = sol print(max_happiness) return best_d, len(set(best_d.values()))
def repeatedly_solve(path): G, s = read_input_file("inputs/" + path + ".in") solutions = [] happiness = [] for i in range(5): D, k = solve_helper(G, s, 12, 0, 0) assert is_valid_solution(D, G, s, k) # write_output_file(D, "outputs_manual/" + str(path) + "_ratio_" + str(i) + ".out") solutions.append(D) happiness.append(calculate_happiness(D, G)) print("i'm done with 5 only ratio") for i in range(5): D, k = solve_helper(G, s, 0, 12, 0) assert is_valid_solution(D, G, s, k) # write_output_file(D, "outputs_manual/" + str(path) + "_happiness_" + str(i) + ".out") solutions.append(D) happiness.append(calculate_happiness(D, G)) print("i'm done with 5 only happiness") for i in range(5): D, k = solve_helper(G, s, 0, 0, 12) assert is_valid_solution(D, G, s, k) # write_output_file(D, "outputs_manual/" + str(path) + "_stress_" + str(i) + ".out") solutions.append(D) happiness.append(calculate_happiness(D, G)) print("i'm done with 5 only stress") for i in range(5): D, k = solve_helper(G, s, 5, 5, 5) assert is_valid_solution(D, G, s, k) # write_output_file(D, "outputs_manual/" + str(path) + "_all_3_" + str(i) + ".out") solutions.append(D) happiness.append(calculate_happiness(D, G)) print("i'm done with 5 all 3") print(happiness) max_happiness = max(happiness) best_index = 0 print(max_happiness) for i in range(20): if happiness[i] == max_happiness: best_index = i print(best_index) write_output_file(solutions[best_index], "out_manual/" + str(path) + ".out")
def single_file(lol): path = 'inputs/small/small-' + str(lol) + '.in' # path = 'test.in' # path = 'inputs/medium/medium-' + str(lol) + '.in' # path = 'inputs/large/large-' + str(lol) + '.in' G = read_input_file(path) print(G.nodes) # c, k = solve2(G) c, k = solve2(G) assert is_valid_solution(G, c, k) print("Shortest Path Difference: {}".format(calculate_score(G, c, k))) write_output_file(G, c, k, 'small-test.out')
def use_greedy_happystress(G, s): best = {} i = 1 while i <= len(G.nodes): G_cop = G.copy() possible = greedy_happystress(G, G_cop, s, i) if is_valid_solution(possible, G, s, i) and not list(G_cop.nodes): if not best or calculate_happiness(best, G) < calculate_happiness( possible, G): best = possible i += 1 return best
def main(): already_done = [ 1, 2, 4, 6, 7, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 26, 29, 30, 33, 34, 35, 38, 39, 40, 41, 43, 46, 47, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 63, 64, 70, 73, 74, 76, 77, 79, 81, 83, 84, 85, 88, 89, 90, 96, 100, 101, 103, 105, 109, 110, 111, 112, 113, 114, 115, 117, 119, 121, 122, 123, 125, 128, 129, 131, 132, 134, 136, 137, 140, 141, 143, 145, 147, 151, 152, 156, 157, 158, 159, 160, 161, 162, 166, 167, 169, 172, 174, 175, 177, 178, 181, 184, 187, 196, 199, 201, 202, 203, 206, 207, 208, 209, 213, 216, 217, 218, 220, 222, 223, 226, 227, 230, 233, 235, 237, 238, 240, 241 ] # already_done = [7, 18, 33, 43, 51, 54, 56, 65, 69, 73, 77, 81, 91, 112, 114, 121, 123, 127, 131, 134, 151, 169, 171, 174, 178, 184, 187, 201, 202, 207, 213, 215, 222] """ inputs = glob.glob('compinputslarge/*') couldnt = [] done = 0 for i in range(len(inputs)): input_path = inputs[i] done += 1 print("doing #" + str(done) + ": " + input_path) output_path = 'comp2large/' + basename(normpath(input_path))[:-3] + '.out' G, s = read_input_file(input_path) D, k = solve(G, s) if k != -1: assert is_valid_solution(D, G, s, k) write_output_file(D, output_path) # print("done, used " + str(k) + " rooms") else: couldnt += [input_path] """ num = int(sys.argv[1]) moves = int(sys.argv[2]) print("Doing #" + str(num)) if num not in already_done: input_path = "compinputsmed/medium-" + str(num) + ".in" current_sol_path = "comp1med/medium-" + str(num) + ".out" output_path = "comp2med/medium-" + str(num) + ".out" G, s = read_input_file(input_path) D, k = solve(G, s, load=current_sol_path, moves=moves) if k != -1: assert is_valid_solution(D, G, s, k) write_output_file(D, output_path)
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 dfs(curAssignment, numAssigned, numRooms): nonlocal bestAssignment, bestNumRooms, bestScore # End early if timed out and return best solution if timeoutInSeconds and time.time() > start + timeoutInSeconds: return -1 # Ignore assignments with more than "numStudents" rooms. if numRooms >= numStudents: return 0 # If all students are assigned check if assignment is better if numAssigned >= numStudents: curScore = calculate_happiness(curAssignment, G) if curScore > bestScore: bestAssignment = copy.deepcopy(curAssignment) bestNumRooms = numRooms bestScore = curScore return 0 # Go through all possible room assignments for the next student for room in range(numRooms + 1): curAssignment[numAssigned] = room newNumRooms = max(numRooms, room + 1) # # Check if assignment is valid so far # roomAssignments = {} # for i in range(numAssigned + 1): # curRoom = curAssignment[i] # if curRoom not in roomAssignments: # roomAssignments[curRoom] = [i] # else: # roomAssignments[curRoom].append(i) # # maxRoomStress = s / newNumRooms # isValid = True # print(roomAssignments) # for breakoutRoom in roomAssignments: # isValid &= maxRoomStress < calculate_stress_for_room(breakoutRoom, G) if is_valid_solution(curAssignment, G, s, newNumRooms): dfs(curAssignment, numAssigned + 1, newNumRooms) del curAssignment[numAssigned]
def solve(G): """ Args: G: networkx.Graph Returns: c: list of cities to remove k: list of edges to remove """ random.seed(datetime.now()) iterations = 0 best_c, best_k = [], [] if len(list(G.nodes)) <= 30: iterations = 500 elif len(list(G.nodes)) <= 50: iterations = 200 elif len(list(G.nodes)) <= 100: iterations = 15 first_time, best_score, is_medium_or_large = True, 0.0, False for i in range(iterations): m = 0 t = len(list(G.nodes)) - 1 if len(list(G.nodes)) <= 30: max_k, max_c, m = 15, 1, 100 elif len(list(G.nodes)) <= 50: max_k, max_c, m = 50, 3, 100 is_medium_or_large = True elif len(list(G.nodes)) <= 100: max_k, max_c, m = 100, 5, 500 is_medium_or_large = True else: max_k, max_c = 0, 0 c, k, m, max_c, max_k, first_time = helper(G, m, t, max_c, max_k, first_time, is_medium_or_large) first_time = False if is_valid_solution(G, c, k, t): curr_score = calculate_score(G, c, k, t) if curr_score > best_score: best_score = curr_score best_c, best_k = c, k print("END") return best_c, best_k
def solve(G, s): max_happiness = 0.0 best_sol = {} num_students = len(list(G.nodes)) for num_rooms in range(1, num_students + 1): all_sols = construct_sol(list(range(num_students)), num_rooms) for sol in all_sols: k = len(set(sol.values())) if is_valid_solution(sol, G, s, k): happy = calculate_happiness(sol, G) if happy > max_happiness: max_happiness = happy best_sol = sol print(max_happiness) return best_sol, len(set(best_sol.values()))
def check(size): output = "smallresult.txt" output = size + "result.txt" print(output, file=open(output, "w")) directory = "small/" directory = size + "/" for filename in os.listdir(directory): #print(filename) if (filename.endswith(".in")): file = filename[:-3] inpath = os.path.join(directory, file + ".in") outpath = os.path.join(directory, file + ".out") G, s = parse.read_input_file(inpath) x = parse.read_output_file(outpath, G, s) uniqueValues = set(x.values()) k = len(uniqueValues) valid = utils.is_valid_solution(x, G, s, k) if (valid == False): print("false output @", file) break happy = utils.calculate_happiness(x, G) print(file, "\tyields", happy, file=open(output, "a"))
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 remove_c(G, c, V): ret = [] nodes = list(G.nodes()) nodes.remove(0) nodes.remove(V - 1) #ret has node while len(ret) < c: temp = -1 curr = -1 for j in nodes: H = G.copy() H.remove_node(j) if nx.is_connected(H): score = calculate_score(G, [j], []) if score > curr: temp = j curr = score if len(nodes) == 0 or temp == -1: return ret #print(temp) nodes.remove(temp) if is_valid_solution(G, ret + [temp], []): ret.append(temp) return ret
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! rooms = {} numRooms = 1 used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} edgeCount = 0 maxHap = 0 maxRooms = {} maxNumRooms = 1 # for i in G.edges(data=True): # print (i[2]) # edges = list(G.edges(data=True)) # edges.sort(key=lambda x: x[2]["happiness"], reverse=True) # while used < G.number_of_nodes(): # edges[edgeCount] # # print(len(list(G.edges))) # print(temp) # for perm in itertools.permutations([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]): # for i in range(500): # perm = np.random.permutation(50) # currRoom = 0 # for student in perm: # # # while numRooms <= 50: # # studentsPerRoom = 50 // numRooms # # studentCountPerRoom = 0 # # currRoom = 0 # # for student in perm: # rooms[student] = currRoom # studentCountPerRoom += 1 # if studentCountPerRoom >= studentsPerRoom: # studentCountPerRoom = 0 # currRoom += 1 # if is_valid_solution(rooms, G, s, numRooms): # temp = calculate_happiness(rooms, G) # if temp > maxHap: # maxHap = temp # maxRooms = rooms # maxNumRooms = numRooms # print(perm, temp) # rooms = {} # numRooms += 1 # # print(perm, maxHap) # rooms = {} # numRooms = 1 numRooms = 1 for student in range(10): rooms[student] = 0 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} numRooms = 2 for i in range(1, 10): for comb in itertools.combinations(used, i): for student in comb: rooms[student] = 0 used.remove(student) for student in used: rooms[student] = 1 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} numRooms = 3 for i in range(1, 10): for comb1 in itertools.combinations(used, i): for student in comb1: rooms[student] = 0 used.remove(student) rooms1 = dict(rooms) used1 = set(used) for j in range(1, 10-i): for comb2 in itertools.combinations(used, j): for student in comb2: rooms[student] = 1 used.remove(student) for student in used: rooms[student] = 2 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = dict(rooms1) used = set(used1) rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} numRooms = 4 for i in range(1, 10): for comb1 in itertools.combinations(used, i): for student in comb1: rooms[student] = 0 used.remove(student) rooms1 = dict(rooms) used1 = set(used) for j in range(1, 10-i): for comb2 in itertools.combinations(used, j): for student in comb2: rooms[student] = 1 used.remove(student) rooms2 = dict(rooms) used2 = set(used) for k in range(1, 10-i-j): for comb3 in itertools.combinations(used, k): for student in comb3: rooms[student] = 2 used.remove(student) for student in used: rooms[student] = 3 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = dict(rooms2) used = set(used2) rooms = dict(rooms1) used = set(used1) rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} if maxHap == 0: numRooms = 5 for i in range(1, 10): for comb1 in itertools.combinations(used, i): for student in comb1: rooms[student] = 0 used.remove(student) rooms1 = dict(rooms) used1 = set(used) for j in range(1, 10-i): for comb2 in itertools.combinations(used, j): for student in comb2: rooms[student] = 1 used.remove(student) rooms2 = dict(rooms) used2 = set(used) for k in range(1, 10-i-j): for comb3 in itertools.combinations(used, k): for student in comb3: rooms[student] = 2 used.remove(student) rooms3 = dict(rooms) used3 = set(used) for l in range(1, 10-i-j-k): for comb4 in itertools.combinations(used, l): for student in comb4: rooms[student] = 3 used.remove(student) for student in used: rooms[student] = 4 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = dict(rooms3) used = set(used3) rooms = dict(rooms2) used = set(used2) rooms = dict(rooms1) used = set(used1) rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} if maxHap == 0: numRooms = 6 for i in range(1, 10): for comb1 in itertools.combinations(used, i): for student in comb1: rooms[student] = 0 used.remove(student) rooms1 = dict(rooms) used1 = set(used) for j in range(1, 10-i): for comb2 in itertools.combinations(used, j): for student in comb2: rooms[student] = 1 used.remove(student) rooms2 = dict(rooms) used2 = set(used) for k in range(1, 10-i-j): for comb3 in itertools.combinations(used, k): for student in comb3: rooms[student] = 2 used.remove(student) rooms3 = dict(rooms) used3 = set(used) for l in range(1, 10-i-j-k): for comb4 in itertools.combinations(used, l): for student in comb4: rooms[student] = 3 used.remove(student) rooms4 = dict(rooms) used4 = set(used) for m in range(1, 10-i-j-k-l): for comb5 in itertools.combinations(used, m): for student in comb5: rooms[student] = 4 used.remove(student) for student in used: rooms[student] = 5 if is_valid_solution(rooms, G, s, numRooms): temp = calculate_happiness(rooms, G) if temp > maxHap: maxHap = temp maxRooms = dict(rooms) maxNumRooms = numRooms rooms = dict(rooms4) used = set(used4) rooms = dict(rooms3) used = set(used3) rooms = dict(rooms2) used = set(used2) rooms = dict(rooms1) used = set(used1) rooms = {} used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} # if maxHap == 0: # numRooms = 7 # for i in range(1, 10): # for comb1 in itertools.combinations(used, i): # for student in comb1: # rooms[student] = 0 # used.remove(student) # rooms1 = dict(rooms) # used1 = set(used) # for j in range(1, 10-i): # for comb2 in itertools.combinations(used, j): # for student in comb2: # rooms[student] = 1 # used.remove(student) # rooms2 = dict(rooms) # used2 = set(used) # for k in range(1, 10-i-j): # for comb3 in itertools.combinations(used, k): # for student in comb3: # rooms[student] = 2 # used.remove(student) # rooms3 = dict(rooms) # used3 = set(used) # for l in range(1, 10-i-j-k): # for comb4 in itertools.combinations(used, l): # for student in comb4: # rooms[student] = 3 # used.remove(student) # rooms4 = dict(rooms) # used4 = set(used) # for m in range(1, 10-i-j-k-l): # for comb5 in itertools.combinations(used, m): # for student in comb5: # rooms[student] = 4 # used.remove(student) # rooms5 = dict(rooms) # used5 = set(used) # for n in range(1, 10-i-j-k-l-m): # for comb6 in itertools.combinations(used, n): # for student in comb6: # rooms[student] = 5 # used.remove(student) # for student in used: # rooms[student] = 6 # if is_valid_solution(rooms, G, s, numRooms): # temp = calculate_happiness(rooms, G) # if temp > maxHap: # maxHap = temp # maxRooms = dict(rooms) # maxNumRooms = numRooms # rooms = dict(rooms5) # used = set(used5) # rooms = dict(rooms4) # used = set(used4) # rooms = dict(rooms3) # used = set(used3) # rooms = dict(rooms2) # used = set(used2) # rooms = dict(rooms1) # used = set(used1) # rooms = {} # used = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} # for dict in dicts: # if is_valid_solution(dict[0], G, s, dict[1]): # temp = calculate_happiness(dict[0], G) # if temp > maxHap: # maxHap = temp # maxRooms = dict[0] # maxNumRooms = dict[1] # print(maxRooms, maxNumRooms) return (maxRooms, maxNumRooms)
return result # 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/*') solved = 0 defaulted = 0 for input_path in inputs: output_path = 'outputs/' + basename(normpath(input_path))[:-3] + '.out' G, s = read_input_file(input_path) n = len(G) best_sol, best_happiness = None, 0 for i in range(1, n + 1): D, k = solve(G, s, i) if len(D) == n and is_valid_solution(D, G, s, k): happiness = calculate_happiness(D, G) if happiness > best_happiness: best_sol = D else: continue if not best_sol: defaulted += 1 print("Was not able to solve {}".format(input_path)) best_sol = dummy_solution(n) write_output_file(best_sol, output_path) else: # Find highest happiness solution and write to file solved += 1 print("Successfully solved {}".format(input_path)) write_output_file(best_sol, output_path)
print(G.nodes) # c, k = solve2(G) c, k = solve2(G) assert is_valid_solution(G, c, k) print("Shortest Path Difference: {}".format(calculate_score(G, c, k))) write_output_file(G, c, k, 'small-test.out') if __name__ == '__main__': # single_file(62) for i in range(1, 301): print("INPUT: ", i) path = 'inputs/medium/medium-' + str(i) + '.in' G = read_input_file(path) c, k = solve2(G) assert is_valid_solution(G, c, k) print("Shortest Path Difference: {}".format(calculate_score(G, c, k))) output_path = 'outputs/medium-' + str(i) + '.out' write_output_file(G, c, k, output_path) # 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: # output_path = 'outputs/' + basename(normpath(input_path))[:-3] + '.out' # G = read_input_file(input_path) # c, k = solve(G) # assert is_valid_solution(G, c, k) # distance = calculate_score(G, c, k) # write_output_file(G, c, k, output_path)
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
for i in range(1, 243): path = 'inputs/medium/medium-' path += str(i) path += '.in' try: test = open(path, 'r') test.close() except: continue G, s = read_input_file(path) #D, k = complete_solve(G, s) # D, k = solve(G, s) D1, k1, h1 = solve(G, s, 0) D2, k2, h2 = solve(G, s, 1) D3, k3, h3 = solve(G, s, 2) assert is_valid_solution(D1, G, s, k1) assert is_valid_solution(D2, G, s, k2) assert is_valid_solution(D3, G, s, k3) best = max([h1, h2, h3]) if h1 == best: D = D1 elif h2 == best: D = D2 elif h3 == best: D = D3 print("Total Happiness: {}".format(calculate_happiness(D, G))) out_path = 'out/' out_path += path.split('/')[-2] out_path += '/' out_path += path.split('/')[-1] out_path = out_path.split('.')[0]
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 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 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
output_path = 'outputs/medium/' + basename(normpath(input_path))[:-3] + '.out' G = read_input_file(input_path) num_nodes = G.number_of_nodes() num_edges = G.number_of_edges() if 20 <= num_nodes <= 30: MAX_EDGES_REMOVED = 15 MAX_NODES_REMOVED = 1 elif 31 <= num_nodes <= 50: MAX_EDGES_REMOVED = 50 MAX_NODES_REMOVED = 3 elif 51 <= num_nodes <= 100: MAX_EDGES_REMOVED = 100 MAX_NODES_REMOVED = 5 resultc, resultk, largest = None, None, 0 for i in range(5): c, k = solve(G) if not is_valid_solution(G, c, k): continue currentScore = calculate_score(G, c, k) if largest < currentScore: resultc, resultk = c, k largest = currentScore existingSol = read_output_file(G, output_path) if largest > existingSol: write_output_file(G, resultc, resultk, output_path) print("enhanced by: " + str((largest - existingSol)/existingSol)) print(str(count) + " out of " +str(len(inputs)) + " Done.") count += 1
def helper(G, m, t, max_c, max_k, first_time, is_medium_or_large): c, k = [], [] if m <= 0: # if there's nothing else to remove, return return c, k, m, max_c, max_k, first_time if max_c <= 0 and max_k <= 0: return c, k, m, max_c, max_k, first_time m = m - 1 edges = list(G.edges) shortest_path_vertices = nx.dijkstra_path(G, 0, t) shortest_path_vertices_count = len(shortest_path_vertices) shortest_path_edges_weights = [] shortest_path_vertices_weights = [] sum_edges_weight = 0.0 sum_vertices_weight = 0.0 for i in range(shortest_path_vertices_count): if i + 1 < shortest_path_vertices_count: # Safety check for i+1 case for edges c1, k1 = [], [] k1.append( (shortest_path_vertices[i], shortest_path_vertices[i + 1])) if is_valid_solution( G, c1, k1, t): # Note this returns true when a node is disconnected edge_weight = G[shortest_path_vertices[i]][ shortest_path_vertices[i + 1]]['weight'] shortest_path_edges_weights.append( (shortest_path_vertices[i], shortest_path_vertices[i + 1], edge_weight)) if is_medium_or_large: sum_edges_weight += (edge_weight / 100.0) * (edge_weight / 100.0) else: sum_edges_weight += edge_weight # Looping through edges in Dijkstras to get edge weights + calculate heuristic v = shortest_path_vertices[i] if v == 0: continue if v == t: continue c2, k2 = [], [] c2.append(v) if not is_valid_solution( G, c2, k2, t): # Note this returns true when a node is disconnected continue vertex_weight, count = 0, 0 for edge in edges: if edge[0] == v or edge[1] == v: vertex_weight += G[edge[0]][edge[1]]['weight'] count += 1 if count > 0: if is_medium_or_large: vertex_weight = 0.01 * vertex_weight * 0.01 * vertex_weight else: vertex_weight = 0.9 * vertex_weight shortest_path_vertices_weights.append((v, vertex_weight)) sum_vertices_weight += vertex_weight if (max_k <= 0): sum_edges_weight = 0.0 if (max_c <= 0): sum_vertices_weight = 0.0 remove_edge = True r = (sum_edges_weight + sum_vertices_weight) * random.random() if (r < sum_vertices_weight): remove_edge = False s = 0 if max_k > 0 and remove_edge: rand_prob_edges = sum_edges_weight * random.random() for A, B, weight in shortest_path_edges_weights: s += weight G_copy = G.copy() if rand_prob_edges < s: G_copy.remove_edge(A, B) k.append((A, B)) max_k = max_k - 1 new_c, new_k, m, max_c, max_k, first_time = helper( G_copy, m, t, max_c, max_k, first_time, is_medium_or_large) c += new_c k += new_k break else: rand_prob_vertices = sum_vertices_weight * random.random() for A, weight in shortest_path_vertices_weights: s += weight G_copy = G.copy() if rand_prob_vertices < s: G_copy.remove_node(A) c.append(A) max_c = max_c - 1 new_c, new_k, m, max_c, max_k, first_time = helper( G_copy, m, t, max_c, max_k, first_time, is_medium_or_large) c += new_c k += new_k break return c, k, m, max_c, max_k, first_time
def solver_loop(input_dir="inputs", output_dir="outputs", input_type=None, team_number=None, max_timeout=None, target_delta=None): inputs = get_all_inputs(input_dir, input_type, team_number) to_run_heap = [] non_optimal_count = 0 total_gaps = 0 for input_path, max_cities, max_edges in inputs: cached = get_cached_run(input_path) if cached == None: heapq.heappush( to_run_heap, PrioritizedItem({ "in_path": input_path, "out_path": f"{output_dir}/" + input_path[6:][:-3] + '.out', "existing_solution": None, "max_cities": max_cities, "max_edges": max_edges, "last_timeout": 1, "is_optimal_new": False, "best_gap": 100, "gap_change": 0, "timeout_change": 0 })) non_optimal_count += 1 total_gaps += 100 elif ("is_optimal_new" not in cached) or (not cached["is_optimal_new"]): if "gap_change" not in cached: cached["gap_change"] = 0 if "timeout_change" not in cached: cached["timeout_change"] = cached["last_timeout"] / 2 if "is_optimal_new" not in cached: cached["is_optimal_new"] = False # if "known_nonoptimal" in cached and cached["known_nonoptimal"]: # cached["last_timeout"] = 60 heapq.heappush(to_run_heap, PrioritizedItem(cached)) non_optimal_count += 1 total_gaps += cached["best_gap"] else: total_gaps += 0 if target_delta: assert len(to_run_heap) == 1 while len(to_run_heap) > 0: next_task_wrap = heapq.heappop(to_run_heap) next_task = next_task_wrap.item if not next_task["is_optimal_new"]: G = read_input_file(next_task["in_path"]) next_timeout = next_task_wrap.estimated_timeout_to_complete if max_timeout: next_timeout = min(next_timeout, max_timeout) target_distance = None if target_delta: original_min_dist = networkx.dijkstra_path_length( G, 0, len(G) - 1) target_distance = original_min_dist + target_delta timeout_delta = next_timeout - next_task["last_timeout"] last_progress = next_task["gap_change"] in_path = next_task["in_path"] print() print() print( "-----------------------------------------------------------") print() print() print( f"Remaining non-optimal: {non_optimal_count}/{len(inputs)}, average gap: {(total_gaps / non_optimal_count) * 100:.2f}%" ) print( f"Running {in_path} with timeout {next_timeout}, last iteration progress {last_progress*100:.2f}%" ) print() solve_result = solve(G, next_task["max_cities"], next_task["max_edges"], next_timeout, next_task["existing_solution"], target_distance) prev_score = 0 if next_task["existing_solution"]: prev_score = calculate_score(G, next_task["existing_solution"][0], next_task["existing_solution"][1]) new_score = 0 if solve_result: assert is_valid_solution(G, solve_result[0], solve_result[1]) new_score = calculate_score(G, solve_result[0], solve_result[1]) better_result = solve_result and (new_score - prev_score) >= 0.0001 if better_result: write_output_file(G, solve_result[0], solve_result[1], next_task["out_path"]) print(f"Shortest Path Difference: {new_score}") if solve_result and solve_result[2]: non_optimal_count -= 1 new_gap = solve_result[3] if solve_result else 100 total_gaps -= next_task["best_gap"] total_gaps += new_gap if next_task["existing_solution"] and next_task[ "best_gap"] != 100 and new_gap > next_task["best_gap"]: orig_best = next_task["best_gap"] print( f"WARNING WARNING WARNING WARNING: new gap {new_gap} was larger than previous best gap {orig_best}" ) new_gap = orig_best if timeout_delta > 0 or better_result or ( new_gap > next_task["best_gap"] ) or "is_optimal_new" not in next_task: new_task = { "in_path": next_task["in_path"], "out_path": next_task["out_path"], "existing_solution": (solve_result[0], solve_result[1]) if solve_result and new_score > prev_score else next_task["existing_solution"], "max_cities": next_task["max_cities"], "max_edges": next_task["max_edges"], "last_timeout": next_timeout, "is_optimal_new": (not target_distance) and (solve_result != None) and solve_result[2], "best_gap": new_gap, "gap_change": new_gap - next_task["best_gap"] if (next_task["existing_solution"] and next_task["best_gap"] != 100) else 0, "timeout_change": max(timeout_delta, 0) } if "known_nonoptimal" in next_task and not better_result: new_task["known_nonoptimal"] = True write_cached_run(new_task["in_path"], new_task) if not new_task["is_optimal_new"]: heapq.heappush(to_run_heap, PrioritizedItem(new_task))
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
room += 1 D[25] = room D[31] = room room += 1 D[26] = room D[29] = room room += 1 D[27] = room D[49] = room room += 1 D[30] = room D[48] = room room += 1 D[32] = room D[38] = room room += 1 D[33] = room D[45] = room room += 1 D[35] = room D[36] = room room += 1 D[40] = room D[42] = room room += 1 k = len(set(D.values())) assert is_valid_solution(D, G, s, k) print("Total Happiness: {}".format(calculate_happiness(D, G))) output_path = "out/other/large-169.out" write_output_file(D, output_path)
i += 1 output_path_num = int( os.path.basename(os.path.normpath(input_path))[:-3].split("-")[1]) if output_path_num in blacklist: print("Skipping Blacklist Num...") continue G, s = read_input_file(input_path, 100) output_path = 'medium_outputs/' + os.path.basename( os.path.normpath(input_path))[:-3] + '.out' D = read_output_file(output_path, G, s) output_happiness = calculate_happiness(D, G) print("Current Happiness:", output_happiness) D_new, k_new, val_new = verify(G, s, output_happiness) print("Returned Happiness", val_new) if D_new and round(val_new, 3) > round(output_happiness, 3): new_happiness = calculate_happiness(D_new, G) print(new_happiness, val_new) assert round(new_happiness, 3) == round(val_new, 3) assert is_valid_solution(D_new, G, s, k_new) print("New Happiness Found:", new_happiness) print() write_output_file(D_new, output_path) redo.append(input_path) else: print("Could not improve happiness (already optimal)") print() print("Inputs Improved:", redo) print("TLE", tle)