def test_can_get_better_than_1(): preferences = read_instance(60, 25, 5, 0) file = "C:\\Users\\Sofia\\Documents\\level5project\\SRI_IP\\data\\outputs\\ASP\\almost-SRI\\output-almost-60-25.txt" solution = parse_answers(file)[4] better_options = can_get_better_than_current_partner( preferences, get_partners(solution), 41) assert set(better_options) == set([23])
def test_feasibility_checker(): for size in [40, 60, 80]: for density in [25, 50, 75, 100]: if size == 40 and density == 25: continue blocking_pairs = parse_blocking_pairs(size, density, True) answers = parse_answers( "C:\\Users\\Sofia\\Documents\\level5project\\SRI_IP\\data\\outputs\\ASP\\almost-SRI\\output-almost-%d-%d.txt" % (size, density)) if size == 40 and density == 50: answers = [None] + answers blocking_pairs = [None] + blocking_pairs for i, answer in enumerate(answers): # Known non-existing/weird answers if (size == 40 and density == 50 and i == 0) or (size == 60 and density == 25 and i == 19): continue preferences = read_instance(size, density, i + 1, 0) print(size, density, i + 1) feasibility = check_feasibility(preferences, answer) assert (not feasibility and not blocking_pairs[i]) or (set( feasibility[0]) == blocking_pairs[i])
def create_SRI(preferences, density=None, index=None, optimisation=OptimalityCriteria.NONE): if density is not None: if index is not None: preferences = read_instance(preferences, density, index) else: raise (ValueError("Too few arguments", preferences, density, index)) elif type(preferences) == type(""): preferences = read_instance(preferences) h = PreferenceHelper(preferences) m = Model("SRI") n = len(preferences) # Create the initial matching matrix x = m.addVars(n, n, vtype=GRB.BINARY) # \sum_{u \in N(v)} x_{u, v} <= 1 for each v \in V m.addConstrs( x.sum([u for u in h.get_neighbours(v)], v) <= 1 for v in range(n)) # x_{u, v} = 0 for each {u, v} \notin E m.addConstrs(x.sum(u, v) == 0 for u, v in h.get_non_edges()) #\sum_{i \in \{ N(u): i >_u v\}} x_{u, i} + #\sum_{j \in { N(v): i >_v u}} x_{v, j} + # x_{u, v} <= 1 for each {u, v} \in E if not optimisation == OptimalityCriteria.ALMOST_STABLE: m.addConstrs( x.sum(u, [i for i in h.get_preferred_neighbours(u, v)]) + x.sum([i for i in h.get_preferred_neighbours(v, u)], v) + x[u, v] >= 1 for u, v in h.get_edges()) # x_{u, v} = x_{v, u} for each {u, v} \notin E m.addConstrs(x[u, v] == x[v, u] for u in range(n) for v in range(n)) has_solution = True if optimisation == OptimalityCriteria.EGALITARIAN: # \sum_{u, v \in V} rank(u, v)x_{u,v} m.setObjective(x.prod(h.ranks)) elif optimisation == OptimalityCriteria.FIRST_CHOICE_MAXIMAL: # \sum_{u, v \in V} \delta^1(u,v)x_{u,v} m.setObjective(x.prod(h.delta(1)), GRB.MAXIMIZE) elif optimisation == OptimalityCriteria.RANK_MAXIMAL: for i in range(1, h.max_pref_length // 2 - 1): delta_i = h.delta(i) m.setObjective(x.prod(delta_i), GRB.MAXIMIZE) m.optimize() if not hasattr(m, "ObjVal"): has_solution = False break m.addConstr(x.prod(delta_i) >= m.ObjVal) m.setObjective(x.prod(h.delta(h.max_pref_length - 1)), GRB.MAXIMIZE) elif optimisation == OptimalityCriteria.GENEROUS: for i in range(h.max_pref_length, h.max_pref_length // 2, -1): delta_i = h.delta(i) m.setObjective(x.prod(delta_i)) m.optimize() if not hasattr(m, "ObjVal"): has_solution = False break m.addConstr(x.prod(delta_i) <= m.ObjVal) m.setObjective(x.prod(h.delta(1))) elif optimisation == OptimalityCriteria.ALMOST_STABLE: b = m.addVars(n, n, vtype=GRB.BINARY) m.addConstrs( x.sum(u, [i for i in h.get_preferred_neighbours(u, v)]) + x.sum([i for i in h.get_preferred_neighbours(v, u)], v) + x[u, v] + b[u, v] >= 1 for u, v in h.get_edges()) m.setObjective(b.sum()) elif optimisation != OptimalityCriteria.NONE: raise (ValueError("Unsupported criteria", optimisation)) return m
from GA import PRP_Genetic, genetic_algorithm_solver from utils import read_instance if __name__ == '__main__': random.seed(42) for instance_size in [100]: # for ref_cost in [578.7815538, 643.0906153]: for ref_cost in [2175.292804, 2619.790834]: results = {'time': [], 'result': [], 'fleet size': []} for i in range(1, 150): instance_name = "UK{}_01".format(instance_size) #config T7 instance = read_instance(inst_name=instance_name) prp = PRP_Genetic(instance) ngen = 1000 final_mutation_rate = 1 / instance_size mutation_rate_decay = (1 - final_mutation_rate) / ngen start = time.time() fitness_scores, best_chromosome, target_time = genetic_algorithm_solver(prp, population_size=100, ngen=ngen, crossover_rate_decay=1, mutation_rate_decay=mutation_rate_decay, route_mutation_rate=1, min_route_mutation_rate=1 / instance_size, speed_mutation_rate=1 / instance_size, elitism_rate=0.15, maintain_diversity=False,
from utils import read_instance if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( "--filename", type=str, default="instances/instance.txt", help="Filename with offline instance", ) parser.add_argument("--search", type=str, default="n", help="Apply search? [y|n]") args = parser.parse_args() a = Seating(*read_instance(args.filename)) start = time.time() seats, no_seat = a.greedy() print() print("Output (greedy) (2=person seated)") print(seats) print("Not seated", no_seat, "out of", a.totalpeople) print("Execution time %s" % (time.time() - start)) if no_seat > 0 and args.search == "y": print("Not everyone seated... Starting branch and bound search...") a = Seating(*read_instance(args.filename)) start = time.time() a.dfs() print("Execution time %s" % (time.time() - start))
def solve_SRI(preferences, density=None, index=None, optimisation=OptimalityCriteria.NONE): start_read_time = time.time_ns() start_total_time = start_read_time if density is not None: if index is not None: preferences = read_instance(preferences, density, index) else: raise (ValueError("Too few arguments", preferences, density, index)) elif type(preferences) == type(""): preferences = read_instance(preferences) h = PreferenceHelper(preferences) print("Readtime: " + str((time.time_ns() - start_read_time)) + " ns") start_build_time = time.time_ns() m = Model("SRI") n = len(preferences) # Create the initial matching matrix x = m.addVars(n, n, vtype=GRB.BINARY) # \sum_{u \in N(v)} x_{u, v} <= 1 for each v \in V m.addConstrs( x.sum([u for u in h.get_neighbours(v)], v) <= 1 for v in range(n)) # x_{u, v} = 0 for each {u, v} \notin E m.addConstrs(x.sum(u, v) == 0 for u, v in h.get_non_edges()) #\sum_{i \in \{ N(u): i >_u v\}} x_{u, i} + #\sum_{j \in { N(v): i >_v u}} x_{v, j} + # x_{u, v} <= 1 for each {u, v} \in E if not optimisation == OptimalityCriteria.ALMOST_STABLE: m.addConstrs( x.sum(u, [i for i in h.get_preferred_neighbours(u, v)]) + x.sum([i for i in h.get_preferred_neighbours(v, u)], v) + x[u, v] >= 1 for u, v in h.get_edges()) # x_{u, v} = x_{v, u} for each {u, v} \notin E m.addConstrs(x[u, v] == x[v, u] for u in range(n) for v in range(n)) has_solution = True if optimisation == OptimalityCriteria.EGALITARIAN: m.Params.BranchDir = -1 m.Params.Heuristics = 0 m.Params.PrePasses = 2 m.setObjective(x.prod(h.ranks)) elif optimisation == OptimalityCriteria.FIRST_CHOICE_MAXIMAL: m.Params.Heuristics = 0 m.Params.MIPFocus = 3 m.Params.NoRelHeurWork = 60 # \sum_{u, v \in V} \delta^1(u,v)x_{u,v} m.setObjective(x.prod(h.delta(1)), GRB.MAXIMIZE) elif optimisation == OptimalityCriteria.RANK_MAXIMAL: m.Params.ScaleFlag = 1 m.Params.Heuristics = 0 m.Params.BranchDir = 1 m.params.PrePasses = 5 m.Params.MIPFocus = 3 for i in range(1, h.max_pref_length - 1): delta_i = h.delta(i) m.setObjective(x.prod(delta_i), GRB.MAXIMIZE) m.optimize() if not hasattr(m, "ObjVal"): has_solution = False break m.addConstr(x.prod(delta_i) >= m.ObjVal) m.setObjective(x.prod(h.delta(h.max_pref_length - 1)), GRB.MAXIMIZE) elif optimisation == OptimalityCriteria.GENEROUS: m.Params.DegenMoves = 4 m.Params.Heuristics = 0 m.Params.PrePasses = 5 m.Params.BranchDir = -1 m.Params.MIPFocus = 2 for i in range(h.max_pref_length, 1, -1): delta_i = h.delta(i) m.setObjective(x.prod(delta_i)) m.optimize() if not hasattr(m, "ObjVal"): has_solution = False break m.addConstr(x.prod(delta_i) <= m.ObjVal) m.setObjective(x.prod(h.delta(1))) elif optimisation == OptimalityCriteria.ALMOST_STABLE: m.Params.NormAdjust = 0 m.Params.Heuristics = 0.001 m.Params.VarBranch = 1 m.Params.GomoryPasses = 15 m.Params.PreSparsify = 0 b = m.addVars(n, n, vtype=GRB.BINARY) m.addConstrs( x.sum(u, [i for i in h.get_preferred_neighbours(u, v)]) + x.sum([i for i in h.get_preferred_neighbours(v, u)], v) + x[u, v] + b[u, v] >= 1 for u, v in h.get_edges()) m.setObjective(b.sum()) elif optimisation != OptimalityCriteria.NONE: raise (ValueError("Unsupported criteria", optimisation)) print("Buildtime: " + str(time.time_ns() - start_build_time) + " ns") if has_solution: m.optimize() print("Totaltime: " + str((time.time_ns() - start_total_time)) + " ns") n = len(preferences) matches = set() if not hasattr(x[0, 0], "x"): return None for u in range(n): for v in range(n): if x[u, v].x > 0 and u < v: matches.add((u + 1, v + 1)) return matches
def make_and_solve_ILP(filename, optimized=False, configFile=""): """ Encodes and solves ILP """ # Prepare our problem instance cinema, people, ys, xs = read_instance(filename) # Filter all the people that cannot be seated. # This will mean less variables in our ILP problem people = filter_people(cinema, people) group_amount = int(np.sum([z for _, z in people.items()])) group_sizes = np.concatenate( [np.array(n * [i + 1], dtype=int) for i, n in people.items()]) max_group_size = np.max(group_sizes) people_amount = np.sum(group_sizes) print( group_amount, " groups with sizes: ", group_sizes, "total people waiting:", people_amount, ) start = time.time() # Collect legal positions per group size only once legals = dict() for size, amt in people.items(): if amt > 0: legals[size + 1] = find_legal_start_positions(size + 1, cinema) # Collect group sizes size_to_group = defaultdict(list) for i, group_size in enumerate(group_sizes): size_to_group[group_size].append(i) # sys.exit(0) print(size_to_group) # Instantiate a gurobi ILP model model = gp.Model() if not configFile == "": model.read(configFile) # Each group has a binary variable per possible seat seated = model.addVars(xs, ys, group_amount, vtype=GRB.BINARY, name="seated") # Every group has a constant size size = model.addVars( group_amount, lb=tuple(group_sizes), ub=tuple(group_sizes), vtype=GRB.INTEGER, name="groupsize", ) # Only one position per group for g in range(group_amount): model.addConstr( gp.quicksum( [seated[x, y, g] for x in range(xs) for y in range(ys)]), GRB.LESS_EQUAL, 1, ) # Check for non-seats and out-of-bounds groups # Do not seat a group when it will overlap with a 0-position/the end of the cinema for x in range(xs): for y in range(ys): for g in range(group_amount): # Loop over all positions from here to here + group_size any_zeros = False for i in range(0, group_sizes[g]): if x + i >= xs or cinema[y, x + i] == 0: any_zeros = True break # If any positions were zero, the starting position was illegal if any_zeros: model.addConstr(seated[x, y, g], GRB.EQUAL, 0) if optimized: for size1 in tqdm(range(1, max_group_size + 1)): for size2 in range(1, max_group_size + 1): # Look for all illegal combinations # Start with every possible position where g1 can be seated using the legals dictionary for (y1, x1) in legals[size1]: # Calculate illegal seats for g2 given this start position invalid_seats = get_invalid_seats(x1, y1, size1, size2, xs, ys) # Add a constraint, only one group can be seated in this area (<= 1) for (x2, y2) in invalid_seats: # For every combination of groups with these specific sizes for g1 in size_to_group[size1]: for g2 in size_to_group[size2]: if g1 != g2: model.addConstr( seated[x1, y1, g1] + seated[x2, y2, g2], GRB.LESS_EQUAL, 1, ) else: # For every combination of groups g1, g2 for g1 in tqdm(range(group_amount)): for g2 in range(group_amount): if g1 > g2: size1 = group_sizes[g1] size2 = group_sizes[g2] for (y1, x1) in legals[size1]: # Calculate illegal seats for g2 given this start position invalid_seats = get_invalid_seats( x1, y1, size1, size2, xs, ys) # Add a constraint, only one group can be seated in this area (<= 1) for (x2, y2) in invalid_seats: model.addConstr( seated[x1, y1, g1] + seated[x2, y2, g2], GRB.LESS_EQUAL, 1, ) del invalid_seats # TODO: Add more constraints that will help fastness of solver # Maximize number of people seated = seated_g * group_size_g # TODO: Set objective maximum manually to help gurobi. model.setObjective( gp.quicksum([ seated[x, y, g] * size[g] for x in range(xs) for y in range(ys) for g in range(group_amount) ]), GRB.MAXIMIZE, ) constraintTime = time.time() - start print("DONE ENCODING IN %s seconds.. STARTING OPTIMIZATION... " % (time.time() - start)) start = time.time() model.optimize() optimizeTime = time.time() - start # Get the solution solution = cinema.copy() for x in range(xs): for y in range(ys): for g in range(group_amount): if seated[x, y, g].x > 0: solution[y, x:x + group_sizes[g]] = np.zeros(group_sizes[g]) + 2 print(cinema) print("--- Was solved in %s seconds ---" % (time.time() - start)) print(solution) print("Not seated", people_amount - count_seated(solution), "out of", people_amount) valid = verify_cinema(solution, xs, ys) return (filename, configFile, constraintTime, optimizeTime, group_amount, people_amount, valid, people_amount - count_seated(solution))
def test_verifier(): preferences = read_instance(40, 50, 2, 0) file = "C:\\Users\\Sofia\\Documents\\level5project\\SRI_IP\\data\\outputs\\ASP\\almost-SRI\\output-almost-40-50.txt" solution = parse_answers(file)[0] blocking_pairs = get_blocking_pairs(preferences, solution) assert set(blocking_pairs) == set()
def test_verifier(): preferences = read_instance(60, 25, 5, 0) file = "C:\\Users\\Sofia\\Documents\\level5project\\SRI_IP\\data\\outputs\\ASP\\almost-SRI\\output-almost-60-25.txt" solution = parse_answers(file)[4] blocking_pairs = get_blocking_pairs(preferences, solution) assert set(blocking_pairs) == set([(41, 23), (23, 41)])