def __init__(self, rounding_digits: int = ROUNDING_DIGITS, max_seconds: int = ILP_SOLVER_MAX_SECONDS) -> None: """Create an ILPSolver. Args: rounding_digits: Number of digits to round the charges to. max_seconds: Maximum run-time to spend searching for a \ solution """ self._rounding_digits = rounding_digits if CPLEX_CMD().available(): self._solver = CPLEX_CMD(timelimit=max_seconds) elif GUROBI_CMD().available(): self._solver = GUROBI_CMD(options=[('timeLimit', max_seconds)]) elif PULP_CBC_CMD().available(): self._solver = PULP_CBC_CMD(maxSeconds=max_seconds) elif GLPK_CMD().available(): self._solver = GLPK_CMD(options=['--tmlim %d' % max_seconds]) elif COIN_CMD().available(): self._solver = COIN_CMD(maxSeconds=max_seconds) else: raise RuntimeError( 'No solver found, there is something wrong with your pulp library setup.' )
def disjointness_LP(sets): if (len(sets) == 0): return prob = LpProblem("Disjointness Problem", LpMaximize) variables = [] for i in range(len(sets)): variables.append(LpVariable("Include Set " + str(i), 0, 1)) #objective prob += lpSum([1 * variables[i] for i in range(len(sets))]) #constraints for j in range(len(sets[0])): #for every qubit, make the sum of actions less than 1 prob += lpDot([sets[i][j] for i in range(len(sets))], [variables[i] for i in range(len(sets))]) <= 1 prob.writeLP("Disjointness.lp") prob.solve(solver=PULP_CBC_CMD(msg=0)) representatives = [] values = [] for v in prob.variables(): i = extract_index(v.name) if (v.varValue != 0.0): representatives.append(i) values.append(v.varValue) return value(prob.objective), representatives, values
def rep(g): nbar = { u: nx.induced_subgraph(g, [v for v in g if v not in g[u]]) for u in g } x = { u: {v: LpVariable(f'x{u},{v}', cat='Binary') for v in nbar[u]} for u in g } lp = LpProblem() lp += lpSum([x[u][u] for u in g]) for v in g: lp += lpSum([x[u][v] for u in nbar[v]]) >= 1 for u in g: for v, w in nbar[u].edges: lp += x[u][v] + x[u][w] <= x[u][u] lp.writeLP('rep.lp') PULP_CBC_CMD(msg=0).solve(lp) reps = [u for u in g if x[u][u].varValue > 0] cols = [None] * g.order() for c, v in enumerate(reps): cols[v] = c for c, r in enumerate(reps): for v in [v for v, xi in x[r].items() if xi.varValue > 0]: if v not in reps: cols[v] = c return cols
def pop(g, H=10): h = list(range(H)) y = {i: {v: LpVariable(f'y{i},{v}', cat='Binary') for v in g} for i in h} z = {v: {i: LpVariable(f'z{v},{i}', cat='Binary') for i in h} for v in g} lp = LpProblem() q = 0 # arbitrary fix vertex, then q = 0 lp += 1 + lpSum([y[i][q] for i in h]) # 15 for v in g: lp += z[v][1] == 0 # 16 lp += y[h[-1]][v] == 0 # 17 for v in g: for i in h[:-2]: lp += y[i][v] - y[i + 1][v] >= 0 # 18 lp += y[i][v] + z[v][i + 1] == 1 # 19 lp += y[i][q] - y[i][v] >= 0 # 21 for u, v in g.edges: for i in h: lp += y[i][u] + z[u][i] + y[i][v] + z[v][i] >= 1 # 20 PULP_CBC_CMD(msg=0).solve(lp) return [ next(i for i in h if y[i][v].varValue == 0.0 and z[v][i].varValue == 0.0) for v in g ]
def optimize(self, time_limit, solver, presolve=2): # The solver value shall one of the available # solver corresponding pulp command if 'gurobi' in solver.lower(): # ignore SIGINT while solver is running # => SIGINT is still delivered to the solver, which is what we want signal.signal(signal.SIGINT, signal.SIG_IGN) self.model.solve( GUROBI_CMD(keepFiles=1, msg=True, options=[("TimeLimit", time_limit), ("Presolve", presolve), ("MIPGapAbs", 0.2)])) else: # TODO Use the solver parameter to get # the target class by reflection self.model.solve( PULP_CBC_CMD(keepFiles=1, msg=True, presolve=presolve, maxSeconds=time_limit)) status = self.model.status print(LpStatus[status]) if status == LpStatusOptimal or (not (solver.lower() == 'gurobi') and status == LpStatusNotSolved): return self.get_obj_coeffs() else: print('lpfile has been saved in FlOpTT-pulp.lp') return None
def optimize_pulp(self): from pulp import LpVariable,LpProblem,LpMaximize,LpBinary,PULP_CBC_CMD p = LpProblem("knapsackP",LpMaximize) x = LpVariable.dict("x",indexs=(range(self.num)),lowBound=0,upBound=1,cat=LpBinary) #価値最大化 #p += sum(x[i]*self.p[i].get_value() for i in range(self.num)) #p += lpDot(x,[self.p[i].get_value() for i in range(self.num)]) p += lpSum(x[i]*self.p[i].get_value() for i in range(self.num)) #重量を制限以内 p += lpSum(x[i]*self.p[i].get_weight() for i in range(self.num)) <= self.limit_weight #解く solver=PULP_CBC_CMD(msg=0,threads=10) p.solve(solver) if p.status == 1: print("## Pulp Optimized Result") self.print([int(x[i].value()) for i in range(self.num)]) ret = sum([x[i].value()*self.p[i].get_value() for i in range(self.num)]) del x,p gc.collect() return ret else: print("## Pulp Optimizing Failed")
class PuLPSolver(Solver): LP_SOLVER = PULP_CBC_CMD(verbose=False, msg=False) def __init__(self): self.prob = LpProblem('Daily Fantasy Sports', LpMaximize) def setup_solver(self): pass def add_variable(self, name, min_value=None, max_value=None): if any([min_value, max_value]): return LpVariable(name, lowBound=min_value, upBound=max_value, cat=LpInteger) return LpVariable(name, cat=LpBinary) def set_objective(self, variables, coefficients): self.prob += lpSum([ variable * coefficient for variable, coefficient in zip(variables, coefficients) ]) def add_constraint(self, variables, coefficients, sign, rhs): if coefficients: lhs = [ variable * coefficient for variable, coefficient in zip(variables, coefficients) ] else: lhs = variables if sign == SolverSign.EQ: self.prob += lpSum(lhs) == rhs elif sign == SolverSign.NOT_EQ: self.prob += lpSum(lhs) != rhs elif sign == SolverSign.GTE: self.prob += lpSum(lhs) >= rhs elif sign == SolverSign.LTE: self.prob += lpSum(lhs) <= rhs else: raise SolverException('Incorrect constraint sign') def copy(self): new_solver = type(self)() new_solver.prob = self.prob.copy() return new_solver def solve(self): self.prob.solve(self.LP_SOLVER) if self.prob.status == LpStatusOptimal: result = [] for variable in self.prob.variables(): val = variable.value() if val is not None and round(val) >= 1.0: result.append(variable) return result else: raise SolverException('Unable to solve')
def run(self): self.problem = LpProblem('FML', LpMaximize) self.create_vars() self.problem += self.get_objective_function(solved=False) for constraint in self.get_constraints(): self.problem += constraint status = self.problem.solve(PULP_CBC_CMD(msg=3)) solved = status == 1 return solved
def _formulate_and_solve( self, env_tick: int, init_inventory: np.ndarray, demand: np.ndarray, supply: np.ndarray ): problem = LpProblem( name=f"Citi_Bike_Repositioning_from_tick_{env_tick}", sense=LpMaximize, ) self._init_variables(init_inventory=init_inventory) self._add_constraints(problem=problem, demand=demand, supply=supply) self._set_objective(problem=problem) problem.solve(PULP_CBC_CMD(msg=0))
def solve(self, print_status=True, print_cost_achieved=True): status = self.problem.solve(PULP_CBC_CMD(msg=0)) self.problem_solved = True print_blank_line = False if print_status: print(f"Status: {LpStatus[status]}") print_blank_line = True if print_cost_achieved: print(f"Cost: {value(self.problem.objective)}") print_blank_line = True if print_blank_line: print()
def solve_exact(self): ''' 整数計画法を用いて厳密解を得る parameters ----- なし returns ----- なし ''' from pulp import LpProblem, LpVariable, lpSum, LpStatus, PULP_CBC_CMD n_city = self.size #Pulpで解く p = LpProblem("TSP") x = LpVariable.dicts(name="x", indexs=(range(n_city), range(n_city)), cat='Binary') p += lpSum( self.dist(i, j) * x[i][j] for i, j in product(range(n_city), range(n_city))) for i in range(n_city): p += lpSum(x[i][j] for j in range(n_city)) == 1 for i in range(n_city): p += lpSum(x[j][i] for j in range(n_city)) == 1 V = set(range(n_city)) for s_len in range(1, n_city - 1): for S_list in combinations(range(n_city), s_len): S = set(S_list) _V = V - S tmp = 0 for i, j in product(S, _V): tmp += x[i][j] p += tmp >= 1 solver = PULP_CBC_CMD(threads=15) status = p.solve(solver) print(LpStatus[status]) self.exact_route = [0] for i in range(n_city - 1): for j in range(n_city): if x[self.exact_route[i]][j].value() == 1.0: self.exact_route.append(j) break self.exact_dist = self.route_len(self.exact_route)
def _solve(self): logger.info("Searching for a cover for {}...".format(self.root_object)) time_start = time() if GUROBI_CMD(msg=0).available(): logger.info("Gurobi installed on system and set as solver") solver = GUROBI_CMD(msg=0) elif PULP_CBC_CMD(msg=0).available(): logger.warning("Gurobi not installed on system, instead " "falling back on PuLP's bundled CBC LP solver") solver = PULP_CBC_CMD(msg=0) else: raise RuntimeError("Unable to load PuLP's bundled CBC LP solver") problem = LpProblem("CombCov LP minimization problem", LpMinimize) X = LpVariable.dicts("x", list(range(len(self.bitstrings))), cat="Binary") for i in range(len(self.elmnts_dict)): # nr. of equations constraint = sum( int(self.bitstrings[j][-i]) * X[j] for j in range(len(self.bitstrings)) ) # nr. of variables x_j problem += constraint == 1 # Objective function problem += sum(X[j] for j in range(len(self.bitstrings))) problem.solve(solver=solver) self.solution = [ self.bitstring_to_rules_dict[self.bitstrings[x]][0] for x in X if X[x].varValue and int(X[x].varValue) == 1 ] time_end = time() elapsed_time = time_end - time_start logger.info("...DONE searching for a cover! " "(Running time: {:.2f} sec)".format(elapsed_time))
def solve(self) -> ModelSolution: """ Method to solve the optimization model. For other optimization frameworks, a similar logic can be applied. ** Gurobi for constraint in self.constraints: self.solver.addConstr(constraint) self.solver.setObjective(self.objective, self.sense) self.solver.optimize() if self.engine_model.status == GRB.OPTIMAL: solution = np.vectorize(self._var_sol)(self.variable_set) else: solution = np.array([]) ** Google or-tools for constraint in self.constraints: self.solver.Add(constraint) if self.sense == Sense.MINIMIZATION: self.solver.Minimize(self.objective) else: self.solver.Maximize(self.objective) status = self.solver.Solve() if status == Solver.OPTIMAL: solution = np.vectorize(self.var_sol)(self.variable_set) else: solution = np.array([]) """ for constraint in self.constraints: self.solver += constraint self.solver += self.objective status = self.solver.solve(PULP_CBC_CMD(msg=False)) if status == LpStatusOptimal: solution = np.vectorize(self._var_sol)(self.variable_set) else: solution = np.array([]) return ModelSolution(variable_set=solution, objective=self.solver.objective.value())
def get_solution(self): """Set a number of constrains for the model and then solve the ILP.""" self.update_model_with_decision_variables() self.add_constraints_to_model() size_string_list = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"] size_dict_list = [self.one, self.two, self.three, self.four, self.five, self.six, self.seven, self.eight] self.update_all_models(size_string_list, size_dict_list) self.determine_biggest_sum(size_string_list, size_dict_list) # Add the objective function to the model self.model += lpSum(self.x) # Solve the problem self.model.solve(PULP_CBC_CMD(timeLimit=600, msg=False, gapRel=0))
def ass(g, h=10): c = list(range(h)) w = [LpVariable(f'w{j}', cat='Binary') for j in c] x = {i: [LpVariable(f'x{i},{j}', cat='Binary') for j in c] for i in g} lp = LpProblem() lp += lpSum(w) for i in g: lp += lpSum(x[i]) == 1 for u, v in g.edges: for j in c: lp += x[u][j] + x[v][j] <= w[j] for j in c: lp += w[j] <= lpSum([x[i][j] for i in g]) for j in c[1:]: lp += w[j] <= w[j - 1] PULP_CBC_CMD(msg=0).solve(lp) return [[xi.varValue for xi in x[i]].index(1.0) for i in g]
def ipla(g): n, k, h = g.order(), max(deg for _, deg in g.degree), g.to_directed() lp = LpProblem() lp += (w := LpVariable('w')) for u in h.nodes: h.nodes[u]['v'] = [ LpVariable(f'y{u},{i}', 1, n, 'Integer') for i in range(k) ] for u, v in g.edges: h[u][v]['v'] = [ LpVariable(f'x{u},{v},{i}', cat='Binary') for i in range(k) ] h[v][u]['v'] = [ LpVariable(f'x{v},{u},{i}', cat='Binary') for i in range(k) ] lp += lpSum(h[u][v]['v']) + lpSum(h[v][u]['v']) == 1 lp += w >= lpSum((i + 1) * h[u][v]['v'][i] + (i + 1) * h[v][u]['v'][i] for i in range(k)) for i in range(k): lp += (h.nodes[u]['v'][i] - h.nodes[v]['v'][i] + (n - 1) * h[u][v]['v'][i] <= n - 2) lp += (h.nodes[v]['v'][i] - h.nodes[u]['v'][i] + (n - 1) * h[v][u]['v'][i] <= n - 2) for u in h.nodes: for i in range(k): lp += lpSum(h[u][v]['v'][i] for v in h.successors(u)) <= 1 lp += lpSum(h[v][u]['v'][i] for v in h.predecessors(u)) <= 1 PULP_CBC_CMD(msg=0).solve(lp) # print(w.varValue) # from pprint import pprint # for v in g: # pprint([x.varValue for x in h.nodes[v]['v']]) # for u, v in h.edges: # pprint([x.varValue for x in h[u][v]['v']]) ep = {} for u, v in g.edges: if sum((res := [h[u][v]['v'][i].varValue for i in range(k)])) != 0: ep[(u, v)] = res.index(1.0) else: ep[(u, v)] = [h[v][u]['v'][i].varValue for i in range(k)].index(1.0)
def __init__(self, config: DottableDict, pm_capacity: List[IlpPmCapacity], logger: Logger, log_path: str): self._logger = logger self._log_path = log_path self._pm_capacity = pm_capacity self._pm_num = len(self._pm_capacity) # LP solver. msg = 1 if config.log.stdout_solver_message else 0 if config.solver == "GLPK": self._solver = GLPK(msg=msg) elif config.solver == "CBC": self._solver = PULP_CBC_CMD(msg=msg) else: print( f"Solver {config.solver} not added in ILP, choose from [GLPK, CBC]" ) exit(0) # For formulation and action application. self.plan_window_size = config.plan_window_size self.apply_buffer_size = config.apply_buffer_size # For performance. self.core_upper_ratio = 1 - config.performance.core_safety_remaining_ratio self.mem_upper_ratio = 1 - config.performance.mem_safety_remaining_ratio # For objective. self.successful_allocation_decay = config.objective.successful_allocation_decay self.allocation_multiple_core_num = config.objective.allocation_multiple_core_num # For logger. self.dump_all_solution = config.log.dump_all_solution self.dump_infeasible_solution = config.log.dump_infeasible_solution # For problem formulation and application self.last_solution_env_tick = -1
def solve(self): """Method for solving the optimization model""" if self.optimizer == 'pulp': for constraint in self.constraints: self.engine_model += constraint self.engine_model += self.objective status = self.engine_model.solve(PULP_CBC_CMD(msg=False)) solution = (np.vectorize(self._var_sol)(self.variable_set) if status == LpStatusOptimal else np.array([])) else: for constraint in self.constraints: self.engine_model.addConstr(constraint) self.engine_model.setObjective(self.objective, self.sense) self.engine_model.optimize() solution = (np.vectorize(self._var_sol)(self.variable_set) if self.engine_model.status == GRB.OPTIMAL else np.array([])) return solution
def run(self): prob = LpProblem("V_star_Problem", LpMinimize) var = [] state_to_var = {} for s in range(self.num_states): if s not in self.end: state_to_var[f"V{s}"] = s var.append(LpVariable(f"V{s}", cat="Continuous")) prob += lpSum(var), "minimize_V" self.add_constraints(var, prob) prob.writeLP("CalculateVStarProblem.lp") result = prob.solve(PULP_CBC_CMD(msg=0)) assert LpStatusOptimal == result self.v_star = [0] * self.num_states for v in prob.variables(): if v.name in state_to_var: self.v_star[state_to_var[v.name]] = v.varValue self.a_star = self.get_action(self.v_star)
def apply(c, Aub, bub, Aeq, beq, parameters=None): """ Gets the overall solution of the problem Parameters ------------ c c parameter of the algorithm Aub A_ub parameter of the algorithm bub b_ub parameter of the algorithm Aeq A_eq parameter of the algorithm beq b_eq parameter of the algorithm parameters Possible parameters of the algorithm Returns ------------- sol Solution of the LP problem by the given algorithm """ if parameters is None: parameters = {} require_ilp = exec_utils.get_param_value(Parameters.REQUIRE_ILP, parameters, False) Aub = np.asmatrix(Aub) if type(bub) is list and len(bub) == 1: bub = bub[0] if Aeq is not None: Aeq = np.asmatrix(Aeq) if beq is not None and type(beq) is list and len(beq) == 1: beq = beq[0] prob = LpProblem("", LpMinimize) x_list = [] for i in range(Aub.shape[1]): if require_ilp: x_list.append(LpVariable("x_" + get_terminal_part_name_num(i), cat='Binary')) else: x_list.append(LpVariable("x_" + get_terminal_part_name_num(i))) eval_str = "" expr_count = 0 for j in range(len(c)): if abs(c[j]) > MIN_THRESHOLD: if expr_count > 0: eval_str = eval_str + " + " eval_str = eval_str + str(c[j]) + "*x_list[" + str(j) + "]" expr_count = expr_count + 1 eval_str = eval_str + ", \"objective\"" prob += eval(eval_str) for i in range(Aub.shape[0]): expr_count = 0 eval_str = 0 eval_str = "" for j in range(Aub.shape[1]): if abs(Aub[i, j]) > MIN_THRESHOLD: if expr_count > 0: eval_str = eval_str + " + " eval_str = eval_str + str(Aub[i, j]) + "*x_list[" + str(j) + "]" expr_count = expr_count + 1 eval_str = eval_str + "<=" + str( bub[i].reshape(-1, ).tolist()[0][0]) + ", \"vinc_" + get_terminal_part_name_num(i) + "\"" prob += eval(eval_str) if Aeq is not None and beq is not None: for i in range(Aeq.shape[0]): expr_count = 0 eval_str = 0 eval_str = "" for j in range(Aeq.shape[1]): if abs(Aeq[i, j]) > MIN_THRESHOLD: if expr_count > 0: eval_str = eval_str + " + " eval_str = eval_str + str(Aeq[i, j]) + "*x_list[" + str(j) + "]" expr_count = expr_count + 1 if eval_str: eval_str = eval_str + "==" + str(beq[i].reshape(-1, ).tolist()[0][0]) + ", \"vinceq_" + get_terminal_part_name_num( i + 1 + Aub.shape[0]) + "\"" prob += eval(eval_str) filename = tempfile.NamedTemporaryFile(suffix='.lp').name prob.writeLP(filename) PULP_CBC_CMD(msg=0).solve(prob) return prob
#問題定義 p = LpProblem(name="SpreadingPointsProblem", sense=LpMaximize) #zの最大化問題として定義 p += z #N個のPointが配置される tmp_sub = 0 for i, j in product(range(SIZE), range(SIZE)): tmp_sub += x[(i, j)] p += tmp_sub == N #確認した2点に同時に点が配置されているとしたばあい、その距離はz以上 BIGM = 100.0 for i, j in product(range(SIZE), range(SIZE)): for k, l in product(range(SIZE), range(SIZE)): if i == k and j == l: continue #x[(i,j)] x[(k,l)]が両方1のときのみ意味ある不等式となる。 p += z <= (1 - x[(i, j)]) * BIGM + (1 - x[(k, l)]) * BIGM + dist( (i, j), (k, l)) solver = PULP_CBC_CMD(msg=0, mip=True, threads=15) p.solve(solver) print(LpStatus[p.status]) print(f"Best Distance@{N}points = {value(p.objective)}") #結果出力 for j in range(SIZE): print(",".join(str(int(x[(j, i)].value())) for i in range(SIZE)))
def steiner_tree(g, term): lp, x = __get_formulae(g, term) lp.writeLP('steiner_tree.lp') PULP_CBC_CMD(msg=0).solve(lp) return nx.Graph((e for e in x if x[e].varValue > 0))
def optimization_setup(distance_df, clump_df, threshold, clump_size_list, clump_ratio_list, group_label, time_limit, top_end_threshold, aisle_indicator): tic_o = time.perf_counter() print("Deleting the single node loops") # removing the single node loops, so that optimization runs easier delete_index = [] for i in range(len(distance_df)): if distance_df.orig[i] == distance_df.dest[i]: delete_index.append(i) ######## checking for feasibility if distance_df.dist[i] > top_end_threshold: delete_index.append(i) distance_df = distance_df.drop(index=delete_index) distance_df = distance_df.reset_index(drop=True) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") # removing the aisle nodes, as indicated by the user if aisle_indicator == "no_aisle_seats": print("Removing Aisle Seats") delete_index = [] for i in range(len(clump_df)): if clump_df.aisle_cluster[i] == 1: delete_index.append(i) clump_df = clump_df.drop(index=delete_index) clump_df = clump_df.reset_index(drop=True) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") busy_string = '1-'+group_label def cut_variable_strings(variable_list): if type(variable_list[0]) is tuple: return [tuple([item.replace(busy_string,'').replace('-','') for item in tuple_item]) for tuple_item in variable_list] else: return [item.replace(busy_string,'').replace('-','') for item in variable_list] # where ratios are of interest, aka 20% 4 seat clusters 80% 2 seat clusters, these individual nodes need to be created print("Creating specific nodes for ratios") if len(clump_ratio_list) >= 2: nodesA = cut_variable_strings(clump_df[clump_df.clump_size == clump_size_list[0]].seatclumpid.tolist()) nodesB = cut_variable_strings(clump_df[clump_df.clump_size == clump_size_list[1]].seatclumpid.tolist()) BAratio = clump_ratio_list[1]/clump_ratio_list[0] if len(clump_ratio_list) >= 3: nodesC = cut_variable_strings(clump_df[clump_df.clump_size == clump_size_list[2]].seatclumpid.tolist()) CBratio = clump_ratio_list[2]/clump_ratio_list[1] if len(clump_ratio_list) >= 4: nodesD = cut_variable_strings(clump_df[clump_df.clump_size == clump_size_list[3]].seatclumpid.tolist()) DCratio = clump_ratio_list[3]/clump_ratio_list[2] if len(clump_ratio_list) >= 5: print("optimization method only set up for 4 types of seat clumps and even that can be ridiculous to optimize against") toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Creating standard nodes") # create the standard list of nodes (seat clumps) nodes = clump_df.seatclumpid.tolist() nodes = cut_variable_strings(nodes) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") # TODO for aisles if that's something of interest #if aisle_indicator == 'force_aisle_seats': #print("Creating the aisles") # create the standard node aisle indicators #aisles = dict(zip(clump_df.seatclumpid, clump_df.aisle_clump)) #toc_o_c = time.perf_counter() #print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Creating the dictionary for nodes") # create a dictionary for those nodes and their value (clump size) sizes = dict(zip(nodes, clump_df.clump_size)) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Creating standard arcs") # create a set of nodes to represent arcs (tuple) # turn arc set into list arcs = distance_df.arc_set.tolist() arcs = cut_variable_strings(arcs) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Creating the dictionary for arcs") # create a dictionary of those sets with distances dists = dict(zip(arcs, distance_df.dist)) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Creating the variables for acrcs and nodes") # OPTIMIZATION MODEL BEGINS # Creates the Variables as Integers arcvars = LpVariable.dicts("Arc",arcs,0,1,LpBinary) nodevars = LpVariable.dicts("Node",nodes,0,1,LpBinary) # creates a heavier optimization problem, but allows the flexibility of 2 vs 3 or 3 vs 4 seat clusters print("Creating the variables for specific nodes for ratios") if len(clump_ratio_list) >= 2: nodeAvars = LpVariable.dicts("NodeA",nodesA,0,1,LpBinary) nodeBvars = LpVariable.dicts("NodeB",nodesB,0,1,LpBinary) if len(clump_ratio_list) >= 3: nodeCvars = LpVariable.dicts("NodeC",nodesC,0,1,LpBinary) if len(clump_ratio_list) >= 4: nodeDvars = LpVariable.dicts("NodeD",nodesD,0,1,LpBinary) toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Initializing the MIP") # Creates the 'prob' variable to contain the problem data prob = LpProblem("Maximum Capacity Problem", LpMaximize) print("Setting up the objective function") # Creates the objective function # here's where we would implement weighting for specific seats prob += lpSum([nodevars[n]* sizes[n] for n in nodes]), "Total Capacity" toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Setting up the first set of constraints, arcs = must exist between two nodes that exist") # Constraint set #1: insuring that if two nodes exist, the arc between them must exist for j in nodes: for k in nodes: if j != k: try: prob += 1 + arcvars[(j,k)] >= nodevars[k]+nodevars[j] except KeyError: pass toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Setting up the second set of constraints, arcs can only exist if they're longer than the threshold") # Constraint set #2: each arc used must have a distance greater than the threshold for a in arcs: prob += arcvars[a]*dists[a] >= threshold*arcvars[a] toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Setting up the third set of constraints, nodes must exist in both the specific listing and the standard listing if specific arc required for ratio") # Constraint set #3: only if there are multiple clump sizes required, make sure they correspond to the typical nodes if len(clump_ratio_list) >= 2: for a in nodesA: prob += nodeAvars[a] == nodevars[a] for b in nodesB: prob += nodeBvars[b] == nodevars[b] if len(clump_ratio_list) >= 3: for c in nodesC: prob += nodeCvars[c] == nodevars[c] if len(clump_ratio_list) >= 4: for d in nodesD: prob += nodeDvars[d] == nodevars[d] toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") if len(clump_ratio_list) >= 2: print("Setting up the fourth set of constraints, the number of arcs in a specific set must fall between 10% of the previous node") # Constraint set #4: make sure the ratios of clumps align with what's requested, window of 10%ish # window reduced to one constraint per option, indicating that if the number of cluster is increasing # it will head for that upper bound as it is more efficient if len(clump_ratio_list) >= 2: prob += lpSum([nodeBvars[n] for n in nodesB]) <= lpSum([nodeAvars[n] for n in nodesA])*1.1*BAratio #prob += lpSum([nodeBvars[n] for n in nodesB]) >= lpSum([nodeAvars[n] for n in nodesA])*0.9*BAratio if len(clump_ratio_list) >= 3: prob += lpSum([nodeCvars[n] for n in nodesC]) <= lpSum([nodeBvars[n] for n in nodesB])*1.1*CBratio #prob += lpSum([nodeCvars[n] for n in nodesC]) >= lpSum([nodeBvars[n] for n in nodesB])*0.9*CBratio if len(clump_ratio_list) >= 4: prob += lpSum([nodeDvars[n] for n in nodesD]) <= lpSum([nodeCvars[n] for n in nodesC])*1.1*DCratio #prob += lpSum([nodeDvars[n] for n in nodesD]) >= lpSum([nodeCvars[n] for n in nodesC])*0.9*DCratio toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") # TODO if aisles are indicated as a point of interest #if aisle_indicator == 'no_aisle_seats': #print("Setting up the fifth set of constraints, inclusion or exclusion of aisle seats") # Constraint set #4: make sure the ratios of clumps align with what's requested, window of 10%ish # window reduced to one constraint per option, indicating that if the number of cluster is increasing # it will head for that upper bound as it is more efficient #for n in nodes: # prob += nodesvars[n]*aisles[n] == 0 #if aisle_indicator == 'force_aisle_seats': not sure this is possible, don't uncomment before finding a reason to move forward here #print("Setting up the fifth set of constraints, inclusion or exclusion of aisle seats") # Constraint set #4: make sure the ratios of clumps align with what's requested, window of 10%ish # window reduced to one constraint per option, indicating that if the number of cluster is increasing # it will head for that upper bound as it is more efficient #for n in nodes: # prob += nodesvars[n]*aisles[n] ????? #toc_o_c = time.perf_counter() #print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") print("Writing the LP or MPS file now") # The problem data is written to an lp or mps file # this file can be run on the NEOS server or other optimization servers if you're facing timeout issues or low compute abilities prob.writeLP("LP Files/stadium_MCP"+group_label+".lp") #prob.writeLP("MPS files/stadium_MCP"+group_label+".mps") toc_o_c = time.perf_counter() print(f"... {toc_o_c-tic_o:0.4f} seconds have elapsed") # The problem is solved using PuLP's choice of Solver prob.solve(PULP_CBC_CMD(maxSeconds = time_limit, msg = 1, fracGap=0.01)) # The optimised objective function value is printed to the screen output_val = value(prob.objective) print("Total Capacity = ", output_val) # creates the variables indicating that those clusters were in fact chosen in the optimal list TOL = 0.01 node_ind = [] for n in nodes: if nodevars[n].varValue > TOL: node_ind.append(1) else: node_ind.append(0) clump_df['clump_ind'] = node_ind clump_sum_df = clump_df[['clump_size', 'clump_ind']] clump_sum_df = clump_sum_df.groupby(['clump_size']).sum().reset_index() # creating a size dataframe to understand the final clusters and final cluster ratios clump_size_for_df = [] clump_amount_for_df = [] for i in range(len(clump_sum_df)): clump_size_for_df.append("clusters of "+str(clump_sum_df.clump_size[i])) clump_amount_for_df.append(clump_sum_df.clump_ind[i]) size_df = pd.DataFrame([clump_amount_for_df], columns = clump_size_for_df) # saves the optimized seats to the Optimized Seats folder so that optimization does not have to run again group_item_name = 'group_label_'+group_label+'_opt_seats' clump_df.to_csv('Optimized Seats/'+group_item_name+'.csv') # prints and returns the optimization time, important for experimentation and evolution toc_o = time.perf_counter() opt_time_num = round(toc_o-tic_o,2) print(opt_time_num) opt_time = group_label+f" took {toc_o-tic_o:0.4f} seconds\n" print(f"Total Optimization for "+opt_time+f" or {(toc_o-tic_o)/60:0.1f} minutes with tolerance") return opt_time, opt_time_num, output_val, clump_df, size_df
from conference_scheduler import scheduler from conference_scheduler.heuristics import hill_climber from conference_scheduler.heuristics import simulated_annealing from conference_scheduler.lp_problem.objective_functions import ( efficiency_capacity_demand_difference, equity_capacity_demand_difference, number_of_changes) from pulp import GLPK from pulp import PULP_CBC_CMD logger = daiquiri.getLogger(__name__) solvers = { 'pulp_cbc_cmd': { 'function': scheduler.solution, 'kwargs': { 'solver': PULP_CBC_CMD(msg=False) } }, 'glpk': { 'function': scheduler.solution, 'kwargs': { 'solver': GLPK(msg=False) } }, 'hill_climber': { 'function': scheduler.heuristic, 'kwargs': { 'algorithm': hill_climber } }, 'simulated_annealing': {
from pulp import LpProblem, LpMinimize, LpVariable, LpStatus, value from pm4py.util import exec_utils from pm4py.util.lp.parameters import Parameters MIN_THRESHOLD = 10**-12 # max safe number of constraints (log10) MAX_NUM_CONSTRAINTS = 7 # keeps compatibility with 1.6.x versions of PuLP in which the interface # for solving was the latter one if hasattr(pulp, "__version__"): # new interface from pulp import PULP_CBC_CMD solver = lambda prob: PULP_CBC_CMD(msg=0).solve(prob) else: # old interface solver = lambda prob: prob.solve() def get_terminal_part_name_num(num): """ Gets the terminal part of the name of a variable Parameters --------------- nam Name Returns
def lrs_ilp(s, verbosity=0): if len(s) == 1: return Solution(1, [[s[0]]]) try: try: from pulp import ( LpVariable, LpProblem, LpMaximize, LpInteger, PulpSolverError, ) model = LpProblem("LRS", LpMaximize) # create variables x = [ LpVariable("x_{}".format(i), 0, 1, LpInteger) for i in range(len(s)) ] # node degree for j in range(len(s)): for i in range(j): if s[i].char == s[j].char: model += (j - i) * x[i] + sum([ x[l] if s[l].char != s[i].char else 0 for l in range(i + 1, j) ]) + (j - i) * x[j] <= 2 * (j - i) # objective model += sum([x[i] * s[i].length for i in range(len(s))]) # depending on pulp version, solvers have to be created differently try: from pulp import getSolver, listSolvers solvers = [getSolver(s, msg=0) for s in listSolvers()] except: from pulp import COIN_CMD, PULP_CBC_CMD, PulpSolverError solvers = [COIN_CMD(msg=0), PULP_CBC_CMD(msg=0)] solved = False for solver in solvers: if solved: break try: model.solve(solver) solved = True except PulpSolverError: pass if not solved: raise ImportError sol = [s[i] for i in range(len(s)) if x[i].varValue > 0.999] return Solution(sum([run.length for run in sol]), [sol]) except (ModuleNotFoundError, ImportError) as e: if verbosity == 1: print( "PuLP itself or some of its properties could not be loaded. Solving model with DP instead." ) elif verbosity >= 2: print("Error loading PuLP solver:") print(e) print("Solving model with DP instead.") return lrs_dp(s) except: if verbosity >= 1: print( "Unexpected error occured while loading PuLP. Solving model with DP instead." ) return lrs_dp(s)
def OPT(wcet): task_count, core_count = wcet.shape """ wcet = dict() for task in range(task_count): for cpu in range(core_count): fit_count = 0 #print(M) for i in M[:,cpu]: if i == 1: fit_count += 1 fit_value = 1/fit_count not_fit_value = fit_value + 0.1 if M[task,cpu] == 1: wcet[(task, cpu)] = fit_value else: wcet[(task, cpu)] = not_fit_value """ # Create the model model = LpProblem(name="partition-partition-scheduler", sense=LpMinimize) # Initialize the decision variables x_variables = dict() for t in range(task_count): for j in range(core_count): if (t, j) not in x_variables: x_variables[(t, j)] = LpVariable(name="x_task{}_cpu{}".format(t, j), lowBound=0, cat="Binary") y_variables = dict() for j in range(core_count): if j not in y_variables: y_variables[j] = LpVariable(name="y_{}".format(j), lowBound=0, cat="Binary") # Add the constraints to the model for t in range(task_count): model += (lpSum([x_variables[(t, j)] for j in range(core_count)]) == 1, "One_assignment_constraint{}".format(t)) for j in range(core_count): model += ( lpSum([x_variables[(t, j)] * wcet[t,j] for t in range(task_count)]) <= 1 * y_variables[j], "EDF constraint on CPU{}".format(j)) # Add the objective function to the model obj_func = lpSum(y_variables) model += obj_func # The problem data is written to an .lp file model.writeLP("TestProblem.lp") # Solve the problem #status = model.solve() status = None time_limit = 900 status = model.solve(PULP_CBC_CMD(msg=0, timeLimit=time_limit, threads=1)) #print("-------------------------------------------------------") #print(f"status: {model.status}, {LpStatus[model.status]}") #print(f"objective: {model.objective.value()}") #for var in model.variables(): # print(f"{var.name}: {var.value()}") #for name, constraint in model.constraints.items(): # print(f"{name}: {constraint.value()}") #print("Solver: {}".format(model.solver)) if model.solutionTime > time_limit: return np.inf, LpStatus[model.status] elif status == 1: return model.objective.value(), LpStatus[model.status] else: #print("OPT is not optimal solution! Reason: {}".format(LpStatus[model.status])) return np.inf, LpStatus[model.status]
def optimize_scenario(rate_of_return_6m: float, rate_of_return_12m: float, rsu_witholding_rate: float, current_state_ltcg_tax_rate: float, current_state_stcg_tax_rate: float, new_state_ltcg_tax_rate: float, new_state_stcg_tax_rate: float, federal_ltcg_tax_rate: float, federal_stcg_tax_rate: float, share_basis_price: float, pre_tax_num_shares: float, alternate_investment_rate_of_return: float, moving_costs: float, debug: bool = False) -> dict: """ This is the meat of the script that calculates the optimal number of shares to sell for short and long term tax rates and in your current or new state. It models this as a linear programming problem, which finds the variable values that maximize the objective function given constraints. :param rate_of_return_6m: The 6-month rate of return for your shares for the first six months after IPO :param rate_of_return_12m: The 6-month rate of return for your shares for the second six months after IPO :param rsu_witholding_rate: How many of your vested shares are withheld for taxes (typically, companies withhold 22 percent) :param current_state_ltcg_tax_rate: The long term capital gains tax rate of your current state (if no separate rate exists, you likely should use your marginal state income tax rate) :param current_state_stcg_tax_rate: The short term capital gains tax rate of you current state :param new_state_ltcg_tax_rate: The long term capital gains tax rate of you prospective new state :param new_state_stcg_tax_rate: The short term capital gains tax rate of you prospective new state :param federal_ltcg_tax_rate: The federal long term capital gains tax rate for your shares :param federal_stcg_tax_rate: The federal short term capital gains tax rate for your shares :param share_basis_price: The cost basis of your stock grant, likely the IPO price :param pre_tax_num_shares: Your vested shares that are becoming liquid through IPO :param alternate_investment_rate_of_return: If you sell your shares at 6 months, the rate of return you expect from investing those proceeds elsewhere :param moving_costs: How much more moving to the new state must save you to make it worthwhile to move. Can be actual expenses or a reasonable margin :param debug: Prints out more info about this optimization :return: A dictionary with the parameters of the optimal solution """ # Derived inputs post_tax_num_shares = pre_tax_num_shares * (1 - rsu_witholding_rate) # Create the linear programming model model = LpProblem(name="optimize_returns", sense=LpMaximize) # Variables that will be optimized in the model current_state_stcg_num_shares = LpVariable(name="current_state_stcg_num_shares", lowBound=0, upBound=post_tax_num_shares) current_state_ltcg_num_shares = LpVariable(name="current_state_ltcg_num_shares", lowBound=0, upBound=post_tax_num_shares) new_state_stcg_num_shares = LpVariable(name="new_state_stcg_num_shares", lowBound=0, upBound=post_tax_num_shares) new_state_ltcg_num_shares = LpVariable(name="new_state_ltcg_num_shares", lowBound=0, upBound=post_tax_num_shares) is_moving = LpVariable(name="is_moving", lowBound=0, upBound=1, cat="Integer") # Calculations used in the constraints and objective functions below short_term_price = share_basis_price * rate_of_return_6m long_term_price = short_term_price * rate_of_return_12m current_state_stcg = current_state_stcg_num_shares * (short_term_price - share_basis_price) current_state_ltcg = current_state_ltcg_num_shares * (long_term_price - share_basis_price) new_state_stcg = new_state_stcg_num_shares * (short_term_price - share_basis_price) new_state_ltcg = new_state_ltcg_num_shares * (long_term_price - share_basis_price) current_state_short_term_proceeds = current_state_stcg_num_shares * short_term_price current_state_alternate_investment_gain = (current_state_short_term_proceeds * alternate_investment_rate_of_return) \ - current_state_short_term_proceeds new_state_short_term_proceeds = new_state_stcg_num_shares * short_term_price new_state_alternate_investment_gain = (new_state_short_term_proceeds * alternate_investment_rate_of_return) \ - new_state_short_term_proceeds total_capital_gains = current_state_stcg + new_state_stcg + current_state_ltcg + new_state_ltcg \ + current_state_alternate_investment_gain + new_state_alternate_investment_gain post_tax_capital = post_tax_num_shares * share_basis_price # Constraints of the model model += (post_tax_num_shares == current_state_stcg_num_shares + current_state_ltcg_num_shares + new_state_stcg_num_shares + new_state_ltcg_num_shares, "total_shares_sum") # Makes is_moving a flag dependent on whether we have new_state capital gains model += (is_moving <= (new_state_stcg_num_shares + new_state_ltcg_num_shares), "new_state_shares_sold_dependency") model += ((new_state_stcg_num_shares + new_state_ltcg_num_shares) <= is_moving * post_tax_num_shares, "new_state_shares_sold_flag") # Objective function we are optimizing total_earnings = (post_tax_capital + total_capital_gains) \ - current_state_stcg * (federal_stcg_tax_rate + current_state_stcg_tax_rate) \ - current_state_ltcg * (federal_ltcg_tax_rate + current_state_ltcg_tax_rate) \ - new_state_stcg * (federal_stcg_tax_rate + new_state_stcg_tax_rate) \ - new_state_ltcg * (federal_ltcg_tax_rate + new_state_ltcg_tax_rate) \ - current_state_alternate_investment_gain * (federal_stcg_tax_rate + current_state_stcg_tax_rate) \ - new_state_alternate_investment_gain * (federal_stcg_tax_rate + new_state_stcg_tax_rate) \ - moving_costs * is_moving model += total_earnings msg = False if debug: msg = True status = model.solve(PULP_CBC_CMD(msg=msg)) if status != 1: print(f"status: {model.status}, {LpStatus[model.status]}") raise Exception("No solution for scenario") if debug: print(model) for name, constraint in model.constraints.items(): print(f"{name}: {constraint.value()}") for var in model.variables(): print(f"{var.name}: {var.value()}") results = { "short_term_price": short_term_price, "long_term_price": long_term_price, "rate_of_return_6m": rate_of_return_6m, "rate_of_return_12m": rate_of_return_12m, "objective": model.objective.value(), } for var in model.variables(): results[var.name] = var.value() return results
class PuLPSolver(Solver): LP_SOLVER = PULP_CBC_CMD(msg=False) def __init__(self): self.prob = LpProblem('pydfs_lineup_optimizer', LpMaximize) def setup_solver(self): pass def add_variable(self, name, min_value=None, max_value=None): name = name.replace(' ', '_') if any([min_value, max_value]): return LpVariable(name, lowBound=min_value, upBound=max_value, cat=LpInteger) return LpVariable(name, cat=LpBinary) def set_objective(self, variables, coefficients): self.prob += lpSum([ variable * coefficient for variable, coefficient in zip(variables, coefficients) ]) def add_constraint(self, variables, coefficients, sign, rhs, name=None): if coefficients: lhs = [ variable * coefficient for variable, coefficient in zip(variables, coefficients) ] else: lhs = variables if sign == SolverSign.EQ: self.prob += lpSum(lhs) == rhs, name elif sign == SolverSign.NOT_EQ: self.prob += lpSum(lhs) != rhs, name elif sign == SolverSign.GTE: self.prob += lpSum(lhs) >= rhs, name elif sign == SolverSign.LTE: self.prob += lpSum(lhs) <= rhs, name else: raise SolverException('Incorrect constraint sign') def copy(self): new_solver = type(self)() new_solver.prob = self.prob.copy() return new_solver def solve(self): self.prob.solve(self.LP_SOLVER) if self.prob.status == LpStatusOptimal: result = [] for variable in self.prob.variables(): val = variable.value() if val is not None and round(val) >= 1.0: result.append(variable) return result else: invalid_constraints = [ (name or str(constraint)) for name, constraint in self.prob.constraints.items() if not constraint.valid() ] raise SolverInfeasibleSolutionException(invalid_constraints)
bincolumns = [ col for col in df.columns if len(df[col].unique()) <= 3 and col != "page" ] df = df.rename(columns={name: name + "bin" for name in bincolumns}) intcolumns = [ col for col in df.columns if len(df[col].unique()) > 3 and col != "page" ] df = df.rename(columns={name: name + "int" for name in intcolumns}) #End Preprocessing step print "Total rows (M) after preprocessing: %i" % len(df) #Start Solving Rank LP's #specify solving method (add more here for whichever methods are installed) solver = PULP_CBC_CMD() #default, comes with pulp #solver=GLPK() ####2016-10-08 [Evan] Make upper/lower bounds variable #upperA = 100 ###(default 10) ###copy this into params: ubound_a=upperA #upperV = 100 ###(default 100) ###copy this into params: ubound_v=upperV #lowerA = .001 ###(default .01) ###copy this into params: lbound_a=lowerA lowerV = 1 ###(default .01) ###copy this into params: lbound_v=lowerV pageset = {1: range(1, 2), 2: range(2, 4), 3: range(4, 8)} #### NEED TO ADD: progressbar threshes = {"bin": (.5, 2, 8), "int": (.02, .1, 1)} threshloop = [(a, b) for a in threshes["bin"] for b in threshes["int"]]