def test(cas_conn): m = so.Model(name='nlpse02', session=cas_conn) N = m.add_parameter(name='N', init=1000) x = m.add_variables(so.exp_range(1, N), name='x', init=1) m.set_objective(so.quick_sum(-4 * x[i] + 3 for i in so.exp_range(1, N - 1)) + so.quick_sum((x[i]**2 + x[N]**2)**2 for i in so.exp_range(1, N - 1)), name='f', sense=so.MIN) m.add_statement('print x;', after_solve=True) m.solve(options={'with': 'nlp'}, verbose=True) print(m.response['Print3.PrintTable']) # Model 2 so.reset_globals() m = so.Model(name='nlpse02_2', session=cas_conn) N = m.add_parameter(name='N', init=1000) x = m.add_variables(so.exp_range(1, N), name='x', lb=1, ub=2) m.set_objective(so.quick_sum( sm.cos(-0.5 * x[i + 1] - x[i]**2) for i in so.exp_range(1, N - 1)), name='f2', sense=so.MIN) m.add_statement('print x;', after_solve=True) m.solve(verbose=True, options={'with': 'nlp', 'algorithm': 'activeset'}) print(m.get_solution_summary()) return m.get_objective_value()
def test(cas_conn, sols=False): m = so.Model(name='multiobjective', session=cas_conn) x = m.add_variables([1, 2], lb=0, ub=5, name='x') f1 = m.set_objective((x[1] - 1)**2 + (x[1] - x[2])**2, name='f1', sense=so.MIN) f2 = m.append_objective((x[1] - x[2])**2 + (x[2] - 3)**2, name='f2', sense=so.MIN) m.solve(verbose=True, options={ 'with': 'blackbox', 'obj': (f1, f2), 'logfreq': 50 }) print('f1', f1.get_value()) print('f2', f2.get_value()) if sols: return dict(solutions=cas_conn.CASTable('allsols').to_frame(), x=x, f1=f1, f2=f2) else: return f1.get_value()
def test(cas_conn, num_guests=20, max_table_size=3, max_tables=None): m = so.Model("wedding", session=cas_conn) # Check max. tables if max_tables is None: max_tables = math.ceil(num_guests / max_table_size) # Sets guests = range(1, num_guests + 1) tables = range(1, max_tables + 1) guest_pairs = [[i, j] for i in guests for j in range(i + 1, num_guests + 1)] # Variables x = m.add_variables(guests, tables, vartype=so.BIN, name="x") unhappy = m.add_variables(tables, name="unhappy", lb=0) # Objective m.set_objective(unhappy.sum('*'), sense=so.MIN, name="obj") # Constraints m.add_constraints((x.sum(g, '*') == 1 for g in guests), name="assigncon") m.add_constraints((x.sum('*', t) <= max_table_size for t in tables), name="tablesizecon") m.add_constraints((unhappy[t] >= abs(g - h) * (x[g, t] + x[h, t] - 1) for t in tables for [g, h] in guest_pairs), name="measurecon") # Solve res = m.solve(options={ 'with': 'milp', 'decomp': { 'method': 'set' }, 'presolver': 'none' }) if res is not None: print(so.get_solution_table(x)) # Print assignments for t in tables: print('Table {} : [ '.format(t), end='') for g in guests: if x[g, t].get_value() == 1: print('{} '.format(g), end='') print(']') return m.get_objective_value()
def test(cas_conn, data=None): # Use default data if not passed if data is None: data = pd.DataFrame([ [4, 8, 43.71], [62, 5, 351.29], [81, 62, 2878.91], [85, 75, 3591.59], [65, 54, 2058.71], [96, 84, 4487.87], [98, 29, 1773.52], [36, 33, 767.57], [30, 91, 1637.66], [3, 59, 215.28], [62, 57, 2067.42], [11, 48, 394.11], [66, 21, 932.84], [68, 24, 1069.21], [95, 30, 1770.78], [34, 14, 368.51], [86, 81, 3902.27], [37, 49, 1115.67], [46, 80, 2136.92], [87, 72, 3537.84], ], columns=['x1', 'x2', 'y']) m = so.Model(name='least_squares', session=cas_conn) # Regression model: L(a,b,c) = a * x1 + b * x2 + c * x1 * x2 a = m.add_variable(name='a') b = m.add_variable(name='b') c = m.add_variable(name='c') x1 = data['x1'] x2 = data['x2'] y = data['y'] err = m.add_implicit_variable( (y[i] - (a * x1[i] + b * x2[i] + c * x1[i] * x2[i]) for i in data.index), name='error') m.set_objective(so.expr_sum(err[i]**2 for i in data.index), sense=so.MIN, name='total_error') m.solve(verbose=True, options={'with': 'nlp'}) return m.get_objective_value()
def test(cas_conn): m = so.Model(name='nlpse01', session=cas_conn) x = m.add_variables(range(1, 9), lb=0.1, ub=10, name='x') f = so.Expression(0.4 * (x[1] / x[7])**0.67 + 0.4 * (x[2] / x[8])**0.67 + 10 - x[1] - x[2], name='f') m.set_objective(f, sense=so.MIN, name='f1') m.add_constraint(1 - 0.0588 * x[5] * x[7] - 0.1 * x[1] >= 0, name='c1') m.add_constraint(1 - 0.0588 * x[6] * x[8] - 0.1 * x[1] - 0.1 * x[2] >= 0, name='c2') m.add_constraint(1 - 4 * x[3] / x[5] - 2 / (x[3]**0.71 * x[5]) - 0.0588 * (x[7] / x[3]**1.3) >= 0, name='c3') m.add_constraint(1 - 4 * x[4] / x[6] - 2 / (x[4]**0.71 * x[6]) - 0.0588 * (x[8] / x[4]**1.3) >= 0, name='c4') m.add_constraint(f == [0.1, 4.2], name='frange') x[1].set_init(6) x[2].set_init(3) x[3].set_init(0.4) x[4].set_init(0.2) x[5].set_init(6) x[6].set_init(6) x[7].set_init(1) x[8].set_init(0.5) m.solve(verbose=True, options={'with': 'nlp', 'algorithm': 'activeset'}) print(m.get_problem_summary()) print(m.get_solution_summary()) if m.get_session_type() == 'CAS': print(m.get_solution()[['var', 'value']]) return m.get_objective_value()
def solve_maximin_problem(gw, options=None): if options is None: options = dict() data = get_multistage_data(gw, n=1) base_folder = pathlib.Path().resolve() output_folder = pathlib.Path(base_folder / f"build/work/") output_folder.mkdir(parents=True, exist_ok=True) options['output_folder'] = output_folder gw = data['gw'] players = data['elements'] types = data['types'] types_df = data['types_df'] next_week_df = data['element_gameweek_df'] team_codes = data['team_codes'] element_df = data['element_df'] element_df['value'] = [next_week_df.loc[i, gw]['points_md'] / element_df.loc[i]['now_cost'] * 10 for i in element_df.index] sorted_elements = element_df.sort_values(by=['element_type', 'id'], ascending=[True, True], ignore_index=False) max_xp = next_week_df['points_md'].max() m = so.Model(name='o_ring_max_min_problem', session=None) x = m.add_variables(players, name='lineup', vartype=so.BIN) z = m.add_variables(players, name='squad', vartype=so.BIN) m.add_constraint(so.quick_sum(x[i] for i in players) == 11, name='lineup_limit') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types), name='squad_min') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types), name='squad_max') # Limit constraints m.add_constraints(( so.quick_sum(z[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(z[i] for i in players) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(z[i] for i in players if next_week_df.loc[i, gw]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') m.add_constraint( so.quick_sum(z[i] * next_week_df.loc[i, gw]['now_cost'] for i in players) <= 1000, name='total_cost_100') m.add_constraints( (x[i] <= z[i] for i in players), name='lineup_squad_con') total_lineup_xp = so.quick_sum(next_week_df.loc[i, gw]['points_md'] * x[i] for i in players) # total_squad_xp = so.quick_sum(next_week_df.loc[i, gw]['points_md'] * z[i] for i in players) total_eff_value = so.quick_sum(element_df.loc[i]['value'] * x[i] for i in players) total_ownership = so.quick_sum(element_df.loc[i]['selected_by_percent'] * x[i] for i in players) total_xp_per_type = [so.quick_sum(next_week_df.loc[i, gw]['points_md'] * x[i] for i in players if element_df.loc[i]['element_type'] == k) for k in types] min_lineup_xp = lambda: min(next_week_df.loc[i, gw]['points_md'] for i in players if x[i].get_value() > 0.5) min_eff_value = lambda: min(element_df.loc[i]['value'] for i in players if x[i].get_value() > 0.5) min_ownership = lambda: min(element_df.loc[i]['selected_by_percent'] for i in players if x[i].get_value() > 0.5) min_xp_per_type = lambda: [round(min(next_week_df.loc[i, gw]['points_md'] for i in players if element_df.loc[i]['element_type'] == k and x[i].get_value() > 0.5),2) for k in types] get_lineup = lambda: ', '.join([sorted_elements.loc[e].web_name for e in sorted_elements.index if x[e].get_value() > 0.5]) get_sol_summary = lambda: { 'problem_name': problem_name, 'total_lineup_xp': round(total_lineup_xp.get_value(), 3), 'total_eff_value': round(total_eff_value.get_value(), 3), 'total_ownership': round(total_ownership.get_value(), 1), 'total_xp_per_type': [round(i.get_value(),3) for i in total_xp_per_type], 'min_linuep_xp': round(min_lineup_xp(), 3), 'min_eff_value': round(min_eff_value(), 3), 'min_ownership': round(min_ownership(), 1), 'min_xp_per_type': min_xp_per_type(), 'lineup': get_lineup()} comp_values = [] # Stage 0 - Lineup maximization m.set_objective(-total_lineup_xp, sense='N', name='regular_obj') problem_name = f"GW{gw}_maximin_0_base" solve_and_save_to_file(m, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 1 - Stage 1 - Max-min for i in players: x[i].set_value(0) z[i].set_value(0) m1 = so.Model(name='maximin') m1.include(m) w = m1.add_variable(name='weakest_link',vartype=so.CONT) m1.add_constraints( (w <= x[i] * next_week_df.loc[i, gw].points_md + (1-x[i]) * max_xp for i in players), name='weakest_link_con') m1.set_objective(-w, sense='N', name='max_min_obj') problem_name = f"GW{gw}_maximin_1_1_maximin" solve_and_save_to_file(m1, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 1 - Stage 2 - Max Lineup xP for i in players: x[i].set_value(0) z[i].set_value(0) m1.add_constraint(w >= w.get_value(), name='w_lb') m1.set_objective(-total_lineup_xp, sense='N', name='max_lineup') problem_name = f"GW{gw}_maximin_1_2_maximin" solve_and_save_to_file(m1, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # # Problem 1 - Stage 3 - Max Squad xP # m.add_constraints((x[i] >= round(x[i].get_value()) for i in players), name='fix_lineup') # for i in players: # x[i].set_value(0) # z[i].set_value(0) # m.set_objective(-total_squad_xp, sense='N', name='max_squad') # problem_name = f"GW{gw}_maximin_1_3_maximin" # solve_and_save_to_file(m, problem_name, data, options) # Problem 2 - Maximin per position for i in players: x[i].set_value(0) z[i].set_value(0) m2 = so.Model(name='maximin_per_position') m2.include(m) w = m2.add_variable('w', vartype=so.CONT) # w_type = m2.add_variables(types, name='weakest_link_pos') # m2.add_constraints( # (w_type[k] <= x[i] * next_week_df.loc[i, gw].points_md + (1-x[i]) * max_xp for i in players for k in types if element_df.loc[i]['element_type'] == k), name='weakest_link_type_con') # m2.set_objective(-so.quick_sum(w_type[k] for k in types), sense='N', name='type_max') m2.add_constraints( (w <= so.quick_sum(x[i] * next_week_df.loc[i, gw].points_md for i in players if element_df.loc[i]['element_type'] == k) for k in types if k != 1), name='weakest_link_type_con') m2.set_objective(-w, sense='N', name='type_max') problem_name = f"GW{gw}_maximin_2_1_pos" solve_and_save_to_file(m2, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 2 - Stage 2 for i in players: x[i].set_value(0) z[i].set_value(0) m2.add_constraint(w >= w.get_value(), name='w_lb') m2.set_objective(-total_lineup_xp, sense='N', name='max_lineup') problem_name = f"GW{gw}_maximin_2_2_pos" solve_and_save_to_file(m2, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 3 - Stage 1 - Maximin for Value for i in players: x[i].set_value(0) z[i].set_value(0) m3 = so.Model(name='maximin_per_position') m3.include(m) w = m3.add_variable(name='lowest_val',vartype=so.CONT) max_val = element_df['value'].max() m3.add_constraints( (w <= x[i] * element_df.loc[i].value + (1-x[i]) * max_val for i in players), name='lowest_val') m3.set_objective(-w, sense='N', name='max_min_value') problem_name = f"GW{gw}_maximin_3_1_val" solve_and_save_to_file(m3, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 3 - Stage 2 for i in players: x[i].set_value(0) z[i].set_value(0) m3.add_constraint(w >= w.get_value(), name='w_lb') m3.set_objective(-total_lineup_xp, sense='N', name='max_min_value') problem_name = f"GW{gw}_maximin_3_2_val" solve_and_save_to_file(m3, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 4 - Stage 1 - Ownership for i in players: x[i].set_value(0) z[i].set_value(0) m4 = so.Model(name='maximin_per_position') m4.include(m) w = m4.add_variable(name='lowest_own',vartype=so.CONT) max_own = element_df['selected_by_percent'].max() m4.add_constraints( (w <= x[i] * element_df.loc[i].selected_by_percent + (1-x[i]) * max_own for i in players), name='lowest_owned') m4.set_objective(-w, sense='N', name='max_min_owner') problem_name = f"GW{gw}_maximin_4_1_own" solve_and_save_to_file(m4, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) # Problem 4 - Stage 2 for i in players: x[i].set_value(0) z[i].set_value(0) m4.add_constraint(w >= w.get_value(), name='w_lb') m4.set_objective(-total_lineup_xp, sense='N', name='max_min_value') problem_name = f"GW{gw}_maximin_4_2_own" solve_and_save_to_file(m4, problem_name, data, options) comp_values.append(get_sol_summary()) print(comp_values) comp_values_df = pd.DataFrame(comp_values) comp_values_df.to_excel(output_folder / f"GW{gw}_o_ring_summary.xlsx") print(comp_values_df) return 0
def solve_best_set_and_forget(input_folder, output_folder): """Solves the budget (1000) and team limited best squad (lineup+subs) with weighted bench total of 8 gameweeks""" df = pd.read_csv(input_folder / 'element_gameweek.csv') # next_week = df['event'].min() # next_week_df = df[df['event'] == next_week].copy() df = df.groupby(['player_id', 'event'], as_index=False).first() next_week_df = df.groupby(['player_id', 'web_name', 'team'])['points_md'].sum() next_week_df = next_week_df.reset_index() df = pd.read_csv(input_folder / 'element.csv') next_week_df = pd.merge(left=next_week_df, right=df, how='inner', left_on=['player_id'], right_on=['id'], suffixes=('', '_extra')) players = next_week_df['player_id'].unique().tolist() next_week_df.set_index('player_id', inplace=True, drop=True) team_codes = next_week_df['team_code'].unique().tolist() types_df = pd.read_csv(input_folder / 'element_type.csv') types = types_df['id'].to_list() types_df.set_index('id', inplace=True, drop=True) m = so.Model(name='limited_best_15_weighted', session=None) x = m.add_variables(players, name='lineup', vartype=so.BIN) y = m.add_variables(players, name='captain', vartype=so.BIN) z = m.add_variables(players, name='squad', vartype=so.BIN) m.add_constraint(so.quick_sum(x[i] for i in players) == 11, name='lineup_limit') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types), name='squad_min') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types), name='squad_max') m.add_constraint(so.quick_sum(y[i] for i in players) == 1, name='single_captain') m.add_constraints((y[i] <= x[i] for i in players), name='captain_should_play') # Limit constraints m.add_constraints(( so.quick_sum(z[i] for i in players if next_week_df.loc[i]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(z[i] for i in players) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(z[i] for i in players if next_week_df.loc[i]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') m.add_constraint( so.quick_sum(z[i] * next_week_df.loc[i]['now_cost'] for i in players) <= 1000, name='total_cost_100') m.add_constraints( (x[i] <= z[i] for i in players), name='lineup_squad_con') m.set_objective(so.quick_sum( -next_week_df.loc[i]['points_md'] * (x[i]+y[i]+0.1*(z[i]-x[i])) for i in players ), sense='N', name='maximize_points') mps_str = get_mps_string(m) with open(output_folder / "limited_best_set_and_forget.mps", "w") as f: f.write(mps_str) filename = str(output_folder / "limited_best_set_and_forget.mps") solutionname = str(output_folder / "limited_best_set_and_forget.sol") csvname = str(output_folder / "limited_best_set_and_forget.csv") solve_and_get_solution(filename, solutionname, m) # Parse solution selected_players = [] for i in players: if z[i].get_value() > 0.5 and x[i].get_value() < 0.5: selected_players.append([i, 0, False, 0]) elif x[i].get_value() > 0.5 and y[i].get_value() < 0.5: selected_players.append([i, 1, False, 1]) elif x[i].get_value() > 0.5 and y[i].get_value() > 0.5: selected_players.append([i, 2, True, 1]) results = pd.DataFrame(selected_players, columns=['player_id', 'multiplier', 'is_captain', 'starting_lineup']) result_df = pd.merge(next_week_df, results, on='player_id', how='inner') result_df = result_df[['player_id', 'web_name', 'team_code', 'element_type', 'now_cost', 'points_md', 'is_captain', 'multiplier', 'starting_lineup', 'selected_by_percent']].copy() result_df['points_md'] = result_df['points_md'] / 8 result_df['gw_points'] = result_df['multiplier'] * result_df['points_md'] result_df = result_df.sort_values(by=['starting_lineup', 'element_type', 'player_id'], ascending=[False, True, True], ignore_index=True) result_df.reset_index(drop=True, inplace=True) result_df.to_csv(csvname, encoding='utf-8') with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.encoding', 'UTF-8'): print(result_df) print(m.get_objective_value())
def solve_iterative_squads(input_folder, output_folder, total_iter=50): """Solves for best squads iteratively for generating an interactive list""" df = pd.read_csv(input_folder / 'element_gameweek.csv') next_week = df['event'].min() element_gameweek_df = df[df['event'] < next_week+3].copy() sum_md_df = element_gameweek_df.groupby(['player_id', 'web_name'])['points_md'].sum() sum_md_df.sort_values(inplace=True, ascending=False) sum_md_df = sum_md_df.reset_index().set_index('player_id').copy() df = pd.read_csv(input_folder / 'element.csv') element_df = df.copy().set_index('id') element_df['ict_sum'] = element_df['influence'] + element_df['creativity'] + element_df['threat'] element_gameweek_df = pd.merge(left=element_gameweek_df, right=df, how='inner', left_on=['player_id'], right_on=['id'], suffixes=('', '_extra')) element_gameweek_df['rawxp'] = element_gameweek_df.apply(lambda r: r['points_md'] * 90 / max(1, r['xmins_md']), axis=1) elements = element_gameweek_df['player_id'].unique().tolist() gameweeks = element_gameweek_df['event'].unique().tolist() total_weeks = len(gameweeks) element_gameweek_df.set_index(['player_id', 'event'], inplace=True, drop=True) popular_element_df = element_df.sort_values(by=['selected_by_percent'], ascending=False)[['web_name', 'selected_by_percent']] team_codes = element_gameweek_df['team_code'].unique().tolist() types_df = pd.read_csv(input_folder / 'element_type.csv') types = types_df['id'].to_list() types_df.set_index('id', inplace=True, drop=True) position = [1,2,3,4] element_gameweek = [(e, g) for e in elements for g in gameweeks] m = so.Model(name='iterative_model', session=None) lineup = m.add_variables(elements, gameweeks, name='lineup', vartype=so.BIN) captain = m.add_variables(elements, gameweeks, name='captain', vartype=so.BIN) squad = m.add_variables(elements, name='squad', vartype=so.BIN) bench = m.add_variables(elements, gameweeks, position, name='bench', vartype=so.BIN) m.add_constraints( (so.quick_sum(lineup[e, g] for e in elements) == 11 for g in gameweeks), name='lineup_limit_per_week') m.add_constraints(( so.quick_sum(lineup[e, g] for e in elements if element_df.loc[e]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types for g in gameweeks), name='squad_min') m.add_constraints(( so.quick_sum(lineup[e, g] for e in elements if element_df.loc[e]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types for g in gameweeks), name='squad_max') m.add_constraints((so.quick_sum(captain[e, g] for e in elements) == 1 for g in gameweeks), name='single_captain') m.add_constraints((captain[e, g] <= lineup[e, g] for e in elements for g in gameweeks), name='captain_should_play') # Limit constraints m.add_constraints(( so.quick_sum(squad[e] for e in elements if element_df.loc[e]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(squad[e] for e in elements) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(squad[e] for e in elements if element_df.loc[e]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') # m.add_constraint( # so.quick_sum(squad[i] * next_week_df.loc[i]['now_cost'] for i in players) <= 1000, # name='total_cost_100') m.add_constraints( (lineup[e, g] <= squad[e] for e in elements for g in gameweeks), name='lineup_squad_con') m.add_constraints( (bench[e, g, p] <= squad[e] for e in elements for g in gameweeks for p in position), name='bench_squad_con') m.add_constraints( (so.quick_sum(bench[e, g, p] for e in elements) == 1 for g in gameweeks for p in position), name='bench_position_con') m.add_constraints( (so.quick_sum(bench[e, g, 1] for e in elements if element_df.loc[e]['element_type'] == 1) == 1 for g in gameweeks), name='only_gk_bench1') m.add_constraints( (lineup[e, g] + so.quick_sum(bench[e, g, p] for p in position) == squad[e] for e in elements for g in gameweeks), name='lineup_plus_bench_equal_squad') # Budget Constraint budget_con = m.add_constraint(so.quick_sum(squad[e] * element_df.loc[e]['now_cost'] for e in elements) <= 1000, name='budget_con') # Every player should play at least once m.add_constraints((so.quick_sum(lineup[e,g] for g in gameweeks) >= squad[e] for e in elements), name='play_at_least_once') total_points = so.quick_sum(element_gameweek_df.loc[e, g]['points_md'] * (lineup[e, g]+ captain[e,g] + so.quick_sum(bench[e,g,p]*10**min(-p+1, -1) for p in position)) for e in elements for g in gameweeks) / total_weeks / element_gameweek_df['points_md'].max() cost_points = so.quick_sum(element_df.loc[e]['now_cost'] * squad[e] for e in elements) / element_df['now_cost'].max() xmin_points = so.quick_sum(element_gameweek_df.loc[e, g]['xmins_md']*lineup[e,g] for e in elements for g in gameweeks) / total_weeks / element_gameweek_df['xmins_md'].max() ep_points = so.quick_sum(element_df.loc[e]['ep_this'] * lineup[e, next_week] for e in elements) / element_df['ep_this'].max() form_points = so.quick_sum(element_df.loc[e]['form'] * lineup[e, next_week] for e in elements) / element_df['form'].max() ppg_points = so.quick_sum(element_df.loc[e]['points_per_game'] * lineup[e, next_week] for e in elements) / element_df['points_per_game'].max() bps_points = so.quick_sum(element_df.loc[e]['bps'] * lineup[e, next_week] for e in elements) / element_df['bps'].max() ict_points = so.quick_sum(element_df.loc[e]['ict_sum'] * lineup[e, next_week] for e in elements) / element_df['ict_sum'].max() rawxP_points = so.quick_sum(element_gameweek_df.loc[e, g]['rawxp'] * lineup[e, g] for e in elements for g in gameweeks) / total_weeks / element_gameweek_df['rawxp'].max() ownership_points = so.quick_sum(element_gameweek_df.loc[e, g]['points_md']*(1-lineup[e, g])*element_df.loc[e]['selected_by_percent']/100.0 for e in elements for g in gameweeks) / total_weeks / element_gameweek_df['points_md'].max() m.set_objective(-total_points, sense='N', name='maximize_points') name = "iterative_model" filename = str(output_folder / f"{name}.mps") solutionname = str(output_folder / f"{name}.sol") csvname = str(output_folder / f"{name}.csv") all_solutions = [] w1 = 1 w2 = w3 = w4 = w5 = w6 = w7 = w8 = w9 = w10 = 0 random.seed(42) for iteration in range(total_iter): if iteration > 0: # add squad cut m.add_constraint(so.quick_sum(squad[e] for e in elements if squad[e].get_value() > 0.5) <= 12, name=f"cutoff_{iteration}") # change objective w1, w2, w3, w4, w5, w6, w7, w8, w9 = (random.random() for _ in range(9)) w10 = random.random()*2-1 # m.set_objective(- ( # w1 * total_points + w2 * cost_points + w3 * xmin_points + w4 * ep_points + w5 * form_points + w6 * ppg_points + w7 * bps_points + w8 * ict_points + w9 * rawxP_points + w10 * ownership_points), # sense='N', name=f'obj_{iteration}') # # Idea 1: Discard most popular/owned 1 out of 3 players # selected_ids = [e for e in elements if squad[e].get_value() > 0.5] # selected_els_df = popular_element_df[popular_element_df.index.isin(selected_ids)] # top3_els = selected_els_df.index[:3].to_list() # print('Popular cut', selected_els_df.loc[top3_els]['web_name']) # m.add_constraint(so.quick_sum(squad[e] for e in top3_els) <= 2, name=f'popular_cut_{iteration}') # # Idea 2: Discard player with most return 1 out of 3 players # selected_els_df = sum_md_df[sum_md_df.index.isin(selected_ids)] # top3_els = selected_els_df.index[:3].to_list() # print('Return cut', selected_els_df.loc[top3_els]['web_name']) # m.add_constraint(so.quick_sum(squad[e] for e in top3_els) <= 2, name=f'return_cut_{iteration}') # # Idea 3: Discard 3 players each time # # add position cuts # # m.add_constraints((so.quick_sum(squad[e] for e in elements if squad[e].get_value() > 0.5 and element_df.loc[e]['element_type'] == et) <= types_df.loc[et]['squad_select']-1 for et in types), name=f"el_type_cutoff_{iteration}") # # add squad cut # # m.add_constraint(so.quick_sum(squad[e] for e in elements if squad[e].get_value() > 0.5) <= 14, name=f"cutoff_{iteration}") # # budget_adj = iteration // 5 # # budget_con.set_rhs(1050 - budget_adj*10) # # m.set_objective(total_points - ownership_weight*missed_ownership_points - budget_weight*cost_value_points, sense='N', name=f'obj_b{budget_weight}_o{ownership_weight}') # # m.set_objective(total_points - ownership_weight*missed_ownership_points, sense='N', name=f'obj_o{ownership_weight}') mps_str = get_mps_string(m) with open(output_folder / f"{name}.mps", "w") as f: f.write(mps_str) for v in m.get_variables(): v.set_value(0) solve_and_get_solution(filename, solutionname, m) print(f"DONE {iteration}") # Parse solution solution = {"id": iteration, "squad":[], "lineup": {g:[] for g in gameweeks}, "bench": {g:{} for g in gameweeks}, "captain": {g: 0 for g in gameweeks}, "ownership": {}} for e in elements: if squad[e].get_value() > 0.5: solution['squad'].append(e) for e in elements: for g in gameweeks: if lineup[e, g].get_value() > 0.5: solution['lineup'][g].append(e) elif squad[e].get_value() > 0.5: for p in position: if bench[e, g, p].get_value() > 0.5: solution['bench'][g][p] = e if captain[e, g].get_value() > 0.5: solution['captain'][g] = e # solution["params"] = {'ownership_weight': ownership_weight} # 'cost_weight': budget_weight, solution["params"] = {'pts_weight': w1, 'cost_weight': w2, 'xmin_weight': w3, 'ep_weight': w4, 'form_weight': w5, 'ppg_weight': w6, 'bps_weight': w7, 'ict_weight': w8, 'rawxp_weight': w9, 'ownership_weight': w10} solution["players"] = [element_df.loc[e]['web_name'] for e in solution['squad']] solution["xP"] = {g: [element_gameweek_df.loc[e, g]['points_md'] for e in solution['squad']] for g in gameweeks} solution["obj"] = {"overall": m.get_objective_value(), "total_points": total_points.get_value(), "cost_points": cost_points.get_value(), "xmin_points": xmin_points.get_value(), "ep_points": ep_points.get_value(), "form_points": form_points.get_value(), "ppg_points": ppg_points.get_value(), "bps_points": bps_points.get_value(), "ict_points": ict_points.get_value(), "rawxP_points": rawxP_points.get_value(), "ownership_points": ownership_points.get_value()} #, "missed_ownership_points": missed_ownership_points.get_value()} #, "budget_points": cost_value_points.get_value()} solution["cost"] = [float(element_df.loc[e]['now_cost']) for e in solution['squad']] solution["total_cost"] = sum(solution["cost"]) solution["ownership"]["squad"] = [float(element_df.loc[e]["selected_by_percent"]) for e in solution['squad']] solution["ownership"]["sum"] = sum(solution["ownership"]["squad"]) solution["element_type"] = [int(element_df.loc[e]['element_type']) for e in solution['squad']] solution["team_code"] = [int(element_df.loc[e]['team_code']) for e in solution['squad']] solution["weeks"] = gameweeks for g in gameweeks: solution["obj"][g] = so.quick_sum(-element_gameweek_df.loc[e, g]['points_md'] * (lineup[e, g]+ captain[e,g] + so.quick_sum(bench[e,g,p]*10**min(-p+1, -1) for p in position)) for e in elements).get_value() print(solution) print(m.get_objective_value()) all_solutions.append(solution) with open(output_folder / "iterative_model.json", "w") as f: json.dump(all_solutions, f) print(all_solutions)
def test(cas_conn): m = so.Model(name='economic_planning', session=cas_conn) industry_data = pd.DataFrame([ ['coal', 150, 300, 60], ['steel', 80, 350, 60], ['transport', 100, 280, 30] ], columns=['industry', 'init_stocks', 'init_productive_capacity', 'demand']).set_index(['industry']) production_data = pd.DataFrame([ ['coal', 0.1, 0.5, 0.4], ['steel', 0.1, 0.1, 0.2], ['transport', 0.2, 0.1, 0.2], ['manpower', 0.6, 0.3, 0.2], ], columns=['input', 'coal', 'steel', 'transport']).set_index(['input']) productive_capacity_data = pd.DataFrame([ ['coal', 0.0, 0.7, 0.9], ['steel', 0.1, 0.1, 0.2], ['transport', 0.2, 0.1, 0.2], ['manpower', 0.4, 0.2, 0.1], ], columns=['input', 'coal', 'steel', 'transport']).set_index(['input']) manpower_capacity = 470 num_years = 5 YEARS = list(range(1, num_years+1)) YEARS0 = [0] + list(YEARS) INDUSTRIES = industry_data.index.tolist() [init_stocks, init_productive_capacity, demand] = so.read_frame( industry_data) # INPUTS = production_data.index.tolist() production_coeff = so.flatten_frame(production_data) productive_capacity_coeff = so.flatten_frame(productive_capacity_data) static_production = m.add_variables(INDUSTRIES, lb=0, name='static_production') m.set_objective(0, sense=so.MIN, name='Zero') m.add_constraints((static_production[i] == demand[i] + so.quick_sum( production_coeff[i, j] * static_production[j] for j in INDUSTRIES) for i in INDUSTRIES), name='static_con') m.solve() print(so.get_solution_table(static_production, sort=True)) final_demand = so.get_solution_table( static_production, sort=True)['static_production'] # Alternative way # final_demand = {} # for i in INDUSTRIES: # final_demand[i] = static_production.get_value() production = m.add_variables(INDUSTRIES, range(0, num_years+2), lb=0, name='production') stock = m.add_variables(INDUSTRIES, range(0, num_years+2), lb=0, name='stock') extra_capacity = m.add_variables(INDUSTRIES, range(1, num_years+3), lb=0, name='extra_capacity') productive_capacity = {} for i in INDUSTRIES: for year in range(1, num_years+2): productive_capacity[i, year] = init_productive_capacity[i] +\ so.quick_sum(extra_capacity[i, y] for y in range(2, year+1)) for i in INDUSTRIES: production[i, 0].set_bounds(ub=0) stock[i, 0].set_bounds(lb=init_stocks[i], ub=init_stocks[i]) total_productive_capacity = sum(productive_capacity[i, num_years] for i in INDUSTRIES) total_production = so.quick_sum(production[i, year] for i in INDUSTRIES for year in [4, 5]) total_manpower = so.quick_sum(production_coeff['manpower', i] * production[i, year+1] + productive_capacity_coeff['manpower', i] * extra_capacity[i, year+2] for i in INDUSTRIES for year in YEARS) continuity_con = m.add_constraints(( stock[i, year] + production[i, year] == (demand[i] if year in YEARS else 0) + so.quick_sum(production_coeff[i, j] * production[j, year+1] + productive_capacity_coeff[i, j] * extra_capacity[j, year+2] for j in INDUSTRIES) + stock[i, year+1] for i in INDUSTRIES for year in YEARS0), name='continuity_con') manpower_con = m.add_constraints(( so.quick_sum(production_coeff['manpower', j] * production[j, year] + productive_capacity_coeff['manpower', j] * extra_capacity[j, year+1] for j in INDUSTRIES) <= manpower_capacity for year in range(1, num_years+2)), name='manpower_con') capacity_con = m.add_constraints((production[i, year] <= productive_capacity[i, year] for i in INDUSTRIES for year in range(1, num_years+2)), name='capacity_con') for i in INDUSTRIES: production[i, num_years+1].set_bounds(lb=final_demand[i]) for i in INDUSTRIES: for year in [num_years+1, num_years+2]: extra_capacity[i, year].set_bounds(ub=0) problem1 = so.Model(name='Problem1', session=cas_conn) problem1.include(production, stock, extra_capacity, continuity_con, manpower_con, capacity_con) problem1.set_objective(total_productive_capacity, sense=so.MAX, name='total_productive_capacity') problem1.solve() productive_capacity_fr = so.dict_to_frame(productive_capacity, cols=['productive_capacity']) print(so.get_solution_table(production, stock, extra_capacity, productive_capacity_fr, sort=True)) print(so.get_solution_table(manpower_con.get_expressions(), sort=True)) # Problem 2 problem2 = so.Model(name='Problem2', session=cas_conn) problem2.include(problem1) problem2.set_objective(total_production, name='total_production', sense=so.MAX) for i in INDUSTRIES: for year in YEARS: continuity_con[i, year].set_rhs(0) problem2.solve() print(so.get_solution_table(production, stock, extra_capacity, productive_capacity, sort=True)) print(so.get_solution_table(manpower_con.get_expressions(), sort=True)) # Problem 3 problem3 = so.Model(name='Problem3', session=cas_conn) problem3.include(production, stock, extra_capacity, continuity_con, capacity_con) problem3.set_objective(total_manpower, sense=so.MAX, name='total_manpower') for i in INDUSTRIES: for year in YEARS: continuity_con[i, year].set_rhs(demand[i]) problem3.solve() print(so.get_solution_table(production, stock, extra_capacity, productive_capacity, sort=True)) print(so.get_solution_table(manpower_con.get_expressions(), sort=True)) return problem3.get_objective_value()
def solve_no_limit_best_11(input_folder, output_folder): """Solves the no limit (money/team) best 11 (no full squad) problem""" df = pd.read_csv(input_folder / 'element_gameweek.csv') next_week = df['event'].min() next_week_df = df[df['event'] == next_week].copy() df = pd.read_csv(input_folder / 'element.csv') next_week_df = next_week_df.groupby(['player_id'], as_index=False).first() next_week_df = pd.merge(left=next_week_df, right=df, how='inner', left_on=['player_id'], right_on=['id'], suffixes=('', '_extra')) players = next_week_df['player_id'].unique().tolist() next_week_df.set_index('player_id', inplace=True, drop=True) types_df = pd.read_csv(input_folder / 'element_type.csv') types = types_df['id'].to_list() types_df.set_index('id', inplace=True, drop=True) m = so.Model(name='no_limit_best11', session=None) x = m.add_variables(players, name='lineup', vartype=so.BIN) y = m.add_variables(players, name='captain', vartype=so.BIN) m.add_constraint(so.quick_sum(x[i] for i in players) == 11, name='lineup_limit') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types), name='squad_min') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types), name='squad_max') m.add_constraint(so.quick_sum(y[i] for i in players) == 1, name='single_captain') m.add_constraints((y[i] <= x[i] for i in players), name='captain_should_play') m.set_objective(so.quick_sum( -next_week_df.loc[i]['points_md'] * (x[i]+y[i]) for i in players ), sense='N', name='maximize_points') mps_str = get_mps_string(m) with open(output_folder / "no_limit_best_11.mps", "w") as f: f.write(mps_str) filename = str(output_folder / "no_limit_best_11.mps") solutionname = str(output_folder / "no_limit_best_11.sol") csvname = str(output_folder / "no_limit_best_11.csv") solve_and_get_solution(filename, solutionname, m) # Parse solution selected_players = [] for i in players: if x[i].get_value() > 0.5 and y[i].get_value() < 0.5: selected_players.append([i, 1, False]) elif x[i].get_value() > 0.5 and y[i].get_value() > 0.5: selected_players.append([i, 2, True]) results = pd.DataFrame(selected_players, columns=['player_id', 'multiplier', 'is_captain']) result_df = pd.merge(next_week_df, results, on='player_id', how='inner') result_df = result_df[['player_id', 'web_name', 'team_code', 'element_type', 'now_cost', 'event', 'points_md', 'is_captain', 'multiplier', 'selected_by_percent']].copy() result_df['gw_points'] = result_df['multiplier'] * result_df['points_md'] result_df = result_df.sort_values(by=['element_type', 'player_id'], ignore_index=True) result_df.reset_index(drop=True, inplace=True) result_df.to_csv(csvname, encoding='utf-8') with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.encoding', 'UTF-8'): print(result_df) print(m.get_objective_value())
def solve_multi_week(self, ft, horizon, decay_base=1.0): # ToDo: absorb optimal squad method into this one # compare your own team outcomes with the optimal squad # useful for deciding when to wildcard # ToDo: add parameter for helping to decide on when to use bench boost ''' Solves multi-objective FPL problem with transfers Parameters ---------- ft: integer Number of available free transfers (currently) horizon: integer Number of weeks to consider in optimization decay_base: float Base for the decay function, default of 1 means no decay ''' # Data players = self.forecasts.index positions = self.positions.index teams = self.teams.index current_squad = self.current_squad['player_id'].tolist() itb = self.bank gameweeks = list(range(self.gw, self.gw+horizon)) all_gw = [self.gw-1] + gameweeks # Model model_name = f'w{self.gw}_h{horizon}_d{decay_base}' model = so.Model(model_name) # Variables squad = model.add_variables( players, all_gw, name='squad', vartype=so.binary) lineup = model.add_variables( players, gameweeks, name='lineup', vartype=so.binary) captain = model.add_variables( players, gameweeks, name='captain', vartype=so.binary) vicecap = model.add_variables( players, gameweeks, name='vicecap', vartype=so.binary) transfer_in = model.add_variables( players, gameweeks, name='transfer_in', vartype=so.binary) transfer_out = model.add_variables( players, gameweeks, name='transfer_out', vartype=so.binary) in_the_bank = model.add_variables( all_gw, name='itb', vartype=so.continuous, lb=0) free_transfers = model.add_variables( all_gw, name='ft', vartype=so.integer, lb=1, ub=2) penalized_transfers = model.add_variables( gameweeks, name='pt', vartype=so.integer, lb=0) # artificial binary variable to handle transfer logic aux = model.add_variables( gameweeks, name='aux', vartype=so.binary) # Dictionaries # sell prices of all players sell_price = self.forecasts['sv'].to_dict() # buy prices of all players buy_price = self.forecasts['bv'].to_dict() # total bank earned from selling players across gameweeks sold_amount = {w: so.expr_sum(sell_price[p] * transfer_out[p,w] for p in players) for w in gameweeks} # total bank spent on buying players across gameweeks bought_amount = {w: so.expr_sum(buy_price[p] * transfer_in[p,w] for p in players) for w in gameweeks} # player weekly forecast points points_player_week = {(p,w): self.forecasts.loc[p, f'{w}_pts'] for p in players for w in gameweeks} # number of transfers made each week number_of_transfers = {w: so.expr_sum(transfer_out[p,w] for p in players) for w in gameweeks} # assume one transfer was made last week ?? why ?? number_of_transfers[self.gw-1] = 1 transfer_diff = {w: number_of_transfers[w] - free_transfers[w] for w in gameweeks} # Initial conditions # set squad = 1 for all players currently in squad at previous GW deadline model.add_constraints( (squad[p, self.gw-1] == 1 for p in current_squad), name='initial_squad_players') # set squad = 0 for all other players model.add_constraints( (squad[p, self.gw-1] == 0 for p in players if p not in current_squad), name='initial_squad_others') # add current bank value model.add_constraint(in_the_bank[self.gw-1] == itb, name='initial_itb') # add current free transfers model.add_constraint(free_transfers[self.gw-1] == ft, name='initial_ft') # Constraints (per week) # 15 players in squad squad_count = { w: so.expr_sum(squad[p, w] for p in players) for w in gameweeks} model.add_constraints( (squad_count[w] == 15 for w in gameweeks), name='squad_count') # 11 players in starting lineup model.add_constraints( (so.expr_sum(lineup[p,w] for p in players) == 11 for w in gameweeks), name='lineup_count') # 1 captain model.add_constraints( (so.expr_sum(captain[p,w] for p in players) == 1 for w in gameweeks), name='captain_count') # 1 vice-captain model.add_constraints( (so.expr_sum(vicecap[p,w] for p in players) == 1 for w in gameweeks), name='vicecap_count') # players in starting lineup must also be in squad model.add_constraints( (lineup[p,w] <= squad[p,w] for p in players for w in gameweeks), name='lineup_squad_rel') # captain must come from within squad model.add_constraints( (captain[p,w] <= lineup[p,w] for p in players for w in gameweeks), name='captain_lineup_rel') # vice-captain must come from within squad model.add_constraints( (vicecap[p,w] <= lineup[p,w] for p in players for w in gameweeks), name='vicecap_lineup_rel') # captain and vice-captain can't be same person model.add_constraints( (captain[p,w] + vicecap[p,w] <= 1 for p in players for w in gameweeks), name='cap_vc_rel') # count of each player per position in starting lineup lineup_type_count = { (t,w): so.expr_sum(lineup[p,w] for p in players if self.forecasts.loc[p, 'position_id'] == t) for t in positions for w in gameweeks} # count of all players in lineup must be at least 'squad_min_play' # and no more than 'squad_max_play' for each position type model.add_constraints( ( lineup_type_count[t,w] == [ self.positions.loc[t, 'squad_min_play'], self.positions.loc[t, 'squad_max_play']] for t in positions for w in gameweeks), name='valid_formation') # count of each player per position in squad squad_type_count = { (t,w): so.expr_sum(squad[p,w] for p in players if self.forecasts.loc[p, 'position_id'] == t) for t in positions for w in gameweeks} # count of all players in squad must be equal to 'squad_select' # for each position type model.add_constraints( ( squad_type_count[t,w] == self.positions.loc[t, 'squad_select'] for t in positions for w in gameweeks), name='valid_squad') # no more than 3 players per team model.add_constraints( ( so.expr_sum(squad[p,w] for p in players if self.forecasts.loc[p, 'team_id'] == t) <= 3 for t in teams for w in gameweeks), name='team_limit') # Transfer constraints # squad is equal to squad from previous week, minus transfers out, plus in model.add_constraints( ( squad[p,w] == squad[p,w-1] + transfer_in[p,w] - transfer_out[p,w] for p in players for w in gameweeks), name='squad_transfer_rel') # handles running bank balance (assumes no changes in player values) model.add_constraints( ( in_the_bank[w] == in_the_bank[w-1] + sold_amount[w] - bought_amount[w] for w in gameweeks), name='cont_budget') # Free transfer constraints # 1 free transfer per week model.add_constraints( (free_transfers[w] == aux[w] + 1 for w in gameweeks), name='aux_ft_rel') # no more than 2 free transfers per week model.add_constraints( ( free_transfers[w-1] - number_of_transfers[w-1] <= 2 * aux[w] for w in gameweeks), name='force_aux_1') # cannot make more than 14 penalized transfers in a week model.add_constraints( ( free_transfers[w-1] - number_of_transfers[w-1] >= aux[w] + (-14)*(1-aux[w]) for w in gameweeks), name='force_aux_2') # not sure what this does ?? model.add_constraints( (penalized_transfers[w] >= transfer_diff[w] for w in gameweeks), name='pen_transfer_rel') # Objectives # sum of starting 11 players, plus double captain score # and upweight vice-captain gw_xp = { w: so.expr_sum(points_player_week[p,w] * (lineup[p,w] + captain[p,w] + 0.1*vicecap[p,w]) for p in players) for w in gameweeks} # subtract transfer costs gw_total = {w: gw_xp[w] - 4 * penalized_transfers[w] for w in gameweeks} total_xp = so.expr_sum( gw_total[w] * pow(decay_base, w-self.gw) for w in gameweeks) model.set_objective(-total_xp, sense='N', name='total_xp') # Solve model.export_mps(f'{model_name}.mps') command = f'cbc {model_name}.mps solve solu {model_name}.txt' process = Popen(command, stdout=DEVNULL, shell=False) # DEVNULL: nologs process.wait() # Parsing with open(f'{model_name}.txt', 'r') as f: for line in f: if 'objective value' in line: continue words = line.split() var = model.get_variable(words[1]) var.set_value(float(words[2])) # DataFrame generation picks = [] for w in gameweeks: for p in players: if squad[p,w].get_value() + transfer_out[p,w].get_value() > .5: lp = self.forecasts.loc[p] is_captain = 1 if captain[p,w].get_value() > .5 else 0 is_lineup = 1 if lineup[p,w].get_value() > .5 else 0 is_vice = 1 if vicecap[p,w].get_value() > .5 else 0 is_transfer_in = 1 if transfer_in[p,w].get_value() > .5 else 0 is_transfer_out = 1 if transfer_out[p,w].get_value() > .5 else 0 position = self.positions.loc[lp['position_id'], 'position_name'] team = self.teams.loc[lp['team_id'], 'team_name'] picks.append([ w, lp['web_name'], lp['position_id'], position, team, buy_price[p], sell_price[p], round(points_player_week[p,w],2), is_lineup, is_captain, is_vice, is_transfer_in, is_transfer_out ]) picks_df = pd.DataFrame( picks, columns=['GW', 'Name', 'Pos_id', 'Pos', 'Team', 'BV', 'SV', 'xP', 'lineup', 'captain', 'vicecaptain', 'transfer_in', 'transfer_out'] ).sort_values( by=['GW', 'lineup', 'Pos_id', 'xP'], ascending=[True, False, True, True]) total_xp = so.expr_sum( (lineup[p,w] + captain[p,w]) * points_player_week[p,w] for p in players for w in gameweeks ).get_value() print('SUMMARY OF ACTIONS', '-----------', sep='\n') for w in gameweeks: print(f'GW {w}:') print(f'ITB {in_the_bank[w].get_value()}:', f'FT={free_transfers[w].get_value()}', f'PT={penalized_transfers[w].get_value()}') for p in players: if transfer_in[p,w].get_value() > .5: print(f' Buy {p} - {self.forecasts["web_name"][p]}') if transfer_out[p,w].get_value() > .5: print(f' Sell {p} - {self.forecasts["web_name"][p]}') print(f'\nTotal expected value: {total_xp:.2f} ({total_xp/horizon:.2f} / week)') os.remove(f'{model_name}.mps') os.remove(f'{model_name}.txt') return picks_df
def test(cas_conn): # Problem data OILS = ['veg1', 'veg2', 'oil1', 'oil2', 'oil3'] PERIODS = range(1, 7) cost_data = [[110, 120, 130, 110, 115], [130, 130, 110, 90, 115], [110, 140, 130, 100, 95], [120, 110, 120, 120, 125], [100, 120, 150, 110, 105], [90, 100, 140, 80, 135]] cost = pd.DataFrame(cost_data, columns=OILS, index=PERIODS).transpose() hardness_data = [8.8, 6.1, 2.0, 4.2, 5.0] hardness = {OILS[i]: hardness_data[i] for i in range(len(OILS))} revenue_per_ton = 150 veg_ub = 200 nonveg_ub = 250 store_ub = 1000 storage_cost_per_ton = 5 hardness_lb = 3 hardness_ub = 6 init_storage = 500 max_num_oils_used = 3 min_oil_used_threshold = 20 # Problem initialization m = so.Model(name='food_manufacture_2', session=cas_conn) # Problem definition buy = m.add_variables(OILS, PERIODS, lb=0, name='buy') use = m.add_variables(OILS, PERIODS, lb=0, name='use') manufacture = m.add_implicit_variable((use.sum('*', p) for p in PERIODS), name='manufacture') last_period = len(PERIODS) store = m.add_variables(OILS, [0] + list(PERIODS), lb=0, ub=store_ub, name='store') for oil in OILS: store[oil, 0].set_bounds(lb=init_storage, ub=init_storage) store[oil, last_period].set_bounds(lb=init_storage, ub=init_storage) VEG = [i for i in OILS if 'veg' in i] NONVEG = [i for i in OILS if i not in VEG] revenue = so.quick_sum(revenue_per_ton * manufacture[p] for p in PERIODS) rawcost = so.quick_sum(cost.at[o, p] * buy[o, p] for o in OILS for p in PERIODS) storagecost = so.quick_sum(storage_cost_per_ton * store[o, p] for o in OILS for p in PERIODS) m.set_objective(revenue - rawcost - storagecost, sense=so.MAX, name='profit') # Constraints m.add_constraints((use.sum(VEG, p) <= veg_ub for p in PERIODS), name='veg_ub') m.add_constraints((use.sum(NONVEG, p) <= nonveg_ub for p in PERIODS), name='nonveg_ub') m.add_constraints((store[o, p - 1] + buy[o, p] == use[o, p] + store[o, p] for o in OILS for p in PERIODS), name='flow_balance') m.add_constraints( (so.quick_sum(hardness[o] * use[o, p] for o in OILS) >= hardness_lb * manufacture[p] for p in PERIODS), name='hardness_ub') m.add_constraints( (so.quick_sum(hardness[o] * use[o, p] for o in OILS) <= hardness_ub * manufacture[p] for p in PERIODS), name='hardness_lb') # Additions to the first problem isUsed = m.add_variables(OILS, PERIODS, vartype=so.BIN, name='is_used') for p in PERIODS: for o in VEG: use[o, p].set_bounds(ub=veg_ub) for o in NONVEG: use[o, p].set_bounds(ub=nonveg_ub) m.add_constraints((use[o, p] <= use[o, p]._ub * isUsed[o, p] for o in OILS for p in PERIODS), name='link') m.add_constraints( (isUsed.sum('*', p) <= max_num_oils_used for p in PERIODS), name='logical1') m.add_constraints((use[o, p] >= min_oil_used_threshold * isUsed[o, p] for o in OILS for p in PERIODS), name='logical2') m.add_constraints((isUsed[o, p] <= isUsed['oil3', p] for o in ['veg1', 'veg2'] for p in PERIODS), name='logical3') res = m.solve() if res is not None: print(so.get_solution_table(buy, use, store, isUsed)) return m.get_objective_value()
def solve_problem(objective, options=None): if options is None: options = dict() car_type = options.get('car_type', 'diesel') day_limit = options.get('day_limit', None) emission_limit = options.get('emission_limit', None) cost_limit = options.get('cost_limit', None) print('Connecting to CAS') hostname = os.getenv('CASHOST') port = os.getenv('CASPORT') cas = CAS(hostname, port) m = so.Model(name='european_trip_2020', session=cas) print('Parsing data') game_data, arcs_data, travel_data = prep_data(car_type) source = 0 sink = 999 GAMES = list(range(1, 52)) RAW_ARCS = [(i.id_x, i.id_y) for i in arcs_data.itertuples()] ARCS = [(source, g) for g in GAMES] + [(g, sink) for g in GAMES] + RAW_ARCS CITIES = list(game_data['city'].unique()) CONNECTION = [(city1, city2, method) for city1 in CITIES for city2 in CITIES if city1 != city2 for method in travel_data.loc[(city1, city2)].index] game_city = game_data['city'].to_dict() method_dict = travel_data.reset_index().groupby(['city_x', 'city_y']).apply( lambda i: i.method.to_list()).to_dict() use_arc = m.add_variables(ARCS, name='use_arc', vartype=so.BIN) use_method = m.add_variables(CONNECTION, name='use_method', vartype=so.BIN) total_emission = so.quick_sum(travel_data.loc[i].emission * use_method[i] for i in CONNECTION) total_trip_time = \ so.quick_sum( use_arc[g, sink] * game_data.loc[g]['ts'] for g in GAMES) - \ so.quick_sum( use_arc[source, g] * game_data.loc[g]['ts'] for g in GAMES) total_duration = so.quick_sum( travel_data.loc[i].duration.total_seconds() * use_method[i] for i in CONNECTION) total_km = so.quick_sum( travel_data.loc[i].car * use_method[i] for i in CONNECTION) total_expense = so.quick_sum( travel_data.loc[i].cost * use_method[i] for i in CONNECTION) if objective == 'least_emission': m.set_objective(total_emission, name='total_emission', sense=so.MIN) elif objective == 'shortest_tour': # Total trip time m.set_objective(total_trip_time, name='total_trip_time', sense=so.MIN) elif objective == 'total_duration': m.set_objective(total_duration, name='total_duration', sense=so.MIN) elif objective == 'total_km': m.set_objective(total_km, name='total_km', sense=so.MIN) elif objective == 'least_expensive': m.set_objective(total_expense, name='total_expense', sense=so.MIN) # Balance constraints m.add_constraints( (so.quick_sum(use_arc[g1, g] for (g1, g2) in ARCS if g2 == g) - so.quick_sum(use_arc[g, g2] for (g1, g2) in ARCS if g1 == g) == (-1 if g == source else (1 if g == sink else 0)) for g in GAMES + [source, sink]), name='balance' ) # Visit each city once m.add_constraints( (so.quick_sum(use_arc[g1, g2] for (g1, g2) in ARCS if g1 != source and game_data.loc[g1]['city'] == CITIES[i]) == 1 for i in range(12)), name='visit') # Must use a travel method m.add_constraints( (so.quick_sum( use_method[game_data.loc[i].city, game_data.loc[j].city, method] for method in travel_data.loc[(game_data.loc[i].city, game_data.loc[j].city)].index.to_list() ) == 1 * use_arc[i, j] for (i, j) in RAW_ARCS if game_data.loc[i].city != game_data.loc[j].city), name='travel_method' ) # Catch game before it starts m.add_constraints(( so.quick_sum( use_method[game_city[i], game_city[j], k] * travel_data.loc[game_city[i], game_city[j], k].duration.total_seconds() for k in method_dict[game_city[i], game_city[j]] ) + datetime.timedelta(hours=4).total_seconds() * use_arc[i, j] <= (game_data.loc[j, 'dt'] - game_data.loc[i, 'dt']).total_seconds() for (i, j) in RAW_ARCS), name='catch_game' ) # Day limit if day_limit: second_limit = datetime.timedelta(days=day_limit).total_seconds() m.add_constraint(total_trip_time <= second_limit, name='time_limit') if emission_limit: m.add_constraint(total_emission <= emission_limit, name='emission_limit') if cost_limit: m.add_constraint(total_expense <= cost_limit, name='cost_limit') print('Submitting') m.solve() steps = [] schedule = [] for (g1, g2) in ARCS: if use_arc[g1, g2].get_value() > 0.5 and g1 != source and g2 != sink: if g1 not in schedule: schedule.append(g1) if g2 not in schedule: schedule.append(g2) steps.append((g1, g2)) methods = travel_data[travel_data.apply( lambda i: use_method[i.name].get_value() > 0.5, axis=1)].copy() methods = methods.reset_index('method') # Sort the schedule and print information schedule = sorted(schedule, key=lambda i: game_data.loc[i, 'ts']) if objective == 'least_emission': objective += car_type result = print_final_schedule( objective, schedule, methods, game_data, arcs_data, options) return result
def solve_custom_problem(input_folder, output_folder, options): """Solves a custom optimization problem""" problem_name = options['name'] df = pd.read_csv(input_folder / 'element_gameweek.csv') target_week = options.get('target_week', df['event'].min()) target_week_df = df[df['event'] == target_week].copy() df = pd.read_csv(input_folder / 'element.csv') target_week_df = pd.merge(left=target_week_df, right=df, how='inner', left_on=['player_id'], right_on=['id'], suffixes=('', '_extra')) players = target_week_df['player_id'].unique().tolist() target_week_df.set_index('player_id', inplace=True, drop=True) target_week_df = target_week_df.groupby(target_week_df.index).first() team_codes = target_week_df['team_code'].unique().tolist() types_df = pd.read_csv(input_folder / 'element_type.csv') types = types_df['id'].to_list() types_df.set_index('id', inplace=True, drop=True) m = so.Model(name=problem_name, session=None) x = m.add_variables(players, name='lineup', vartype=so.BIN) y = m.add_variables(players, name='captain', vartype=so.BIN) z = m.add_variables(players, name='squad', vartype=so.BIN) m.add_constraint(so.quick_sum(x[i] for i in players) == 11, name='lineup_limit') m.add_constraints(( so.quick_sum(x[i] for i in players if target_week_df.loc[i]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types), name='squad_min') m.add_constraints(( so.quick_sum(x[i] for i in players if target_week_df.loc[i]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types), name='squad_max') m.add_constraint(so.quick_sum(y[i] for i in players) == 1, name='single_captain') m.add_constraints((y[i] <= x[i] for i in players), name='captain_should_play') # Limit constraints m.add_constraints(( so.quick_sum(z[i] for i in players if target_week_df.loc[i]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(z[i] for i in players) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(z[i] for i in players if target_week_df.loc[i]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') m.add_constraint( so.quick_sum(z[i] * target_week_df.loc[i]['now_cost'] for i in players) <= options['budget']*10, name='total_cost_100') m.add_constraints( (x[i] <= z[i] for i in players), name='lineup_squad_con') obj_type = options['objective'] if obj_type == 'lineup': m.set_objective(so.quick_sum( -target_week_df.loc[i]['points_md'] * (x[i]+y[i]) for i in players ), sense='N', name='maximize_lineup_points') elif obj_type == 'bb': m.set_objective(so.quick_sum( -target_week_df.loc[i]['points_md'] * (z[i]+y[i]) for i in players ), sense='N', name='maximize_bb_points') mps_str = get_mps_string(m) with open(output_folder / f"{problem_name}.mps", "w") as f: f.write(mps_str) filename = str(output_folder / f"{problem_name}.mps") solutionname = str(output_folder / f"{problem_name}.sol") csvname = str(output_folder / f"{problem_name}.csv") xlsname = str(output_folder / f"{problem_name}.xlsx") solve_and_get_solution(filename, solutionname, m) # Parse solution selected_players = [] for i in players: if z[i].get_value() > 0.5 and x[i].get_value() < 0.5: selected_players.append([i, 0, False, 0]) elif x[i].get_value() > 0.5 and y[i].get_value() < 0.5: selected_players.append([i, 1, False, 1]) elif x[i].get_value() > 0.5 and y[i].get_value() > 0.5: selected_players.append([i, 2, True, 1]) results = pd.DataFrame(selected_players, columns=['player_id', 'multiplier', 'is_captain', 'starting_lineup']) result_df = pd.merge(target_week_df, results, on='player_id', how='inner') result_df = result_df[['player_id', 'web_name', 'team_code', 'element_type', 'now_cost', 'event', 'points_md', 'is_captain', 'multiplier', 'starting_lineup', 'selected_by_percent']].copy() result_df['gw_points'] = result_df['multiplier'] * result_df['points_md'] result_df = result_df.sort_values(by=['starting_lineup', 'element_type', 'player_id'], ascending=[False, True, True], ignore_index=True) result_df.reset_index(drop=True, inplace=True) result_df.to_csv(csvname, encoding='utf-8') result_df.to_excel(xlsname, encoding='utf-8') with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.encoding', 'UTF-8'): print(result_df) print(m.get_objective_value())
def test(cas_conn): # Problem data OILS = ['veg1', 'veg2', 'oil1', 'oil2', 'oil3'] PERIODS = range(1, 7) cost_data = [[110, 120, 130, 110, 115], [130, 130, 110, 90, 115], [110, 140, 130, 100, 95], [120, 110, 120, 120, 125], [100, 120, 150, 110, 105], [90, 100, 140, 80, 135]] cost = pd.DataFrame(cost_data, columns=OILS, index=PERIODS).transpose() hardness_data = [8.8, 6.1, 2.0, 4.2, 5.0] hardness = {OILS[i]: hardness_data[i] for i in range(len(OILS))} revenue_per_ton = 150 veg_ub = 200 nonveg_ub = 250 store_ub = 1000 storage_cost_per_ton = 5 hardness_lb = 3 hardness_ub = 6 init_storage = 500 # Problem initialization m = so.Model(name='food_manufacture_1', session=cas_conn) # Problem definition buy = m.add_variables(OILS, PERIODS, lb=0, name='buy') use = m.add_variables(OILS, PERIODS, lb=0, name='use') manufacture = m.add_implicit_variable((use.sum('*', p) for p in PERIODS), name='manufacture') last_period = len(PERIODS) store = m.add_variables(OILS, [0] + list(PERIODS), lb=0, ub=store_ub, name='store') for oil in OILS: store[oil, 0].set_bounds(lb=init_storage, ub=init_storage) store[oil, last_period].set_bounds(lb=init_storage, ub=init_storage) VEG = [i for i in OILS if 'veg' in i] NONVEG = [i for i in OILS if i not in VEG] revenue = so.quick_sum(revenue_per_ton * manufacture[p] for p in PERIODS) rawcost = so.quick_sum(cost.at[o, p] * buy[o, p] for o in OILS for p in PERIODS) storagecost = so.quick_sum(storage_cost_per_ton * store[o, p] for o in OILS for p in PERIODS) m.set_objective(revenue - rawcost - storagecost, sense=so.MAX, name='profit') # Constraints m.add_constraints((use.sum(VEG, p) <= veg_ub for p in PERIODS), name='veg_ub') m.add_constraints((use.sum(NONVEG, p) <= nonveg_ub for p in PERIODS), name='nonveg_ub') m.add_constraints((store[o, p - 1] + buy[o, p] == use[o, p] + store[o, p] for o in OILS for p in PERIODS), name='flow_balance') m.add_constraints( (so.quick_sum(hardness[o] * use[o, p] for o in OILS) >= hardness_lb * manufacture[p] for p in PERIODS), name='hardness_ub') m.add_constraints( (so.quick_sum(hardness[o] * use[o, p] for o in OILS) <= hardness_ub * manufacture[p] for p in PERIODS), name='hardness_lb') # Solver call res = m.solve() # With other solve options m.solve(options={'with': 'lp', 'algorithm': 'PS'}) m.solve(options={'with': 'lp', 'algorithm': 'PS'}) m.solve(options={'with': 'lp', 'algorithm': 'PS'}) if res is not None: print(so.get_solution_table(buy, use, store)) return m.get_objective_value()
def test(cas_conn): m = so.Model(name='factory_planning_2', session=cas_conn) # Input data product_list = ['prod{}'.format(i) for i in range(1, 8)] product_data = pd.DataFrame([10, 6, 8, 4, 11, 9, 3], columns=['profit'], index=product_list) demand_data = [ [500, 1000, 300, 300, 800, 200, 100], [600, 500, 200, 0, 400, 300, 150], [300, 600, 0, 0, 500, 400, 100], [200, 300, 400, 500, 200, 0, 100], [0, 100, 500, 100, 1000, 300, 0], [500, 500, 100, 300, 1100, 500, 60]] demand_data = pd.DataFrame( demand_data, columns=product_list, index=range(1, 7)) machine_type_product_data = [ ['grinder', 0.5, 0.7, 0, 0, 0.3, 0.2, 0.5], ['vdrill', 0.1, 0.2, 0, 0.3, 0, 0.6, 0], ['hdrill', 0.2, 0, 0.8, 0, 0, 0, 0.6], ['borer', 0.05, 0.03, 0, 0.07, 0.1, 0, 0.08], ['planer', 0, 0, 0.01, 0, 0.05, 0, 0.05]] machine_type_product_data = \ pd.DataFrame(machine_type_product_data, columns=['machine_type'] + product_list).set_index(['machine_type']) machine_types_data = [ ['grinder', 4, 2], ['vdrill', 2, 2], ['hdrill', 3, 3], ['borer', 1, 1], ['planer', 1, 1]] machine_types_data = pd.DataFrame(machine_types_data, columns=[ 'machine_type', 'num_machines', 'num_machines_needing_maintenance'])\ .set_index(['machine_type']) store_ub = 100 storage_cost_per_unit = 0.5 final_storage = 50 num_hours_per_period = 24 * 2 * 8 # Problem definition PRODUCTS = product_list profit = product_data['profit'] PERIODS = range(1, 7) MACHINE_TYPES = machine_types_data.index.tolist() num_machines = machine_types_data['num_machines'] make = m.add_variables(PRODUCTS, PERIODS, lb=0, name='make') sell = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=demand_data.transpose(), name='sell') store = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=store_ub, name='store') for p in PRODUCTS: store[p, 6].set_bounds(lb=final_storage, ub=final_storage) storageCost = so.quick_sum( storage_cost_per_unit * store[p, t] for p in PRODUCTS for t in PERIODS) revenue = so.quick_sum(profit[p] * sell[p, t] for p in PRODUCTS for t in PERIODS) m.set_objective(revenue-storageCost, sense=so.MAX, name='total_profit') num_machines_needing_maintenance = \ machine_types_data['num_machines_needing_maintenance'] numMachinesDown = m.add_variables(MACHINE_TYPES, PERIODS, vartype=so.INT, lb=0, name='numMachinesDown') production_time = machine_type_product_data m.add_constraints(( so.quick_sum(production_time.at[mc, p] * make[p, t] for p in PRODUCTS) <= num_hours_per_period * (num_machines[mc] - numMachinesDown[mc, t]) for mc in MACHINE_TYPES for t in PERIODS), name='machine_hours_con') m.add_constraints((so.quick_sum(numMachinesDown[mc, t] for t in PERIODS) == num_machines_needing_maintenance[mc] for mc in MACHINE_TYPES), name='maintenance_con') m.add_constraints(((store[p, t-1] if t-1 in PERIODS else 0) + make[p, t] == sell[p, t] + store[p, t] for p in PRODUCTS for t in PERIODS), name='flow_balance_con') res = m.solve() if res is not None: print(so.get_solution_table(make, sell, store)) print(so.get_solution_table(numMachinesDown).unstack(level=-1)) print(m.get_solution_summary()) print(m.get_problem_summary()) return m.get_objective_value()
def test(cas_conn): m = so.Model(name='mining_optimization', session=cas_conn) mine_data = pd.DataFrame([ ['mine1', 5, 2, 1.0], ['mine2', 4, 2.5, 0.7], ['mine3', 4, 1.3, 1.5], ['mine4', 5, 3, 0.5], ], columns=['mine', 'cost', 'extract_ub', 'quality']).\ set_index(['mine']) year_data = pd.DataFrame([ [1, 0.9], [2, 0.8], [3, 1.2], [4, 0.6], [5, 1.0], ], columns=['year', 'quality_required']).set_index(['year']) max_num_worked_per_year = 3 revenue_per_ton = 10 discount_rate = 0.10 MINES = mine_data.index.tolist() cost = mine_data['cost'] extract_ub = mine_data['extract_ub'] quality = mine_data['quality'] YEARS = year_data.index.tolist() quality_required = year_data['quality_required'] isOpen = m.add_variables(MINES, YEARS, vartype=so.BIN, name='isOpen') isWorked = m.add_variables(MINES, YEARS, vartype=so.BIN, name='isWorked') extract = m.add_variables(MINES, YEARS, lb=0, name='extract') [extract[i, j].set_bounds(ub=extract_ub[i]) for i in MINES for j in YEARS] extractedPerYear = {j: extract.sum('*', j) for j in YEARS} discount = {j: 1 / (1 + discount_rate)**(j - 1) for j in YEARS} totalRevenue = revenue_per_ton *\ so.quick_sum(discount[j] * extractedPerYear[j] for j in YEARS) totalCost = so.quick_sum(discount[j] * cost[i] * isOpen[i, j] for i in MINES for j in YEARS) m.set_objective(totalRevenue - totalCost, sense=so.MAX, name='totalProfit') m.add_constraints((extract[i, j] <= extract[i, j]._ub * isWorked[i, j] for i in MINES for j in YEARS), name='link') m.add_constraints( (isWorked.sum('*', j) <= max_num_worked_per_year for j in YEARS), name='cardinality') m.add_constraints( (isWorked[i, j] <= isOpen[i, j] for i in MINES for j in YEARS), name='worked_implies_open') m.add_constraints((isOpen[i, j] <= isOpen[i, j - 1] for i in MINES for j in YEARS if j != 1), name='continuity') m.add_constraints((so.quick_sum(quality[i] * extract[i, j] for i in MINES) == quality_required[j] * extractedPerYear[j] for j in YEARS), name='quality_con') res = m.solve() if res is not None: print(so.get_solution_table(isOpen, isWorked, extract)) quality_sol = { j: so.quick_sum(quality[i] * extract[i, j].get_value() for i in MINES) / extractedPerYear[j].get_value() for j in YEARS } qs = so.dict_to_frame(quality_sol, ['quality_sol']) epy = so.dict_to_frame(extractedPerYear, ['extracted_per_year']) print(so.get_solution_table(epy, qs, quality_required)) return m.get_objective_value()
def test(cas_conn): # Data generation n = 100 p = 0.02 random.seed(1) ARCS = {} for i in range(0, n): for j in range(0, n): if random.random() < p: ARCS[i, j] = random.random() max_length = 10 # Model model = so.Model("kidney_exchange", session=cas_conn) # Sets NODES = set().union(*ARCS.keys()) MATCHINGS = range(1, int(len(NODES) / 2) + 1) # Variables UseNode = model.add_variables(NODES, MATCHINGS, vartype=so.BIN, name="usenode") UseArc = model.add_variables(ARCS, MATCHINGS, vartype=so.BIN, name="usearc") Slack = model.add_variables(NODES, vartype=so.BIN, name="slack") print('Setting objective...') # Objective model.set_objective(so.quick_sum( (ARCS[i, j] * UseArc[i, j, m] for [i, j] in ARCS for m in MATCHINGS)), name="total_weight", sense=so.MAX) print('Adding constraints...') # Constraints Node_Packing = model.add_constraints( (UseNode.sum(i, '*') + Slack[i] == 1 for i in NODES), name="node_packing") Donate = model.add_constraints((UseArc.sum(i, '*', m) == UseNode[i, m] for i in NODES for m in MATCHINGS), name="donate") Receive = model.add_constraints((UseArc.sum('*', j, m) == UseNode[j, m] for j in NODES for m in MATCHINGS), name="receive") Cardinality = model.add_constraints( (UseArc.sum('*', '*', m) <= max_length for m in MATCHINGS), name="cardinality") # Solve model.solve(options={'with': 'milp', 'maxtime': 300}) # Define decomposition blocks for i in NODES: for m in MATCHINGS: Donate[i, m].set_block(m - 1) Receive[i, m].set_block(m - 1) for m in MATCHINGS: Cardinality[m].set_block(m - 1) model.solve(verbose=True, options={ 'with': 'milp', 'maxtime': 300, 'presolver': 'basic', 'decomp': { 'method': 'user' } }) return model.get_objective_value()
def solve_optimal_transfer_problem(team_name, options=None): print('\n *** Solving problem for ', team_name, '\n') if options is None: options = {'age_limit': 33} team_info = get_team_info(team_name) if os.path.isfile('playerdb.pickle'): player_db = pd.read_pickle('playerdb.pickle') else: player_db = get_player_db() player_db['player_id'] = player_db.index player_db = player_db.set_index(['link']) # Remove duplicate rows player_db = player_db[~player_db.index.duplicated(keep='last')] if options and 'budget_limit' in options: budget = options['budget_limit'] else: budget = team_info['budget'] eligible = [] for i, pos in enumerate(team_info['positions']): print('Filtering eligible candidates for', pos) if pos in ('RCB', 'LCB'): filter_pos = 'CB' elif pos in ('RCM', 'LCM'): filter_pos = 'CM' elif pos in ('LS', 'RS'): filter_pos = 'ST' elif pos in ('LDM', 'RDM'): filter_pos = 'DM' else: filter_pos = pos # Can play for position filtered = player_db[player_db['pos'].str.contains(filter_pos)] # Has no missing value filtered = filtered[filtered['value'] > 0] # Under budget filtered = filtered[filtered['value'] < budget] # Better than current squad member filtered = filtered[filtered['overall'] > team_info['ratings'][i]] if options and 'age_limit' in options: # Age limit filtered = filtered[filtered['age'] <= options['age_limit']] for id in filtered['player_id'].tolist(): eligible.append([id, i, pos]) eligible = pd.DataFrame(eligible, columns=['player_id', 'position', 'pos_str']) print('Total number of eligible transfers:', len(eligible)) squad = [] for i in range(11): try: current_member = player_db.loc[team_info['players'][i]] except: # If user is not in db, fetch player page print('Found a player who is not in DB!') current_member = get_player_info(team_info['players'][i]) current_member['player_id'] = len(player_db['name']) player_db.loc[team_info['players'][i]] = [ current_member['name'], None, # img None, # age [], # pos 0, # value current_member['overall'], current_member['potential'], # potential player_db['player_id'].max() + 1 ] print('Current squad member for ', team_info['positions'][i], ':', current_member['name'], ', rating', current_member['overall']) squad.append([ i, current_member['player_id'], team_info['positions'][i], current_member['overall'] ]) squad = pd.DataFrame( squad, columns=['position', 'player_id', 'pos_str', 'overall']) player_db = player_db[player_db['player_id'].isin( eligible['player_id'].tolist() + squad['player_id'].tolist())] # Modeling so.reset_globals() m = so.Model(name='optimal_squad_1', session=session) PLAYERS, (name, age, value, overall, potential) = m.read_table( player_db, key=['player_id'], columns=['name', 'age', 'value', 'overall', 'potential'], col_types={'name': 'str'}, upload=False, casout='player_list') ELIG, _ = m.read_table(eligible, key=['player_id', 'position'], upload=False, casout='eligible_list') POSITIONS, (member, pos_str, c_overall) = m.read_table( squad, key=['position'], columns=['player_id', 'pos_str', 'overall'], col_types={'pos_str': 'str'}, upload=False, casout='squad_list') rating = m.add_variables(POSITIONS, name='rating') transfer = m.add_variables(ELIG, name='transfer', vartype=so.BIN) m.set_objective(so.quick_sum(rating[j] for j in POSITIONS), name='total_rating', sense=so.MAX) m.add_constraint(so.quick_sum(transfer[i, j] * value[i] for (i, j) in ELIG) <= budget, name='budget_con') m.add_constraints( (rating[j] == overall[member[j]] + so.quick_sum(transfer[i, j] * (overall[i] - overall[member[j]]) for (i, j2) in ELIG if j == j2) for j in POSITIONS), name='transfer_con') # Potential rating alternative # m.add_constraints( # (rating[j] == potential[member[j]] + so.quick_sum( # transfer[i, j] * (potential[i] - potential[member[j]]) for (i, j2) in ELIG if j==j2) for j in POSITIONS), name='potential_con') m.add_constraints((so.quick_sum(transfer[i, j] for (i2, j) in ELIG if i == i2) <= 1 for i in PLAYERS), name='only_one_position') m.add_constraints((so.quick_sum(transfer[i, j] for (i, j2) in ELIG if j == j2) <= 1 for j in POSITIONS), name='only_one_transfer') for j in POSITIONS: print(j, pos_str[j], len([1 for (i, j2) in ELIG if j == j2])) if team_name is None: m.add_constraints((so.quick_sum(transfer[i, j] for (i, j2) in ELIG if j == j2) == 1 for j in POSITIONS), name='transfer_one') m.solve() old_rating = sum(c_overall) print('Original squad rating:', old_rating) new_rating = rating.sum('*').get_value() print('New squad rating:', new_rating) new_players = [] final_team = [] for i, pos in enumerate(POSITIONS): for player in PLAYERS: if (player, pos) not in ELIG: continue if transfer[player, pos].get_value() > 0.5: print( '{}: {} ({}, pot:{}), previous: {} ({}), paid: {}'.format( pos_str[pos], name[player], overall[player], potential[player], name[member[pos]], c_overall[pos], value[player])) new_players.append(name[player]) final_team.append([ pos_str[pos], name[member[pos]], c_overall[pos], potential[member[pos]], name[player], overall[player], potential[player], value[player] ]) break else: print('{}: {} ({})'.format(pos_str[pos], name[member[pos]], c_overall[pos])) final_team.append([ pos_str[pos], name[member[pos]], c_overall[pos], potential[member[pos]], name[member[pos]], c_overall[pos], potential[member[pos]], 0 ]) final_team = pd.DataFrame(final_team, columns=[ 'Pos', 'Old', 'Old.R', 'Old.Pot', 'New', 'New.R', 'New.Pot', 'Paid' ]) final_team = final_team.append(final_team.sum(numeric_only=True), ignore_index=True) money_spent = so.quick_sum(value[i] * transfer[i, j] for (i, j) in ELIG).get_value() efficiency = (new_rating - old_rating) / (money_spent / 1e6) if money_spent > 0 else 0 print('Rating increase per million euro:', efficiency) transfer_list = ', '.join(new_players) return (team_name, options['age_limit'], old_rating, round(old_rating / 11.0, 3), round(new_rating), round(new_rating / 11.0, 3), budget, money_spent, efficiency, transfer_list, final_team)
def test(cas_conn, **kwargs): m = so.Model(name='refinery_optimization', session=cas_conn) crude_data = pd.DataFrame([ ['crude1', 20000], ['crude2', 30000] ], columns=['crude', 'crude_ub']).set_index(['crude']) arc_data = pd.DataFrame([ ['source', 'crude1', 6], ['source', 'crude2', 6], ['crude1', 'light_naphtha', 0.1], ['crude1', 'medium_naphtha', 0.2], ['crude1', 'heavy_naphtha', 0.2], ['crude1', 'light_oil', 0.12], ['crude1', 'heavy_oil', 0.2], ['crude1', 'residuum', 0.13], ['crude2', 'light_naphtha', 0.15], ['crude2', 'medium_naphtha', 0.25], ['crude2', 'heavy_naphtha', 0.18], ['crude2', 'light_oil', 0.08], ['crude2', 'heavy_oil', 0.19], ['crude2', 'residuum', 0.12], ['light_naphtha', 'regular_petrol', np.nan], ['light_naphtha', 'premium_petrol', np.nan], ['medium_naphtha', 'regular_petrol', np.nan], ['medium_naphtha', 'premium_petrol', np.nan], ['heavy_naphtha', 'regular_petrol', np.nan], ['heavy_naphtha', 'premium_petrol', np.nan], ['light_naphtha', 'reformed_gasoline', 0.6], ['medium_naphtha', 'reformed_gasoline', 0.52], ['heavy_naphtha', 'reformed_gasoline', 0.45], ['light_oil', 'jet_fuel', np.nan], ['light_oil', 'fuel_oil', np.nan], ['heavy_oil', 'jet_fuel', np.nan], ['heavy_oil', 'fuel_oil', np.nan], ['light_oil', 'light_oil_cracked', 2], ['light_oil_cracked', 'cracked_oil', 0.68], ['light_oil_cracked', 'cracked_gasoline', 0.28], ['heavy_oil', 'heavy_oil_cracked', 2], ['heavy_oil_cracked', 'cracked_oil', 0.75], ['heavy_oil_cracked', 'cracked_gasoline', 0.2], ['cracked_oil', 'jet_fuel', np.nan], ['cracked_oil', 'fuel_oil', np.nan], ['reformed_gasoline', 'regular_petrol', np.nan], ['reformed_gasoline', 'premium_petrol', np.nan], ['cracked_gasoline', 'regular_petrol', np.nan], ['cracked_gasoline', 'premium_petrol', np.nan], ['residuum', 'lube_oil', 0.5], ['residuum', 'jet_fuel', np.nan], ['residuum', 'fuel_oil', np.nan], ], columns=['i', 'j', 'multiplier']).set_index(['i', 'j']) octane_data = pd.DataFrame([ ['light_naphtha', 90], ['medium_naphtha', 80], ['heavy_naphtha', 70], ['reformed_gasoline', 115], ['cracked_gasoline', 105], ], columns=['i', 'octane']).set_index(['i']) petrol_data = pd.DataFrame([ ['regular_petrol', 84], ['premium_petrol', 94], ], columns=['petrol', 'octane_lb']).set_index(['petrol']) vapour_pressure_data = pd.DataFrame([ ['light_oil', 1.0], ['heavy_oil', 0.6], ['cracked_oil', 1.5], ['residuum', 0.05], ], columns=['oil', 'vapour_pressure']).set_index(['oil']) fuel_oil_ratio_data = pd.DataFrame([ ['light_oil', 10], ['cracked_oil', 4], ['heavy_oil', 3], ['residuum', 1], ], columns=['oil', 'coefficient']).set_index(['oil']) final_product_data = pd.DataFrame([ ['premium_petrol', 700], ['regular_petrol', 600], ['jet_fuel', 400], ['fuel_oil', 350], ['lube_oil', 150], ], columns=['product', 'profit']).set_index(['product']) vapour_pressure_ub = 1 crude_total_ub = 45000 naphtha_ub = 10000 cracked_oil_ub = 8000 lube_oil_lb = 500 lube_oil_ub = 1000 premium_ratio = 0.40 ARCS = arc_data.index.tolist() arc_mult = arc_data['multiplier'].fillna(1) FINAL_PRODUCTS = final_product_data.index.tolist() final_product_data['profit'] = final_product_data['profit'] / 100 profit = final_product_data['profit'] ARCS = ARCS + [(i, 'sink') for i in FINAL_PRODUCTS] flow = m.add_variables(ARCS, name='flow', lb=0) NODES = np.unique([i for j in ARCS for i in j]) m.set_objective(so.expr_sum(profit[i] * flow[i, 'sink'] for i in FINAL_PRODUCTS if (i, 'sink') in ARCS), name='totalProfit', sense=so.MAX) m.add_constraints((so.expr_sum(flow[a] for a in ARCS if a[0] == n) == so.expr_sum(arc_mult[a] * flow[a] for a in ARCS if a[1] == n) for n in NODES if n not in ['source', 'sink']), name='flow_balance') CRUDES = crude_data.index.tolist() crudeDistilled = m.add_variables(CRUDES, name='crudesDistilled', lb=0) crudeDistilled.set_bounds(ub=crude_data['crude_ub']) m.add_constraints((flow[i, j] == crudeDistilled[i] for (i, j) in ARCS if i in CRUDES), name='distillation') OILS = ['light_oil', 'heavy_oil'] CRACKED_OILS = [i+'_cracked' for i in OILS] oilCracked = m.add_variables(CRACKED_OILS, name='oilCracked', lb=0) m.add_constraints((flow[i, j] == oilCracked[i] for (i, j) in ARCS if i in CRACKED_OILS), name='cracking') octane = octane_data['octane'] PETROLS = petrol_data.index.tolist() octane_lb = petrol_data['octane_lb'] vapour_pressure = vapour_pressure_data['vapour_pressure'] m.add_constraints((so.expr_sum(octane[a[0]] * arc_mult[a] * flow[a] for a in ARCS if a[1] == p) >= octane_lb[p] * so.expr_sum(arc_mult[a] * flow[a] for a in ARCS if a[1] == p) for p in PETROLS), name='blending_petrol') m.add_constraint(so.expr_sum(vapour_pressure[a[0]] * arc_mult[a] * flow[a] for a in ARCS if a[1] == 'jet_fuel') <= vapour_pressure_ub * so.expr_sum(arc_mult[a] * flow[a] for a in ARCS if a[1] == 'jet_fuel'), name='blending_jet_fuel') fuel_oil_coefficient = fuel_oil_ratio_data['coefficient'] sum_fuel_oil_coefficient = sum(fuel_oil_coefficient) m.add_constraints((sum_fuel_oil_coefficient * flow[a] == fuel_oil_coefficient[a[0]] * flow.sum('*', ['fuel_oil']) for a in ARCS if a[1] == 'fuel_oil'), name='blending_fuel_oil') m.add_constraint(crudeDistilled.sum('*') <= crude_total_ub, name='crude_total_ub') m.add_constraint(so.expr_sum(flow[a] for a in ARCS if a[0].find('naphtha') > -1 and a[1] == 'reformed_gasoline') <= naphtha_ub, name='naphtba_ub') m.add_constraint(so.expr_sum(flow[a] for a in ARCS if a[1] == 'cracked_oil') <= cracked_oil_ub, name='cracked_oil_ub') m.add_constraint(flow['lube_oil', 'sink'] == [lube_oil_lb, lube_oil_ub], name='lube_oil_range') m.add_constraint(flow.sum('premium_petrol', '*') >= premium_ratio * flow.sum('regular_petrol', '*'), name='premium_ratio') res = m.solve(**kwargs) if res is not None: print(so.get_solution_table(crudeDistilled)) print(so.get_solution_table(oilCracked)) print(so.get_solution_table(flow)) octane_sol = [] for p in PETROLS: octane_sol.append(so.expr_sum(octane[a[0]] * arc_mult[a] * flow[a].get_value() for a in ARCS if a[1] == p) / sum(arc_mult[a] * flow[a].get_value() for a in ARCS if a[1] == p)) octane_sol = pd.Series(octane_sol, name='octane_sol', index=PETROLS) print(so.get_solution_table(octane_sol, octane_lb)) print(so.get_solution_table(vapour_pressure)) vapour_pressure_sol = sum(vapour_pressure[a[0]] * arc_mult[a] * flow[a].get_value() for a in ARCS if a[1] == 'jet_fuel') /\ sum(arc_mult[a] * flow[a].get_value() for a in ARCS if a[1] == 'jet_fuel') print('Vapour_pressure_sol: {:.4f}'.format(vapour_pressure_sol)) num_fuel_oil_ratio_sol = [arc_mult[a] * flow[a].get_value() / sum(arc_mult[b] * flow[b].get_value() for b in ARCS if b[1] == 'fuel_oil') for a in ARCS if a[1] == 'fuel_oil'] num_fuel_oil_ratio_sol = pd.Series(num_fuel_oil_ratio_sol, name='num_fuel_oil_ratio_sol', index=[a[0] for a in ARCS if a[1] == 'fuel_oil']) print(so.get_solution_table(fuel_oil_coefficient, num_fuel_oil_ratio_sol)) return m.get_objective_value()
def solve_gain_loss_problem_1GW(gw, weights, options=None): if options is None: options = dict() data = get_multistage_data(gw, n=1) base_folder = pathlib.Path().resolve() output_folder = pathlib.Path(base_folder / f"build/work/") output_folder.mkdir(parents=True, exist_ok=True) gw = data['gw'] players = data['elements'] types = data['types'] types_df = data['types_df'] next_week_df = data['element_gameweek_df'] team_codes = data['team_codes'] element_df = data['element_df'] m = so.Model(name='gainloss', session=None) x = m.add_variables(players, name='lineup', vartype=so.BIN) y = m.add_variables(players, name='captain', vartype=so.BIN) z = m.add_variables(players, name='squad', vartype=so.BIN) m.add_constraint(so.quick_sum(x[i] for i in players) == 11, name='lineup_limit') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types), name='squad_min') m.add_constraints(( so.quick_sum(x[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types), name='squad_max') m.add_constraint(so.quick_sum(y[i] for i in players) == 1, name='single_captain') m.add_constraints((y[i] <= x[i] for i in players), name='captain_should_play') # Limit constraints m.add_constraints(( so.quick_sum(z[i] for i in players if next_week_df.loc[i, gw]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(z[i] for i in players) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(z[i] for i in players if next_week_df.loc[i, gw]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') m.add_constraint( so.quick_sum(z[i] * next_week_df.loc[i, gw]['now_cost'] for i in players) <= 1000, name='total_cost_100') m.add_constraints( (x[i] <= z[i] for i in players), name='lineup_squad_con') gain_weight = weights['gain'] loss_weight = weights['loss'] total_gain = so.quick_sum(next_week_df.loc[e, gw]['points_md']*(1-element_df.loc[e]['selected_by_percent']/100.0)*x[e] for e in players) total_loss = so.quick_sum(next_week_df.loc[e, gw]['points_md']*(element_df.loc[e]['selected_by_percent']/100.0)*(1-x[e]) for e in players) weighted_net = gain_weight * total_gain - loss_weight * total_loss overall_net = total_gain - total_loss if options.get('overall_net_lb') is not None: m.add_constraint(overall_net >= options['overall_net_lb'], name='overall_net_lb_con') m.set_objective( # so.quick_sum(-next_week_df.loc[i, gw]['points_md'] * (x[i]+y[i]) for i in players) - weighted_net, sense='N', name='maximize_points') mps_str = get_mps_string(m) problem_name = f"GW{gw}_gain_loss_{gain_weight:.3f}_{loss_weight:.3f}" if options.get('name') is not None: problem_name += '_' + options['name'] with open(output_folder / f"{problem_name}.mps", "w") as f: f.write(mps_str) filename = str(output_folder / f"{problem_name}.mps") solutionname = str(output_folder / f"{problem_name}.sol") csvname = str(output_folder / f"{problem_name}.csv") solve_and_get_solution(filename, solutionname, m) selected_players = [] for i in players: if z[i].get_value() > 0.5 and x[i].get_value() < 0.5: selected_players.append([i, gw, 0, False, 0]) elif x[i].get_value() > 0.5 and y[i].get_value() < 0.5: selected_players.append([i, gw, 1, False, 1]) elif x[i].get_value() > 0.5 and y[i].get_value() > 0.5: selected_players.append([i, gw, 2, True, 1]) results = pd.DataFrame(selected_players, columns=['player_id', 'event', 'multiplier', 'is_captain', 'starting_lineup']) result_df = pd.merge(next_week_df, results, on=['player_id', 'event'], how='inner') result_df = result_df[['player_id', 'web_name', 'team_code', 'element_type', 'now_cost', 'event', 'points_md', 'is_captain', 'multiplier', 'starting_lineup', 'selected_by_percent']].copy() result_df['gw_points'] = result_df['multiplier'] * result_df['points_md'] result_df = result_df.sort_values(by=['starting_lineup', 'element_type', 'player_id'], ascending=[False, True, True], ignore_index=True) result_df.reset_index(drop=True, inplace=True) result_df.to_csv(csvname, encoding='utf-8') lineup_players = result_df['web_name'].tolist()[0:11] with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.encoding', 'UTF-8'): print(result_df) print(weights, ) print(m.get_objective_value()) return {"gain": total_gain.get_value(), "loss": total_loss.get_value(), "obj": weighted_net.get_value(), "net": overall_net.get_value(), "lineup": ', '.join(lineup_players)}
def solve_multiperiod(input_folder, output_folder, options): """Solves for best squads iteratively for generating an interactive list""" df = pd.read_csv(input_folder / 'element_gameweek.csv') if options.get('target_weeks') is None: next_week = df['event'].min() element_gameweek_df = df[df['event'] < next_week+3].copy() else: element_gameweek_df = df[df['event'].isin(options.get('target_weeks'))].copy() df = pd.read_csv(input_folder / 'element.csv') element_df = df.copy().set_index('id') element_gameweek_df = pd.merge(left=element_gameweek_df, right=df, how='inner', left_on=['player_id'], right_on=['id'], suffixes=('', '_extra')) element_gameweek_df['rawxp'] = element_gameweek_df.apply(lambda r: r['points_md'] * 90 / max(1, r['xmins_md']), axis=1) elements = element_gameweek_df['player_id'].unique().tolist() gameweeks = element_gameweek_df['event'].unique().tolist() total_weeks = len(gameweeks) copy_gw_df = element_gameweek_df.copy() copy_gw_df = copy_gw_df.groupby(['player_id', 'event']).first().reset_index() element_gameweek_df.set_index(['player_id', 'event'], inplace=True, drop=True) element_gameweek_df = element_gameweek_df.groupby(element_gameweek_df.index).first() team_codes = element_gameweek_df['team_code'].unique().tolist() types_df = pd.read_csv(input_folder / 'element_type.csv') types = types_df['id'].to_list() types_df.set_index('id', inplace=True, drop=True) position = [1,2,3,4] element_gameweek = [(e, g) for e in elements for g in gameweeks] m = so.Model(name='iterative_model', session=None) lineup = m.add_variables(elements, gameweeks, name='lineup', vartype=so.BIN) captain = m.add_variables(elements, gameweeks, name='captain', vartype=so.BIN) squad = m.add_variables(elements, name='squad', vartype=so.BIN) bench = m.add_variables(elements, gameweeks, position, name='bench', vartype=so.BIN) m.add_constraints( (so.quick_sum(lineup[e, g] for e in elements) == 11 for g in gameweeks), name='lineup_limit_per_week') m.add_constraints(( so.quick_sum(lineup[e, g] for e in elements if element_df.loc[e]['element_type'] == et) >= types_df.loc[et]['squad_min_play'] for et in types for g in gameweeks), name='squad_min') m.add_constraints(( so.quick_sum(lineup[e, g] for e in elements if element_df.loc[e]['element_type'] == et) <= types_df.loc[et]['squad_max_play'] for et in types for g in gameweeks), name='squad_max') m.add_constraints((so.quick_sum(captain[e, g] for e in elements) == 1 for g in gameweeks), name='single_captain') m.add_constraints((captain[e, g] <= lineup[e, g] for e in elements for g in gameweeks), name='captain_should_play') # Limit constraints m.add_constraints(( so.quick_sum(squad[e] for e in elements if element_df.loc[e]['element_type'] == et) == types_df.loc[et]['squad_select'] for et in types), name='squad_exact') m.add_constraint(so.quick_sum(squad[e] for e in elements) == 15, name='squad_limit') m.add_constraints( (so.quick_sum(squad[e] for e in elements if element_df.loc[e]['team_code'] == j) <= 3 for j in team_codes), name='player_team_limit') m.add_constraints( (lineup[e, g] <= squad[e] for e in elements for g in gameweeks), name='lineup_squad_con') m.add_constraints( (bench[e, g, p] <= squad[e] for e in elements for g in gameweeks for p in position), name='bench_squad_con') m.add_constraints( (so.quick_sum(bench[e, g, p] for e in elements) == 1 for g in gameweeks for p in position), name='bench_position_con') m.add_constraints( (so.quick_sum(bench[e, g, 1] for e in elements if element_df.loc[e]['element_type'] == 1) == 1 for g in gameweeks), name='only_gk_bench1') m.add_constraints( (lineup[e, g] + so.quick_sum(bench[e, g, p] for p in position) == squad[e] for e in elements for g in gameweeks), name='lineup_plus_bench_equal_squad') # Budget Constraint budget_con = m.add_constraint(so.quick_sum(squad[e] * element_df.loc[e]['now_cost'] for e in elements) <= options.get('budget', 100) * 10, name='budget_con') total_points = so.quick_sum(element_gameweek_df.loc[[(e,g)]].iloc[0]['points_md'] * (lineup[e, g]+ captain[e,g]) for e in elements for g in gameweeks) m.set_objective(-total_points, sense='N', name='maximize_points') name = options['name'] filename = str(output_folder / f"{name}.mps") solutionname = str(output_folder / f"{name}.sol") csvname = str(output_folder / f"{name}.csv") xlsname = str(output_folder / f"{name}.xlsx") mps_str = get_mps_string(m) with open(output_folder / f"{name}.mps", "w") as f: f.write(mps_str) for v in m.get_variables(): v.set_value(0) solve_and_get_solution(filename, solutionname, m) # Parse solution selected_players = [] solution = {"squad":[], "lineup": {g:[] for g in gameweeks}, "bench": {g:{} for g in gameweeks}, "captain": {g: 0 for g in gameweeks}, "ownership": {}} for e in elements: if squad[e].get_value() > 0.5: solution['squad'].append(e) for g in gameweeks: for e in elements: if squad[e].get_value() > 0.5: if captain[e, g].get_value() > 0.5: solution['captain'][g] = e selected_players.append([g, e, 2, True, 1]) elif lineup[e, g].get_value() > 0.5: solution['lineup'][g].append(e) selected_players.append([g, e, 1, False, 1]) elif squad[e].get_value() > 0.5: for p in position: if bench[e, g, p].get_value() > 0.5: solution['bench'][g][p] = e selected_players.append([g, e, 0, False, 0]) print(solution) results = pd.DataFrame(selected_players, columns=['event', 'player_id', 'multiplier', 'is_captain', 'starting_lineup']) result_df = pd.merge(copy_gw_df, results, on=['player_id', 'event'], how='inner') result_df = result_df[['event', 'player_id', 'web_name', 'team_code', 'element_type', 'now_cost', 'points_md', 'is_captain', 'multiplier', 'starting_lineup', 'selected_by_percent']].copy() result_df = result_df.sort_values(by=['event', 'starting_lineup', 'element_type', 'player_id'], ascending=[True, False, True, True], ignore_index=True) result_df.reset_index(drop=True, inplace=True) result_df.to_csv(csvname, encoding='utf-8') result_df.to_excel(xlsname, encoding='utf-8') with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.encoding', 'UTF-8'): print(result_df) print(m.get_objective_value())
def test(cas_conn): m = so.Model(name='factory_planning_1', session=cas_conn) # Input data product_list = ['prod{}'.format(i) for i in range(1, 8)] product_data = pd.DataFrame([10, 6, 8, 4, 11, 9, 3], columns=['profit'], index=product_list) demand_data = [ [500, 1000, 300, 300, 800, 200, 100], [600, 500, 200, 0, 400, 300, 150], [300, 600, 0, 0, 500, 400, 100], [200, 300, 400, 500, 200, 0, 100], [0, 100, 500, 100, 1000, 300, 0], [500, 500, 100, 300, 1100, 500, 60]] demand_data = pd.DataFrame( demand_data, columns=product_list, index=range(1, 7)) machine_types_data = [ ['grinder', 4], ['vdrill', 2], ['hdrill', 3], ['borer', 1], ['planer', 1]] machine_types_data = pd.DataFrame(machine_types_data, columns=[ 'machine_type', 'num_machines']).set_index(['machine_type']) machine_type_period_data = [ ['grinder', 1, 1], ['hdrill', 2, 2], ['borer', 3, 1], ['vdrill', 4, 1], ['grinder', 5, 1], ['vdrill', 5, 1], ['planer', 6, 1], ['hdrill', 6, 1]] machine_type_period_data = pd.DataFrame(machine_type_period_data, columns=[ 'machine_type', 'period', 'num_down']) machine_type_product_data = [ ['grinder', 0.5, 0.7, 0, 0, 0.3, 0.2, 0.5], ['vdrill', 0.1, 0.2, 0, 0.3, 0, 0.6, 0], ['hdrill', 0.2, 0, 0.8, 0, 0, 0, 0.6], ['borer', 0.05, 0.03, 0, 0.07, 0.1, 0, 0.08], ['planer', 0, 0, 0.01, 0, 0.05, 0, 0.05]] machine_type_product_data = \ pd.DataFrame(machine_type_product_data, columns=['machine_type'] + product_list).set_index(['machine_type']) store_ub = 100 storage_cost_per_unit = 0.5 final_storage = 50 num_hours_per_period = 24 * 2 * 8 # Problem definition PRODUCTS = product_list PERIODS = range(1, 7) MACHINE_TYPES = machine_types_data.index.values num_machine_per_period = pd.DataFrame() for i in range(1, 7): num_machine_per_period[i] = machine_types_data['num_machines'] for _, row in machine_type_period_data.iterrows(): num_machine_per_period.at[row['machine_type'], row['period']] -= row['num_down'] make = m.add_variables(PRODUCTS, PERIODS, lb=0, name='make') sell = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=demand_data.transpose(), name='sell') store = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=store_ub, name='store') for p in PRODUCTS: store[p, 6].set_bounds(lb=final_storage, ub=final_storage+1) storageCost = storage_cost_per_unit * store.sum('*', '*') revenue = so.expr_sum(product_data.at[p, 'profit'] * sell[p, t] for p in PRODUCTS for t in PERIODS) m.set_objective(revenue-storageCost, sense=so.MAX, name='total_profit') production_time = machine_type_product_data m.add_constraints(( so.expr_sum(production_time.at[mc, p] * make[p, t] for p in PRODUCTS) <= num_hours_per_period * num_machine_per_period.at[mc, t] for mc in MACHINE_TYPES for t in PERIODS), name='machine_hours') m.add_constraints(((store[p, t-1] if t-1 in PERIODS else 0) + make[p, t] == sell[p, t] + store[p, t] for p in PRODUCTS for t in PERIODS), name='flow_balance') res = m.solve() if res is not None: print(so.get_solution_table(make, sell, store)) return m.get_objective_value()
def test(cas_conn): m = so.Model(name='decentralization', session=cas_conn) DEPTS = ['A', 'B', 'C', 'D', 'E'] CITIES = ['Bristol', 'Brighton', 'London'] benefit_data = pd.DataFrame( [['Bristol', 10, 15, 10, 20, 5], ['Brighton', 10, 20, 15, 15, 15]], columns=['city'] + DEPTS).set_index('city') comm_data = pd.DataFrame( [['A', 'B', 0.0], ['A', 'C', 1.0], ['A', 'D', 1.5], ['A', 'E', 0.0], ['B', 'C', 1.4], ['B', 'D', 1.2], ['B', 'E', 0.0], ['C', 'D', 0.0], ['C', 'E', 2.0], ['D', 'E', 0.7]], columns=['i', 'j', 'comm']).set_index(['i', 'j']) cost_data = pd.DataFrame( [['Bristol', 'Bristol', 5], ['Bristol', 'Brighton', 14], ['Bristol', 'London', 13], ['Brighton', 'Brighton', 5], ['Brighton', 'London', 9], ['London', 'London', 10]], columns=['i', 'j', 'cost']).set_index(['i', 'j']) max_num_depts = 3 benefit = {} for city in CITIES: for dept in DEPTS: try: benefit[dept, city] = benefit_data.loc[city, dept] except: benefit[dept, city] = 0 comm = {} for row in comm_data.iterrows(): (i, j) = row[0] comm[i, j] = row[1]['comm'] comm[j, i] = comm[i, j] cost = {} for row in cost_data.iterrows(): (i, j) = row[0] cost[i, j] = row[1]['cost'] cost[j, i] = cost[i, j] assign = m.add_variables(DEPTS, CITIES, vartype=so.BIN, name='assign') IJKL = [(i, j, k, l) for i in DEPTS for j in CITIES for k in DEPTS for l in CITIES if i < k] product = m.add_variables(IJKL, vartype=so.BIN, name='product') totalBenefit = so.expr_sum(benefit[i, j] * assign[i, j] for i in DEPTS for j in CITIES) totalCost = so.expr_sum(comm[i, k] * cost[j, l] * product[i, j, k, l] for (i, j, k, l) in IJKL) m.set_objective(totalBenefit - totalCost, name='netBenefit', sense=so.MAX) m.add_constraints((so.expr_sum(assign[dept, city] for city in CITIES) == 1 for dept in DEPTS), name='assign_dept') m.add_constraints((so.expr_sum(assign[dept, city] for dept in DEPTS) <= max_num_depts for city in CITIES), name='cardinality') product_def1 = m.add_constraints( (assign[i, j] + assign[k, l] - 1 <= product[i, j, k, l] for (i, j, k, l) in IJKL), name='pd1') product_def2 = m.add_constraints( (product[i, j, k, l] <= assign[i, j] for (i, j, k, l) in IJKL), name='pd2') product_def3 = m.add_constraints( (product[i, j, k, l] <= assign[k, l] for (i, j, k, l) in IJKL), name='pd3') m.solve() print(m.get_problem_summary()) m.drop_constraints(product_def1) m.drop_constraints(product_def2) m.drop_constraints(product_def3) m.add_constraints( (so.expr_sum(product[i, j, k, l] for j in CITIES if (i, j, k, l) in IJKL) == assign[k, l] for i in DEPTS for k in DEPTS for l in CITIES if i < k), name='pd4') m.add_constraints( (so.expr_sum(product[i, j, k, l] for l in CITIES if (i, j, k, l) in IJKL) == assign[i, j] for k in DEPTS for i in DEPTS for j in CITIES if i < k), name='pd5') m.solve() print(m.get_problem_summary()) totalBenefit.set_name('totalBenefit') totalCost.set_name('totalCost') print(so.get_solution_table(totalBenefit, totalCost)) print(so.get_solution_table(assign).unstack(level=-1)) return m.get_objective_value()
def test(cas_conn): # Input data demand_data = pd.DataFrame([ [0, 2000, 1500, 1000], [1, 1000, 1400, 1000], [2, 500, 2000, 1500], [3, 0, 2500, 2000] ], columns=['period', 'unskilled', 'semiskilled', 'skilled'])\ .set_index(['period']) worker_data = pd.DataFrame( [['unskilled', 0.25, 0.10, 500, 200, 1500, 50, 500], ['semiskilled', 0.20, 0.05, 800, 500, 2000, 50, 400], ['skilled', 0.10, 0.05, 500, 500, 3000, 50, 400]], columns=[ 'worker', 'waste_new', 'waste_old', 'recruit_ub', 'redundancy_cost', 'overmanning_cost', 'shorttime_ub', 'shorttime_cost' ]).set_index(['worker']) retrain_data = pd.DataFrame([ ['unskilled', 'semiskilled', 200, 400], ['semiskilled', 'skilled', math.inf, 500], ], columns=['worker1', 'worker2', 'retrain_ub', 'retrain_cost']).\ set_index(['worker1', 'worker2']) downgrade_data = pd.DataFrame( [['semiskilled', 'unskilled'], ['skilled', 'semiskilled'], ['skilled', 'unskilled']], columns=['worker1', 'worker2']) semiskill_retrain_frac_ub = 0.25 downgrade_leave_frac = 0.5 overmanning_ub = 150 shorttime_frac = 0.5 # Sets WORKERS = worker_data.index.tolist() PERIODS0 = demand_data.index.tolist() PERIODS = PERIODS0[1:] RETRAIN_PAIRS = [i for i, _ in retrain_data.iterrows()] DOWNGRADE_PAIRS = [(row['worker1'], row['worker2']) for _, row in downgrade_data.iterrows()] waste_old = worker_data['waste_old'] waste_new = worker_data['waste_new'] redundancy_cost = worker_data['redundancy_cost'] overmanning_cost = worker_data['overmanning_cost'] shorttime_cost = worker_data['shorttime_cost'] retrain_cost = retrain_data['retrain_cost'].unstack(level=-1) # Initialization m = so.Model(name='manpower_planning', session=cas_conn) # Variables numWorkers = m.add_variables(WORKERS, PERIODS0, name='numWorkers', lb=0) demand0 = demand_data.loc[0] for w in WORKERS: numWorkers[w, 0].set_bounds(lb=demand0[w], ub=demand0[w]) numRecruits = m.add_variables(WORKERS, PERIODS, name='numRecruits', lb=0) worker_ub = worker_data['recruit_ub'] for w in WORKERS: for p in PERIODS: numRecruits[w, p].set_bounds(ub=worker_ub[w]) numRedundant = m.add_variables(WORKERS, PERIODS, name='numRedundant', lb=0) numShortTime = m.add_variables(WORKERS, PERIODS, name='numShortTime', lb=0) shorttime_ub = worker_data['shorttime_ub'] for w in WORKERS: for p in PERIODS: numShortTime.set_bounds(ub=shorttime_ub[w]) numExcess = m.add_variables(WORKERS, PERIODS, name='numExcess', lb=0) retrain_ub = pd.DataFrame() for i in PERIODS: retrain_ub[i] = retrain_data['retrain_ub'] numRetrain = m.add_variables(RETRAIN_PAIRS, PERIODS, name='numRetrain', lb=0, ub=retrain_ub) numDowngrade = m.add_variables(DOWNGRADE_PAIRS, PERIODS, name='numDowngrade', lb=0) # Constraints m.add_constraints( (numWorkers[w, p] - (1 - shorttime_frac) * numShortTime[w, p] - numExcess[w, p] == demand_data.loc[p, w] for w in WORKERS for p in PERIODS), name='demand') m.add_constraints( (numWorkers[w, p] == (1 - waste_old[w]) * numWorkers[w, p - 1] + (1 - waste_new[w]) * numRecruits[w, p] + (1 - waste_old[w]) * numRetrain.sum('*', w, p) + (1 - downgrade_leave_frac) * numDowngrade.sum('*', w, p) - numRetrain.sum(w, '*', p) - numDowngrade.sum(w, '*', p) - numRedundant[w, p] for w in WORKERS for p in PERIODS), name='flow_balance') m.add_constraints((numRetrain['semiskilled', 'skilled', p] <= semiskill_retrain_frac_ub * numWorkers['skilled', p] for p in PERIODS), name='semiskill_retrain') m.add_constraints( (numExcess.sum('*', p) <= overmanning_ub for p in PERIODS), name='overmanning') # Objectives redundancy = so.Expression(numRedundant.sum('*', '*'), name='redundancy') cost = so.Expression( so.expr_sum(redundancy_cost[w] * numRedundant[w, p] + shorttime_cost[w] * numShortTime[w, p] + overmanning_cost[w] * numExcess[w, p] for w in WORKERS for p in PERIODS) + so.expr_sum(retrain_cost.loc[i, j] * numRetrain[i, j, p] for i, j in RETRAIN_PAIRS for p in PERIODS), name='cost') m.set_objective(redundancy, sense=so.MIN, name='redundancy_obj') res = m.solve() if res is not None: print('Redundancy:', redundancy.get_value()) print('Cost:', cost.get_value()) print( so.get_solution_table(numWorkers, numRecruits, numRedundant, numShortTime, numExcess)) print(so.get_solution_table(numRetrain)) print(so.get_solution_table(numDowngrade)) m.set_objective(cost, sense=so.MIN, name='cost_obj') res = m.solve() if res is not None: print('Redundancy:', redundancy.get_value()) print('Cost:', cost.get_value()) print( so.get_solution_table(numWorkers, numRecruits, numRedundant, numShortTime, numExcess)) print(so.get_solution_table(numRetrain)) print(so.get_solution_table(numDowngrade)) return m.get_objective_value()
def solve_optimal_squad(self, budget=100): players = self.forecasts.index positions = self.positions.index teams = self.teams.index model_name = f'gw{self.gw}_{budget}budget' model = so.Model(model_name) # Variables squad = model.add_variables(players,name='squad', vartype=so.binary) lineup = model.add_variables(players, name='lineup', vartype=so.binary) captain = model.add_variables(players, name='captain', vartype=so.binary) vicecap = model.add_variables(players, name='vicecap', vartype=so.binary) # Constraints # 15 players in squad squad_count = so.expr_sum(squad[p] for p in players) model.add_constraint(squad_count == 15, name='squad_count') # 11 players in starting lineup model.add_constraint(so.expr_sum(lineup[p] for p in players) == 11, name='lineup_count') # 1 captain model.add_constraint(so.expr_sum(captain[p] for p in players) == 1, name='captain_count') # 1 vice-captain model.add_constraint(so.expr_sum(vicecap[p] for p in players) == 1, name='vicecap_count') # players in starting lineup must also be in squad model.add_constraints((lineup[p] <= squad[p] for p in players), name='lineup_squad_rel') # captain must come from within squad model.add_constraints((captain[p] <= lineup[p] for p in players), name='captain_lineup_rel') # vice-captain must come from within squad model.add_constraints((vicecap[p] <= lineup[p] for p in players), name='vicecap_lineup_rel') # captain and vice-captain can't be same person model.add_constraints((captain[p] + vicecap[p] <= 1 for p in players), name='cap_vc_rel') # count of each player per position in starting lineup lineup_type_count = { t: so.expr_sum(lineup[p] for p in players if self.forecasts.loc[p, 'position_id'] == t) for t in positions} # count of all players in lineup must be at least 'squad_min_play' # and no more than 'squad_max_play' for each position type model.add_constraints( (lineup_type_count[t] == [self.positions.loc[t, 'squad_min_play'], self.positions.loc[t, 'squad_max_play']] for t in positions), name='valid_formation') # count of each player per position in squad squad_type_count = { t: so.expr_sum(squad[p] for p in players if self.forecasts.loc[p, 'position_id'] == t) for t in positions} # count of all players in squad must be equal to 'squad_select' # for each position type model.add_constraints( (squad_type_count[t] == self.positions.loc[t, 'squad_select'] for t in positions), name='valid_squad') # total value of squad cannot exceed budget price = so.expr_sum( self.forecasts.loc[p, 'bv'] * squad[p] for p in players) model.add_constraint(price <= budget, name='budget_limit') # no more than 3 players per team model.add_constraints( ( so.expr_sum(squad[p] for p in players if self.forecasts.loc[p, 'team_id'] == t) <= 3 for t in teams), name='team_limit' ) # sum of starting 11 players, plus double captain score # and upweight vice-captain total_points = so.expr_sum(self.forecasts.loc[p, f'{self.gw}_pts'] * (lineup[p] + captain[p] + 0.1 * vicecap[p]) for p in players) # Objective model.set_objective(-total_points, sense='N', name='total_xp') model.export_mps(f'{model_name}.mps') command = f'cbc {model_name}.mps solve solu {model_name}.txt' Popen(command, shell=False, stdout=DEVNULL).wait() for v in model.get_variables(): v.set_value(0) with open(f'{model_name}.txt', 'r') as f: for line in f: if 'objective value' in line: continue words = line.split() var = model.get_variable(words[1]) var.set_value(float(words[2])) picks = [] for p in players: if squad[p].get_value() > .5: lp = self.forecasts.loc[p] is_captain = 1 if captain[p].get_value() > .5 else 0 is_lineup = 1 if lineup[p].get_value() > .5 else 0 is_vice = 1 if vicecap[p].get_value() > .5 else 0 position = self.positions.loc[lp['position_id'], 'position_name'] team = self.teams.loc[lp['team_id'], 'team_name'] picks.append([lp['web_name'], lp['position_id'], position, team, lp['bv'], round(lp[f'{self.gw}_pts'], 2), is_lineup, is_captain, is_vice]) picks_df = pd.DataFrame( picks, columns=['Name', 'Pos_id', 'Pos', 'Team', 'Price', 'xP', 'lineup', 'captain', 'vicecaptain'] ).sort_values(by=['lineup', 'Pos_id', 'xP'], ascending=[False, True, True]) total_xp = so.expr_sum((lineup[p] + captain[p]) * self.forecasts.loc[p, f'{self.gw}_pts'] for p in players).get_value() print(f'Total expected value for budget {budget:.1f}: {total_xp:.2f}') os.remove(f'{model_name}.mps') os.remove(f'{model_name}.txt') return picks_df
def test(cas_conn): m = so.Model(name='farm_planning', session=cas_conn) # Input Data cow_data_raw = [] for age in range(12): if age < 2: row = { 'age': age, 'init_num_cows': 10, 'acres_needed': 2 / 3.0, 'annual_loss': 0.05, 'bullock_yield': 0, 'heifer_yield': 0, 'milk_revenue': 0, 'grain_req': 0, 'sugar_beet_req': 0, 'labour_req': 10, 'other_costs': 50 } else: row = { 'age': age, 'init_num_cows': 10, 'acres_needed': 1, 'annual_loss': 0.02, 'bullock_yield': 1.1 / 2, 'heifer_yield': 1.1 / 2, 'milk_revenue': 370, 'grain_req': 0.6, 'sugar_beet_req': 0.7, 'labour_req': 42, 'other_costs': 100 } cow_data_raw.append(row) cow_data = pd.DataFrame(cow_data_raw).set_index(['age']) grain_data = pd.DataFrame([['group1', 20, 1.1], ['group2', 30, 0.9], ['group3', 20, 0.8], ['group4', 10, 0.65]], columns=['group', 'acres', 'yield']).set_index(['group']) num_years = 5 num_acres = 200 bullock_revenue = 30 heifer_revenue = 40 dairy_cow_selling_age = 12 dairy_cow_selling_revenue = 120 max_num_cows = 130 sugar_beet_yield = 1.5 grain_cost = 90 grain_revenue = 75 grain_labour_req = 4 grain_other_costs = 15 sugar_beet_cost = 70 sugar_beet_revenue = 58 sugar_beet_labour_req = 14 sugar_beet_other_costs = 10 nominal_labour_cost = 4000 nominal_labour_hours = 5500 excess_labour_cost = 1.2 capital_outlay_unit = 200 num_loan_years = 10 annual_interest_rate = 0.15 max_decrease_ratio = 0.50 max_increase_ratio = 0.75 # Sets AGES = cow_data.index.tolist() init_num_cows = cow_data['init_num_cows'] acres_needed = cow_data['acres_needed'] annual_loss = cow_data['annual_loss'] bullock_yield = cow_data['bullock_yield'] heifer_yield = cow_data['heifer_yield'] milk_revenue = cow_data['milk_revenue'] grain_req = cow_data['grain_req'] sugar_beet_req = cow_data['sugar_beet_req'] cow_labour_req = cow_data['labour_req'] cow_other_costs = cow_data['other_costs'] YEARS = list(range(1, num_years + 1)) YEARS0 = [0] + YEARS # Variables numCows = m.add_variables(AGES + [dairy_cow_selling_age], YEARS0, lb=0, name='numCows') for age in AGES: numCows[age, 0].set_bounds(lb=init_num_cows[age], ub=init_num_cows[age]) numCows[dairy_cow_selling_age, 0].set_bounds(lb=0, ub=0) numBullocksSold = m.add_variables(YEARS, lb=0, name='numBullocksSold') numHeifersSold = m.add_variables(YEARS, lb=0, name='numHeifersSold') GROUPS = grain_data.index.tolist() acres = grain_data['acres'] grain_yield = grain_data['yield'] grainAcres = m.add_variables(GROUPS, YEARS, lb=0, name='grainAcres') for group in GROUPS: for year in YEARS: grainAcres[group, year].set_bounds(ub=acres[group]) grainBought = m.add_variables(YEARS, lb=0, name='grainBought') grainSold = m.add_variables(YEARS, lb=0, name='grainSold') sugarBeetAcres = m.add_variables(YEARS, lb=0, name='sugarBeetAcres') sugarBeetBought = m.add_variables(YEARS, lb=0, name='sugarBeetBought') sugarBeetSold = m.add_variables(YEARS, lb=0, name='sugarBeetSold') numExcessLabourHours = m.add_variables(YEARS, lb=0, name='numExcessLabourHours') capitalOutlay = m.add_variables(YEARS, lb=0, name='capitalOutlay') yearly_loan_payment = (annual_interest_rate * capital_outlay_unit) /\ (1 - (1+annual_interest_rate)**(-num_loan_years)) # Objective function revenue = { year: bullock_revenue * numBullocksSold[year] + heifer_revenue * numHeifersSold[year] + dairy_cow_selling_revenue * numCows[dairy_cow_selling_age, year] + so.expr_sum(milk_revenue[age] * numCows[age, year] for age in AGES) + grain_revenue * grainSold[year] + sugar_beet_revenue * sugarBeetSold[year] for year in YEARS } cost = { year: grain_cost * grainBought[year] + sugar_beet_cost * sugarBeetBought[year] + nominal_labour_cost + excess_labour_cost * numExcessLabourHours[year] + so.expr_sum(cow_other_costs[age] * numCows[age, year] for age in AGES) + so.expr_sum(grain_other_costs * grainAcres[group, year] for group in GROUPS) + sugar_beet_other_costs * sugarBeetAcres[year] + so.expr_sum(yearly_loan_payment * capitalOutlay[y] for y in YEARS if y <= year) for year in YEARS } profit = {year: revenue[year] - cost[year] for year in YEARS} totalProfit = so.expr_sum(profit[year] - yearly_loan_payment * (num_years - 1 + year) * capitalOutlay[year] for year in YEARS) m.set_objective(totalProfit, sense=so.MAX, name='totalProfit') # Constraints m.add_constraints( (so.expr_sum(acres_needed[age] * numCows[age, year] for age in AGES) + so.expr_sum(grainAcres[group, year] for group in GROUPS) + sugarBeetAcres[year] <= num_acres for year in YEARS), name='num_acres') m.add_constraints((numCows[age + 1, year + 1] == (1 - annual_loss[age]) * numCows[age, year] for age in AGES if age != dairy_cow_selling_age for year in YEARS0 if year != num_years), name='aging') m.add_constraints((numBullocksSold[year] == so.expr_sum( bullock_yield[age] * numCows[age, year] for age in AGES) for year in YEARS), name='numBullocksSold_def') m.add_constraints((numCows[0, year] == so.expr_sum(heifer_yield[age] * numCows[age, year] for age in AGES) - numHeifersSold[year] for year in YEARS), name='numHeifersSold_def') m.add_constraints((so.expr_sum(numCows[age, year] for age in AGES) <= max_num_cows + so.expr_sum(capitalOutlay[y] for y in YEARS if y <= year) for year in YEARS), name='max_num_cows_def') grainGrown = {(group, year): grain_yield[group] * grainAcres[group, year] for group in GROUPS for year in YEARS} m.add_constraints( (so.expr_sum(grain_req[age] * numCows[age, year] for age in AGES) <= so.expr_sum(grainGrown[group, year] for group in GROUPS) + grainBought[year] - grainSold[year] for year in YEARS), name='grain_req_def') sugarBeetGrown = {(year): sugar_beet_yield * sugarBeetAcres[year] for year in YEARS} m.add_constraints( (so.expr_sum(sugar_beet_req[age] * numCows[age, year] for age in AGES) <= sugarBeetGrown[year] + sugarBeetBought[year] - sugarBeetSold[year] for year in YEARS), name='sugar_beet_req_def') m.add_constraints((so.expr_sum(cow_labour_req[age] * numCows[age, year] for age in AGES) + so.expr_sum(grain_labour_req * grainAcres[group, year] for group in GROUPS) + sugar_beet_labour_req * sugarBeetAcres[year] <= nominal_labour_hours + numExcessLabourHours[year] for year in YEARS), name='labour_req_def') m.add_constraints((profit[year] >= 0 for year in YEARS), name='cash_flow') m.add_constraint(so.expr_sum(numCows[age, num_years] for age in AGES if age >= 2) / sum(init_num_cows[age] for age in AGES if age >= 2) == [ 1 - max_decrease_ratio, 1 + max_increase_ratio ], name='final_dairy_cows_range') res = m.solve() if res is not None: so.pd.display_all() print(so.get_solution_table(numCows)) revenue_df = so.dict_to_frame(revenue, cols=['revenue']) cost_df = so.dict_to_frame(cost, cols=['cost']) profit_df = so.dict_to_frame(profit, cols=['profit']) print( so.get_solution_table(numBullocksSold, numHeifersSold, capitalOutlay, numExcessLabourHours, revenue_df, cost_df, profit_df)) gg_df = so.dict_to_frame(grainGrown, cols=['grainGrown']) print(so.get_solution_table(grainAcres, gg_df)) sbg_df = so.dict_to_frame(sugarBeetGrown, cols=['sugerBeetGrown']) print( so.get_solution_table(grainBought, grainSold, sugarBeetAcres, sbg_df, sugarBeetBought, sugarBeetSold)) num_acres = m.get_constraint('num_acres') na_df = num_acres.get_expressions() max_num_cows_con = m.get_constraint('max_num_cows_def') mnc_df = max_num_cows_con.get_expressions() print(so.get_solution_table(na_df, mnc_df)) return m.get_objective_value()
def test(cas_conn, sols=False): # Upload data to server first xy_raw = pd.DataFrame([ [0.0, 1.0], [0.5, 0.9], [1.0, 0.7], [1.5, 1.5], [1.9, 2.0], [2.5, 2.4], [3.0, 3.2], [3.5, 2.0], [4.0, 2.7], [4.5, 3.5], [5.0, 1.0], [5.5, 4.0], [6.0, 3.6], [6.6, 2.7], [7.0, 5.7], [7.6, 4.6], [8.5, 6.0], [9.0, 6.8], [10.0, 7.3] ], columns=['x', 'y']) xy_data = cas_conn.upload_frame(xy_raw, casout={'name': 'xy_data', 'replace': True}) # Read observations POINTS, (x, y), xy_table_ref = so.read_table(xy_data, columns=['x', 'y']) # Parameters and variables order = so.Parameter(name='order') beta = so.VariableGroup(so.exp_range(0, order), name='beta') estimate = so.ImplicitVar( (beta[0] + so.quick_sum(beta[k] * x[i] ** k for k in so.exp_range(1, order)) for i in POINTS), name='estimate') surplus = so.VariableGroup(POINTS, name='surplus', lb=0) slack = so.VariableGroup(POINTS, name='slack', lb=0) objective1 = so.Expression( so.quick_sum(surplus[i] + slack[i] for i in POINTS), name='objective1') abs_dev_con = so.ConstraintGroup( (estimate[i] - surplus[i] + slack[i] == y[i] for i in POINTS), name='abs_dev_con') minmax = so.Variable(name='minmax') objective2 = so.Expression(minmax + 0.0, name='objective2') minmax_con = so.ConstraintGroup( (minmax >= surplus[i] + slack[i] for i in POINTS), name='minmax_con') order.set_init(1) L1 = so.Model(name='L1', session=cas_conn) L1.set_objective(objective1, sense=so.MIN) L1.include(POINTS, x, y, xy_table_ref) L1.include(order, beta, estimate, surplus, slack, abs_dev_con) L1.add_statement('print x y estimate surplus slack;', after_solve=True) L1.solve(verbose=True) sol_data1 = L1.response['Print3.PrintTable'].sort_values('x') print(so.get_solution_table(beta)) print(sol_data1.to_string()) Linf = so.Model(name='Linf', session=cas_conn) Linf.include(L1, minmax, minmax_con) Linf.set_objective(objective2, sense=so.MIN) Linf.solve() sol_data2 = Linf.response['Print3.PrintTable'].sort_values('x') print(so.get_solution_table(beta)) print(sol_data2.to_string()) order.set_init(2) L1.solve() sol_data3 = L1.response['Print3.PrintTable'].sort_values('x') print(so.get_solution_table(beta)) print(sol_data3.to_string()) Linf.solve() sol_data4 = Linf.response['Print3.PrintTable'].sort_values('x') print(so.get_solution_table(beta)) print(sol_data4.to_string()) if sols: return (sol_data1, sol_data2, sol_data3, sol_data4) else: return Linf.get_objective_value()
def tbfp(distance_data, game_data, venue_data, start_date=datetime.date(2019, 3, 28), end_date=datetime.date(2019, 10, 1), obj_type=0): # Define a CAS session cas_session = CAS(your_cas_server, port=your_cas_port) m = so.Model(name='tbfp', session=cas_session) t0 = time.time() # Discard games outside of the selected interval game_data = game_data[game_data['START'] >= start_date] game_data = game_data[game_data['END'] <= end_date] # Numerical assignment for source and sink source = 0 sink = 9999 # Define sets STADIUMS = sorted(venue_data.index.tolist()) game_data = game_data[game_data['VENUE'].isin(STADIUMS)] GAMES = game_data.index.tolist() NODES = GAMES + [source, sink] # Define parameters away = game_data['AWAY'] home = game_data['HOME'] start = game_data['START'] end = game_data['END'] location = game_data['VENUE'] city = game_data['CITY'] driving = distance_data['minutes'] distance = distance_data['miles'] lat = venue_data['lat'] lon = venue_data['lon'] min_dist = {s: 0 for s in STADIUMS} arg_min = {s: 0 for s in STADIUMS} print('Numer of GAMES: {}'.format(len(GAMES))) # Define all possible arcs in the network model ARCS = [] for g1 in GAMES: for s in STADIUMS: min_dist[s] = datetime.datetime(2020, 1, 1) arg_min[s] = -1 for g2 in GAMES: if location[g1] != location[g2]: time_between = driving[location[g1], location[g2]] driving_time = datetime.timedelta(minutes=float(time_between)) if end[g1] + driving_time <= start[g2] and min_dist[location[g2]] > start[g2]: min_dist[location[g2]] = start[g2] arg_min[location[g2]] = g2 for s in STADIUMS: if arg_min[s] != -1: ARCS.append((g1, arg_min[s])) ARCS = ARCS + [(source, g) for g in GAMES] + [(g, sink) for g in GAMES] print('Number of ARCS: {}'.format(len(ARCS))) cost = {} for (g1, g2) in ARCS: if g1 != source and g2 != sink: cost[g1, g2] = (end[g2] - end[g1]).total_seconds()/86400.0 elif g2 != sink and g1 == source: cost[g1, g2] = (end[g2]-start[g2]).total_seconds()/86400.0 else: cost[g1, g2] = 0 t1 = time.time() data_time = t1-t0 # Add variables use_arc = m.add_variables(ARCS, vartype=so.BIN, name='use_arc') # Define expressions for the objectives total_time = so.quick_sum( cost[g1, g2] * use_arc[g1, g2] for (g1, g2) in ARCS) total_distance = so.quick_sum( distance[location[g1], location[g2]] * use_arc[g1, g2] for (g1, g2) in ARCS if g1 != source and g2 != sink) total_cost = total_time * 130 + total_distance * 0.25 # Set objectives if obj_type == 0: m.set_objective(total_time, sense=so.MIN) elif obj_type == 1: m.set_objective(total_cost, sense=so.MIN) # Balance constraint m.add_constraints(( so.quick_sum(use_arc[g, g2] for (gx, g2) in ARCS if gx == g) - so.quick_sum(use_arc[g1, g] for (g1, gx) in ARCS if gx == g) == (1 if g == source else (-1 if g == sink else 0)) for g in NODES), name='balance') # Visit once constraint visit_once = so.ConstraintGroup(( so.quick_sum( use_arc[g1, g2] for (g1, g2) in ARCS if g2 != sink and location[g2] == s) == 1 for s in STADIUMS), name='visit_once') m.include(visit_once) prep_mark = time.time() prep_time = prep_mark - t1 # Send the problem to SAS Viya solvers and solve the problem m.solve(milp={'concurrent': True}, frame=True) solve_time = time.time() - prep_mark # Parse the results schedule = [] for (g1, g2) in ARCS: if (use_arc[g1, g2].get_value() > 0.5 and g1 != source and g2 != sink): if g1 not in schedule: schedule.append(g1) if g2 not in schedule: schedule.append(g2) # Sort the schedule and print information schedule = sorted(schedule, key=lambda i: start[i]) route = [] shortest_dist = [distance[location[schedule[0]], location[schedule[1]]], 1, 2] longest_dist = shortest_dist shortest_time = [ (start[schedule[1]] - end[schedule[0]]).total_seconds() / 60.0, 1, 2] longest_time = shortest_time most_critical = [shortest_time[0] - shortest_dist[0], 1, 2] c_game = -1 print('{:3} {:<30} {:<12} {:<12} {:<20} {:<19} {:<6} {:<6}'.format( 'Obs', 'Location', 'Away', 'Home', 'City', 'Time', 'Lat', 'Lon')) for i, g in enumerate(schedule): route.append([i+1, location[g], away[g], home[g], city[g], start[g], lat[location[g]], lon[location[g]]]) print('{:3d} {:<30} {:<12} {:<12} {:<20} {} {:6.3f} {:6.3f}'.format( *route[-1])) if c_game != -1: c_dis = distance[location[c_game], location[g]] c_driv = driving[location[c_game], location[g]] c_tim = (start[g] - end[c_game]).total_seconds() / 60.0 if c_dis > longest_dist[0]: longest_dist = [c_dis, i, i+1] if c_dis < shortest_dist[0]: shortest_dist = [c_dis, i, i+1] if c_tim > longest_time[0]: longest_time = [c_tim, i, i+1] if c_tim < shortest_time[0]: shortest_time = [c_tim, i, i+1] if c_tim - c_driv < most_critical[0]: most_critical = [c_tim - c_driv, i, i+1] c_game = g print('Total time: {}'.format(end[schedule[-1]] - start[schedule[0]])) # Save the resulting schedules and information into a file for notebook n_months = (end_date-start_date).total_seconds()/(60.0*60.0*24*30) out = '''objt: {} sdat: {} edat: {} mont: {:.1f} time: {:.3f} days dist: {:.3f} miles cost: {:.3f} USD gams: {} vars: {} cons: {} data: {:.3f} secs prep: {:.3f} secs solv: {:.3f} secs sdis: {} {}-{} ldis: {} {}-{} stim: {} {}-{} ltim: {} {}-{} mcri: {} {}-{} schd: [ '''.format(obj_type, start_date, end_date, n_months, total_time.get_value(), total_distance.get_value(), total_cost.get_value(), len(GAMES), len(m.get_variables()), len(m.get_constraints()), data_time, prep_time, solve_time, *shortest_dist, *longest_dist, *shortest_time, *longest_time, *most_critical) out += '{}'.format('\n'.join([','.join([str(j) for j in i]) for i in route])) out += '\n]' file = open('results/{}.txt'.format(id(m)), 'w') file.write(out) file.close() print(out)