def test_knapsack(solver: str): p = [10, 13, 18, 31, 7, 15] w = [11, 15, 20, 35, 10, 33] c, I = 47, range(len(w)) m = Model("knapsack", solver_name=solver) x = [m.add_var(var_type=BINARY) for i in I] m.objective = maximize(xsum(p[i] * x[i] for i in I)) m += xsum(w[i] * x[i] for i in I) <= c, "cap" m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 41 m.constr_by_name("cap").rhs = 60 m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 51 # modifying objective function m.objective = m.objective + 10 * x[0] + 15 * x[1] assert abs(m.objective.expr[x[0]] - 20) <= 1e-10 assert abs(m.objective.expr[x[1]] - 28) <= 1e-10
def create_mip(solver, J, dur, S, c, r, EST, relax=False, sense=MINIMIZE): """Creates a mip model to solve the RCPSP""" NR = len(c) mip = Model(solver_name=solver) sd = sum(dur[j] for j in J) vt = CONTINUOUS if relax else BINARY x = [ { t: mip.add_var("x(%d,%d)" % (j, t), var_type=vt) for t in range(EST[j], sd + 1) } for j in J ] TJ = [set(x[j].keys()) for j in J] T = set() for j in J: T = T.union(TJ[j]) if sense == MINIMIZE: mip.objective = minimize(xsum(t * x[J[-1]][t] for t in TJ[-1])) else: mip.objective = maximize(xsum(t * x[J[-1]][t] for t in TJ[-1])) # one time per job for j in J: mip += xsum(x[j][t] for t in TJ[j]) == 1, "selTime(%d)" % j # precedences for (u, v) in S: mip += ( xsum(t * x[v][t] for t in TJ[v]) >= xsum(t * x[u][t] for t in TJ[u]) + dur[u], "prec(%d,%d)" % (u, v), ) # resource usage for t in T: for ir in range(NR): mip += ( xsum( r[ir][j] * x[j][tl] for j in J[1:-1] for tl in TJ[j].intersection( set(range(t - dur[j] + 1, t + 1)) ) ) <= c[ir], "resUsage(%d,%d)" % (ir, t), ) return mip
def test_linexpr_x(solver: str, val: int): m = Model("bounds", solver_name=solver) x = m.add_var(lb=0, ub=2 * val) y = m.add_var(lb=val, ub=2 * val) obj = x - y assert obj.x is None # No solution yet. m.objective = maximize(obj) m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == val assert round(x.x) == 2 * val assert round(y.x) == val # Check that the linear expression value is equal to the same expression # calculated from the values of the variables. assert abs((x + y).x - (x.x + y.x)) < TOL assert abs((x + 2 * y).x - (x.x + 2 * y.x)) < TOL assert abs((x + 2 * y + x).x - (x.x + 2 * y.x + x.x)) < TOL assert abs((x + 2 * y + x + 1).x - (x.x + 2 * y.x + x.x + 1)) < TOL assert abs((x + 2 * y + x + 1 + x / 2).x - (x.x + 2 * y.x + x.x + 1 + x.x / 2)) < TOL
def optimal_split(self, ratio=0.5): """Function that returns the optimal split for a certain ratio of the potential (default to 0.5) Keyword Arguments: ratio {float} -- The ratio of the potential needed (default: {0.5}) Returns: list tuple -- Returns the tuple (A, B) representing the partitions. """ if (sum(self.game_state) == 1): if (randint(1, 100) <= 50): return self.game_state, [0] * (self.K + 1) else: return [0] * (self.K + 1), self.game_state else: m = Model("") x = [m.add_var(var_type=INTEGER) for i in self.game_state] m.objective = minimize( sum([ 2**(-(self.K - i)) * c for c, i in zip(x, range(self.K + 1)) ]) - ratio * self.potential(self.game_state)) for i in range(len(x)): m += 0 <= x[i] m += x[i] <= self.game_state[i] m += sum([ 2**(-(self.K - i)) * c for c, i in zip(x, range(self.K + 1)) ]) >= ratio * self.potential(self.game_state) m.optimize() Abis = [0] * (self.K + 1) for i in range(len(x)): Abis[i] = int(x[i].x) B = [z - a for z, a in zip(self.game_state, Abis)] return Abis, B
def min_unproportionality_allocation(utilities: Dict[int, List[float]], m: Model) -> None: """ Computes (one of) the item allocation(s) which minimizes global unproportionality (observe we only sum unproportionality when it is larger than 0). :param utilities: the dictionary representing the utility profile, where each key is an agent and its value an array of floats such that the i-th float is the utility of the i-th item for the key-agent. :param m: the MIP model to optimize. :return: a dictionary mapping to each agent the bundle which has been assigned to her so that unproportionality is minimized. """ agents, items = len(utilities), len(list(utilities.values())[0]) dummies = [ m.add_var(name='dummy_{}'.format(agent), var_type=CONTINUOUS) for agent in range(agents) ] m.objective = minimize( xsum( m.var_by_name('dummy_{}'.format(agent)) for agent in range(agents))) for agent in range(agents): m += m.var_by_name('dummy_{}'.format(agent)) >= 0 m += m.var_by_name('dummy_{}'.format(agent)) >= (sum(utilities[agent][item] for item in range(items)) / agents)\ - (sum(utilities[agent][item] * m.var_by_name('assign_{}_{}'.format(item ,agent)) for item in range(items))) m.optimize()
def _add_opt_goal( m: Model, v_list: List[Vertex], v2var_x: Dict[Vertex, Var], v2var_y1: Dict[Vertex, Var], v2var_y2: Dict[Vertex, Var], ) -> None: # add optimization goal all_edges = get_all_edges(v_list) e2cost_var = {e: m.add_var(var_type=INTEGER, name=f'intra_{e.name}') for e in all_edges} # note pos is different from slot_idx, becasue the x dimension is different from the y dimention # we will use |(y1 * 2 + y1) - (y2 * 2 + y2)| + |x1 - x2| to express the hamming distance pos_y = lambda v : v2var_y1[v] * 2 + v2var_y2[v] pos_x = lambda v : v2var_x[v] cost_y = lambda e : pos_y(e.src) - pos_y(e.dst) cost_x = lambda e : pos_x(e.src) - pos_x(e.dst) for e, cost_var in e2cost_var.items(): m += cost_var >= cost_y(e) + cost_x(e) m += cost_var >= -cost_y(e) + cost_x(e) m += cost_var >= cost_y(e) - cost_x(e) m += cost_var >= -cost_y(e) - cost_x(e) m.objective = minimize(xsum(cost_var * e.width for e, cost_var in e2cost_var.items() ) )
def do_matching(graph, visualize=True): print("Starting model") weights = dict() graph = {int(key): graph[key] for key in graph} E = set() V = graph.keys() for v in V: original = v for u, weight in graph[original]: s, t = (u, v) if u < v else (v, u) edge = (s, t) E.add(edge) weights[original, u] = weight if visualize: graph = nx.Graph() graph.add_nodes_from(V) graph.add_edges_from(E) nx.draw_kamada_kawai(graph) plt.show() model = Model("Maximum matching") edge_vars = {e: model.add_var(var_type=BINARY) for e in E} for v in V: model += xsum(edge_vars[s, t] for s, t in E if v in [s, t]) <= 1 model.objective = maximize( xsum( xsum(((weights[edge] + weights[edge[1], edge[0]]) / 2) * edge_vars[edge] for edge in E) for edge in E)) model.optimize(max_seconds=300) return sorted([e for e in E if edge_vars[e].x > .01])
def _add_opt_goal(self, m: Model, v2var: Dict[str, Var], direction: Dir) -> None: """ minimize the weighted sum over all edges """ edge_list = get_all_edges(list(self.curr_v2s.keys())) e2cost_var = { e: m.add_var(var_type=INTEGER, name=f'e_cost_{e.name}') for e in edge_list } def _get_loc_after_partition(v: Vertex): if direction == Dir.vertical: return self.curr_v2s[v].getQuarterPositionX( ) + v2var[v] * self.curr_v2s[v].getHalfLenX() elif direction == Dir.horizontal: return self.curr_v2s[v].getQuarterPositionY( ) + v2var[v] * self.curr_v2s[v].getHalfLenY() else: assert False for e, cost_var in e2cost_var.items(): m += cost_var >= _get_loc_after_partition( e.src) - _get_loc_after_partition(e.dst) m += cost_var >= _get_loc_after_partition( e.dst) - _get_loc_after_partition(e.src) m.objective = minimize( xsum(cost_var * e.width for e, cost_var in e2cost_var.items()))
def solve(active: list, centers: list, sets: list, M: int) -> list: N, K = len(active), len(sets) ### model and variables m = Model(sense=MAXIMIZE, solver_name=CBC) # whether the ith set is picked x = [m.add_var(name=f"x{i}", var_type=BINARY) for i in range(K)] # whether the ith point is covered y = [m.add_var(name=f"y{i}", var_type=BINARY) for i in range(N)] ### constraints m += xsum(x) == M, "number_circles" for i in range(N): # if yi is covered, at least one set needs to have it included = [x[k] for k in range(K) if active[i] in sets[k]] m += xsum(included) >= y[i], f"inclusion{i}" ### objective: maximize number of circles covered m.objective = xsum(y[i] for i in range(N)) m.emphasis = 2 # emphasize optimality m.verbose = 1 status = m.optimize() circles = [centers[i] for i in range(K) if x[i].x >= 0.99] covered = {active[i] for i in range(N) if y[i].x >= 0.99} return circles, covered
def ilp(prods, n_prods, alpha): S1, S2, S3, S4 = segregate(prods, n_prods, alpha) x = np.array([0.0 for i in range(n_prods)]) d = 0 for prod in S1: x[prod.index] = 1 d = d + (prod.q - alpha) rev = [-1.0 for i in range(n_prods)] qdiff = [-1.0 for i in range(n_prods)] for prod in S2: ind = prod.index rev[ind] = prod.r qdiff[ind] = prod.q - alpha for prod in S3: ind = prod.index rev[ind] = prod.r qdiff[ind] = prod.q - alpha m = Model('ilp') m.verbose = False y = [m.add_var(var_type=BINARY) for i in range(n_prods)] m.objective = maximize(xsum(rev[i] * y[i] for i in range(n_prods))) m += xsum(qdiff[i] * y[i] for i in range(n_prods)) >= -1 * d m.optimize() selected = np.array([y[i].x for i in range(n_prods)]) import pdb pdb.set_trace() selected = np.floor(selected + 0.01) import pdb pdb.set_trace() return x + selected, d
def mip_optimization(cal_df, y, constrain=3, daily_weights=None): """Mixed integer linear programming optimization with constraints. Args: y (numpy.ndarray): sum of daily features (dim=#ofdays) constrain (int): minimum days in office daily_weights (array): weighting of days, e.g. if you prefer to come on mondays Return: """ # daily weighting u = np.ones(len(y)) if daily_weights == None else daily_weights I = range(len(y)) # idx for days for summation m = Model("knapsack") # MIP model w = [m.add_var(var_type=BINARY) for i in I] # weights to optimize m.objective = maximize(xsum(y[i] * w[i] for i in I)) # optimization function m += xsum(w[i] * u[i] for i in I) <= constrain # constraint m.optimize() #selected = [i for i in I if w[i].x >= 0.99] selected = [w[i].x for i in I] df = pd.DataFrame(columns=["home_office"], index=cal_df.index, data={'home_office': selected}) return df
def add_opt_goal(self, m: Model, fifo_to_paths: Dict[Edge, List[RoutingPath]], path_to_var: Dict[RoutingPath, Var]) -> None: """ minimize the total length * width of all selected paths """ # concatenate to get all paths all_paths: List[RoutingPath] = sum(fifo_to_paths.values(), []) m.objective = minimize( xsum(path_to_var[path] * path.get_cost() for path in all_paths))
def knapsack(): p = [10, 13, 18, 31, 7, 15] w = [11, 15, 20, 35, 10, 33] c, I = 47, range(len(w)) m = Model("knapsack") x = [m.add_var(var_type=BINARY) for i in I] m.objective = maximize(xsum(p[i] * x[i] for i in I)) m += xsum(w[i] * x[i] for i in I) <= c print(m.optimize())
def do_matching_stable(graph, visualize=True, individual=1, communal=10000000): print("Starting model") weights = dict() graph = {int(key): graph[key] for key in graph} E = set() V = graph.keys() inputs = {v: [] for v in V} outputs = {v: [] for v in V} for v in V: original = v for u, weight in graph[original]: s, t = (u, v) if u < v else (v, u) edge = (s, t) E.add(edge) weights[(original, u)] = weight outputs[original].append(u) inputs[u].append(original) if visualize: graph = nx.Graph() graph.add_nodes_from(V) graph.add_edges_from(E) nx.draw_kamada_kawai(graph) plt.show() model = Model("Rogue Couples based") edge_vars = {e: model.add_var(var_type=BINARY) for e in E} undirected = dict() for e in E: undirected[e] = edge_vars[e] undirected[e[1], e[0]] = edge_vars[e] rogue_vars = {e: model.add_var(var_type=BINARY) for e in E} partners = dict() for v in V: partners[v] = model.add_var() partners[v] = xsum(edge_vars[s, t] for s, t in E if v in [s, t]) model += partners[v] <= 1 for (u, v), rogue_var in rogue_vars.items(): v_primes = [ vp for vp in outputs[u] if weights[(u, vp)] < weights[(u, v)] ] u_primes = [ up for up in outputs[v] if weights[(v, up)] < weights[(v, u)] ] model += 1 - partners[v] - partners[u] + xsum( undirected[u, vp] for vp in v_primes) + xsum(undirected[up, v] for up in u_primes) <= rogue_var model.objective = maximize(individual * xsum( ((weights[edge] + weights[edge[1], edge[0]]) / 2) * edge_vars[edge] for edge in E) - communal * xsum(rogue_vars[edge] for edge in E)) model.optimize(max_seconds=300) return sorted([e for e in E if edge_vars[e].x > .01])
def test_variable_bounds(solver: str, val: int): m = Model("bounds", solver_name=solver) x = m.add_var(var_type=INTEGER, lb=0, ub=2 * val) y = m.add_var(var_type=INTEGER, lb=val, ub=2 * val) m.objective = maximize(x - y) m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == val assert round(x.x) == 2 * val assert round(y.x) == val
def _add_opt_goal(m: Model, v_to_s_to_cost: Dict[Vertex, Dict[Slot, int]], v_to_s_to_var: Dict[Vertex, Dict[Slot, Var]]) -> None: """ minimize the cost """ cost_var_pair_list: List[Tuple[int, Var]] = [] for v, s_to_var in v_to_s_to_var.items(): for s, var in s_to_var.items(): cost = v_to_s_to_cost[v][s] cost_var_pair_list.append((cost, var)) m.objective = minimize(xsum(cost * var for cost, var in cost_var_pair_list))
def random_knapsack(n: int, interval): I = range(n) p = [randrange(*interval) for _ in I] w = [randrange(*interval) for _ in I] c = round(sum(interval) / 2 * n) m = Model("random-knapsack") x = [m.add_var(var_type=BINARY) for i in I] m.objective = maximize(xsum(p[i] * x[i] for i in I)) m += xsum(w[i] * x[i] for i in I) <= c start = monotonic() print(m.optimize()) print(f"DURATION: {(monotonic() - start) * 1000} ms")
def do_matching_double_matches(graph, wants_two_matches=None): print("Starting model") weights = dict() graph = {int(key): graph[key] for key in graph} E = set() V = graph.keys() if not wants_two_matches: wants_two_matches = {v: True for v in V} inputs = {v: [] for v in V} outputs = {v: [] for v in V} for v in V: original = v for u, weight in graph[original]: s, t = (u, v) if u < v else (v, u) edge = (s, t) E.add(edge) weights[(original, u)] = weight outputs[original].append(u) inputs[u].append(original) model = Model("Allow double matches based") edge_vars = {e: model.add_var(var_type=BINARY) for e in E} undirected = dict() for e in E: undirected[e] = edge_vars[e] undirected[e[1], e[0]] = edge_vars[e] is_best = {e: model.add_var(var_type=BINARY) for e in undirected.keys()} penalty = {v: model.add_var(var_type=BINARY) for v in V} happiness = {v: model.add_var() for v in V} epsilon = .0000001 C = 1e3 for v in V: model += xsum(edge_vars[s, t] for s, t in E if v in [s, t]) <= 1 + penalty[v] * wants_two_matches[v] model += happiness[v] <= xsum(edge_vars[s, t] for s, t in E if v in [s, t]) * C if outputs[v]: model += xsum(is_best[(v, m)] for m in outputs[v]) == 1 for m in outputs[v]: model += happiness[v] <= undirected[(v, m)] * weights[ (v, m)] + (1 - is_best[(v, m)]) * C else: happiness[v] <= 0 model.objective = maximize( xsum(happiness[v] for v in V) - epsilon * xsum(penalty[v] for v in V)) model.optimize(max_seconds=300) return sorted([e for e in E if edge_vars[e].x > .01])
def solve_zero_one_linear_program(c, A, b, solver): """Minimize c*x x is binary A*c <= b """ assert A.shape[1] == c.shape[0] assert A.shape[1] == b.shape[0] out = None if solver == "cvxpy": start = time.time() print("Solving integer program of shape {}...".format(A.shape)) # The variable we are solving for selection = cvxpy.Variable(c.shape[0], boolean=True) weight_constraint = A * selection <= b # We tell cvxpy that we want to maximize total utility # subject to weight_constraint. All constraints in # cvxpy must be passed as a list problem = cvxpy.Problem(cvxpy.Minimize(c * selection), [weight_constraint]) # Solving the problem problem.solve(solver=cvxpy.GLPK_MI, verbose=True) print("Integer program solved in {}!".format(time.time() - start)) out = np.array(list(problem.solution.primal_vars.values())[0], dtype=bool) elif solver == "mip": m = Model() x = [m.add_var(var_type=BINARY) for i in range(len(c))] m.objective = minimize(xsum(c[i] * x[i] for i in range(len(c)))) for i in range(A.shape[0]): m += xsum(A[i, j] * x[j] for j in range(len(c))) <= b[i] m.optimize() out = np.array([x[i].x >= 0.99 for i in range(len(c))]) elif solver == "approximate": print("using approximate solution") solution = linprog(c=c, A_ub=A, b_ub=b) out = remove_overlapping_in_order(A=A, out=np.round(solution.x) > 0) else: raise ValueError("Solver {} not recognized".format(solver)) assert out is not None return out
def solveTSP(adjMatrixSubGraph, listPath, nodeKantor, listNode, mapIdxToNode, mapNodeToIdx): model = Model() listNode.insert(0, nodeKantor) n = len(listNode) # add variable x = [[model.add_var(var_type=BINARY) for j in range(n)] for i in range(n)] y = [model.add_var() for i in range(n)] # add objective function model.objective = minimize( xsum(adjMatrixSubGraph[mapNodeToIdx[listNode[i]]][mapNodeToIdx[ listNode[j]]] * x[i][j] for i in range(n) for j in range(n))) V = set(range(n)) # constraint : leave each city only once for i in V: model += xsum(x[i][j] for j in V - {i}) == 1 # constraint : enter each city only once for i in V: model += xsum(x[j][i] for j in V - {i}) == 1 # subtour elimination for (i, j) in product(V - {0}, V - {0}): if i != j: model += y[i] - (n + 1) * x[i][j] >= y[j] - n # optimizing model.optimize(max_seconds=30) res = [] # checking if a solution was found if model.num_solutions: print("SOLUTION FOUND") for i in range(n): for j in range(n): if (x[i][j].x == 1): print( listNode[i], " ", listNode[j], " : ", listPath[mapNodeToIdx[listNode[i]]][mapNodeToIdx[ listNode[j]]]) res.append((listNode[i], listNode[j])) else: print("gak ketemu") return res
def test_float(solver: str, val: int): m = Model("bounds", solver_name=solver) x = m.add_var(lb=0, ub=2 * val) y = m.add_var(lb=val, ub=2 * val) obj = x - y # No solution yet. __float__ MUST return a float type, so it returns nan. assert obj.x is None assert math.isnan(float(obj)) m.objective = maximize(obj) m.optimize() assert m.status == OptimizationStatus.OPTIMAL # test vars. assert x.x == float(x) assert y.x == float(y) # test linear expressions. assert float(x + y) == (x + y).x
def do_matching_two_round(graph): print("Starting model") weights = dict() graph = {int(key): graph[key] for key in graph} E = set() V = graph.keys() inputs = {v: [] for v in V} outputs = {v: [] for v in V} for v in V: original = v for u, weight in graph[original]: s, t = (u, v) if u < v else (v, u) edge = (s, t) E.add(edge) weights[(original, u)] = weight outputs[original].append(u) inputs[u].append(original) model = Model("Rogue Couples based") edge_vars = {e: model.add_var(var_type=BINARY) for e in E} undirected = dict() for e in E: undirected[e] = edge_vars[e] undirected[e[1], e[0]] = edge_vars[e] second_vars = {e: model.add_var(var_type=BINARY) for e in E} partners = dict() second_round_partners = dict() for v in V: partners[v] = model.add_var() model += partners[v] == xsum(edge_vars[s, t] for s, t in E if v in [s, t]) model += partners[v] <= 1 for v in V: second_round_partners[v] = model.add_var() model += second_round_partners[v] == xsum(second_vars[s, t] for s, t in E if v in [s, t]) model += second_round_partners[v] <= 1 for e in E: u, v = e model += second_vars[(u, v)] <= 2 - partners[v] - partners[u] model.objective = maximize( xsum(((weights[edge] + weights[edge[1], edge[0]]) / 2) * (edge_vars[edge] + second_vars[edge]) for edge in E)) model.optimize(max_seconds=1000) return sorted([e for e in E if edge_vars[e].x > .01] + [e for e in E if second_vars[e].x > .01])
def Int_Knapsack(f,d, V_d, Kf): p = list(np.ones((len(V_d),),dtype=int)) m = Model("knapsack") #x = [m.add_var(var_type=BINARY) for i in list(V_d.keys())] x = [(i,m.add_var(var_type=BINARY)) for i in list(V_d.keys())] m.objective = maximize(xsum(p[i] * x[i][1] for i in range(len(x)))) m += xsum(V_d[x[i][0]] * x[i][1] for i in range(len(x))) <= Kf[f] m.optimize() #selected = [i for i in list(V_d.keys()) if x[i].x >= 0.99] selected = [x[i][0] for i in range(len(x)) if x[i][1].x >= 0.99] #print("selected items: {}".format(selected)) y=(d,selected,f) return y #sol = Int_Knapsack(f,d,V_d, Kf)
def create_mip(solver, w, h, W, relax=False): m = Model(solver_name=solver) n = len(w) I = set(range(n)) S = [[j for j in I if h[j] <= h[i]] for i in I] G = [[j for j in I if h[j] >= h[i]] for i in I] if relax: x = [{ j: m.add_var( var_type=CONTINUOUS, lb=0.0, ub=1.0, name="x({},{})".format(i, j), ) for j in S[i] } for i in I] else: x = [{ j: m.add_var(var_type=BINARY, name="x({},{})".format(i, j)) for j in S[i] } for i in I] if relax: vtoth = m.add_var(name="H", lb=0.0, ub=sum(h), var_type=CONTINUOUS) else: vtoth = m.add_var(name="H", lb=0.0, ub=sum(h), var_type=INTEGER) toth = xsum(h[i] * x[i][i] for i in I) m.objective = minimize(toth) # each item should appear as larger item of the level # or as an item which belongs to the level of another item for i in I: m += xsum(x[j][i] for j in G[i]) == 1, "cons(1,{})".format(i) # represented items should respect remaining width for i in I: m += ( (xsum(w[j] * x[i][j] for j in S[i] if j != i) <= (W - w[i]) * x[i][i]), "cons(2,{})".format(i), ) return m
def max_utilitarian_welfare_allocation(utilities: Dict[int, List[float]], m: Model) -> None: """ Computes (one of) the item allocation(s) which maximizes utilitarian welfare, returning the optimized model. :param utilities: the dictionary representing the utility profile, where each key is an agent and its value an array of floats such that the i-th float is the utility of the i-th item for the key-agent. :param m: the MIP model which represents the integer linear program. """ agents, items = len(utilities), len(list(utilities.values())[0]) m.objective = maximize( xsum(utilities[agent][item] * m.var_by_name('assign_{}_{}'.format(item, agent)) for item in range(items) for agent in range(agents))) m.optimize()
def solve(self): """Try to solve the problem and identify possible matches.""" self._check_linear_dependency() A_eq = self.A3D.reshape(-1, self.n_1 * self.n_2) n = self.n_1 * self.n_2 # PYTHON MIP: model = Model() x = [model.add_var(var_type=BINARY) for i in range(n)] model.objective = minimize(xsum(x[i] for i in range(n))) for i, row in enumerate(A_eq): model += xsum(int(row[j]) * x[j] for j in range(n)) == int(self.b[i]) model.emphasis = 2 model.verbose = 0 model.optimize(max_seconds=2) self.X_binary = np.asarray([x[i].x for i in range(n) ]).reshape(self.n_1, self.n_2)
def _add_opt_goal( m: Model, v_list: List[Vertex], v2var_y1: Dict[Vertex, Var], v2var_y2: Dict[Vertex, Var], ) -> None: # add optimization goal all_edges = get_all_edges(v_list) e2cost_var = {e: m.add_var(var_type=INTEGER, name=f'intra_{e.name}') for e in all_edges} # we will use |(y1 * 2 + y1) - (y2 * 2 + y2)|to express the hamming distance pos_y = lambda v : v2var_y1[v] * 2 + v2var_y2[v] cost_y = lambda e : pos_y(e.src) - pos_y(e.dst) for e, cost_var in e2cost_var.items(): m += cost_var >= cost_y(e) m += cost_var >= -cost_y(e) m.objective = minimize(xsum(cost_var * e.width for e, cost_var in e2cost_var.items() ) )
def get_lineups(self, slate, ptcol, lineups, salcap=50000): positions = slate['positions'] pool= pd.concat(slate['players'].values(),ignore_index='True').drop(columns='position')\ .drop_duplicates().reset_index(drop=True) #Establish positions eligibility data structure elig = [[ 1 if plyr['name'] in list(slate['players'][pos]['name']) else 0 for i, pos in enumerate(positions) ] for skip, plyr in pool.iterrows()] pts = list(pool[ptcol]) #Set up player salary list sal = list(pool['salary']) #Set up range just for short reference I = range(len(pts)) J = range(len(positions)) #Set up results results = [] m = Model() m.verbose = False x = [[m.add_var(var_type=BINARY) for j in J] for i in I] m.objective = maximize( xsum(x[i][j] * elig[i][j] * pts[i] for i in I for j in J)) #Apply salary cap constraint m += xsum((x[i][j] * sal[i] for i in I for j in J)) <= salcap #Apply one player per position constraint for j in J: m += xsum(x[i][j] for i in I) == 1 #apply max one position per player constraint for i in I: m += xsum(x[i][j] for j in J) <= 1 for lineup in range(lineups): print(lineup) m.optimize() #Add lineup to results idx = [(i, j) for i in I for j in J if x[i][j].x >= 0.99] results.append( pd.concat([pool.iloc[i:i + 1] for i, j in idx], ignore_index=True)) results[-1]['position'] = [positions[j] for i, j in idx] #Apply constraint to ensure this player combination will not be repeated (cannot have three overlapping players for diversity) m += xsum(x[i][j] for i, skip in idx for j in J) <= len(positions) - 3 return results
def maximize_sum(plfs, max_costs): # pylint: disable=too-many-locals m = Model("bid-landscapes") costs = LinExpr() objective = LinExpr() xs = [] ws = [] for (i, plf) in enumerate(plfs): k = len(plf) w = [m.add_var(var_type=CONTINUOUS) for _ in range(0, k)] x = [m.add_var(var_type=BINARY) for _ in range(0, k - 1)] xs.append(x) ws.append(w) m += xsum(w[i] for i in range(0, k)) == 1 for i in range(0, k): m += w[i] >= 0 m += w[0] <= x[0] for i in range(1, k - 1): m += w[i] <= x[i - 1] + x[i] m += w[k - 1] <= x[k - 2] m += xsum(x[k] for k in range(0, k - 1)) == 1 for i in range(0, k): costs.add_term(w[i] * plf.a[i]) objective.add_term(w[i] * plf.b[i]) m += costs <= max_costs m.objective = maximize(objective) start = monotonic() print(m.optimize()) print(f"DURATION: {(monotonic() - start) * 1000} ms") optimum = [] for (i, plf) in enumerate(plfs): k = len(plf) u_i = sum(ws[i][j].x * plf.a[j] for j in range(0, k)) v_i = sum(ws[i][j].x * plf.b[j] for j in range(0, k)) optimum.append(Line(cost=u_i, revenue=v_i, plf=plf)) return optimum
def solve(F, groups): allEmployees = 0 for g in groups: allEmployees += g.employees G = len(groups) print("Solving for {} floors with {} employees in {} groups".format( F, allEmployees, G)) # A binary search would be much better here, of course, but meh for wcs in range(1, allEmployees + 1): m = Model() x = [m.add_var(var_type=INTEGER) for i in range(F * G)] for i, g in enumerate(groups): m += xsum(x[i * F + f] for f in g.floors) >= g.employees for f in range(F): m += xsum(x[f + g * F] for g in range(G)) <= wcs m.objective = xsum(0 for i in range(F * G)) m.max_gap = 0.05 status = m.optimize(max_seconds=3000) if status == OptimizationStatus.OPTIMAL: print('optimal solution cost {} found'.format(m.objective_value)) elif status == OptimizationStatus.FEASIBLE: print('sol.cost {} found, best possible: {}'.format( m.objective_value, m.objective_bound)) elif status == OptimizationStatus.NO_SOLUTION_FOUND: print('no feasible solution found, lower bound is: {}'.format( m.objective_bound)) if status == OptimizationStatus.OPTIMAL or status == OptimizationStatus.FEASIBLE: print( '===================================================================' ) print('solution:') for v in m.vars: if abs(v.x) > 1e-6: # only printing non-zeros print('{} : {}'.format(v.name, v.x)) return wcs