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.expr_sum(-4 * x[i] + 3 for i in so.exp_range(1, N - 1)) + so.expr_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.get_solution_summary()) if m.get_session_type() == 'CAS': print(m.response['Print1.PrintTable'].head()) # Model 2 so.reset() 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.expr_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, 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 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 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): 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): # 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.expr_sum(revenue_per_ton * manufacture[p] for p in PERIODS) rawcost = so.expr_sum(cost.at[o, p] * buy[o, p] for o in OILS for p in PERIODS) storagecost = so.expr_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.expr_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.expr_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 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 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): # 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 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): # 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.expr_sum(revenue_per_ton * manufacture[p] for p in PERIODS) rawcost = so.expr_sum(cost.at[o, p] * buy[o, p] for o in OILS for p in PERIODS) storagecost = so.expr_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.expr_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.expr_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': 'IP'}) m.solve(options={'with': 'lp', 'algorithm': 'NS'}) if res is not None: print(so.get_solution_table(buy, use, store)) return m.get_objective_value()
def test(cas_conn, get_tables=False): input_list = pd.DataFrame( ['staff', 'showroom', 'pop1', 'pop2', 'alpha_enq', 'beta_enq'], columns=['input']) input_data = cas_conn.upload_frame(data=input_list, casout={ 'name': 'input_data', 'replace': True }) output_list = pd.DataFrame(['alpha_sales', 'beta_sales', 'profit'], columns=['output']) output_data = cas_conn.upload_frame(data=output_list, casout={ 'name': 'output_data', 'replace': True }) problem_data = pd.DataFrame([ ['Winchester', 7, 8, 10, 12, 8.5, 4, 2, 0.6, 1.5], ['Andover', 6, 6, 20, 30, 9, 4.5, 2.3, 0.7, 1.6], ['Basingstoke', 2, 3, 40, 40, 2, 1.5, 0.8, 0.25, 0.5], ['Poole', 14, 9, 20, 25, 10, 6, 2.6, 0.86, 1.9], ['Woking', 10, 9, 10, 10, 11, 5, 2.4, 1, 2], ['Newbury', 24, 15, 15, 13, 25, 19, 8, 2.6, 4.5], ['Portsmouth', 6, 7, 50, 40, 8.5, 3, 2.5, 0.9, 1.6], ['Alresford', 8, 7.5, 5, 8, 9, 4, 2.1, 0.85, 2], ['Salisbury', 5, 5, 10, 10, 5, 2.5, 2, 0.65, 0.9], ['Guildford', 8, 10, 30, 35, 9.5, 4.5, 2.05, 0.75, 1.7], ['Alton', 7, 8, 7, 8, 3, 2, 1.9, 0.7, 0.5], ['Weybridge', 5, 6.5, 9, 12, 8, 4.5, 1.8, 0.63, 1.4], ['Dorchester', 6, 7.5, 10, 10, 7.5, 4, 1.5, 0.45, 1.45], ['Bridport', 11, 8, 8, 10, 10, 6, 2.2, 0.65, 2.2], ['Weymouth', 4, 5, 10, 10, 7.5, 3.5, 1.8, 0.62, 1.6], ['Portland', 3, 3.5, 3, 2, 2, 1.5, 0.9, 0.35, 0.5], ['Chichester', 5, 5.5, 8, 10, 7, 3.5, 1.2, 0.45, 1.3], ['Petersfield', 21, 12, 6, 8, 15, 8, 6, 0.25, 2.9], ['Petworth', 6, 5.5, 2, 2, 8, 5, 1.5, 0.55, 1.55], ['Midhurst', 3, 3.6, 3, 3, 2.5, 1.5, 0.8, 0.2, 0.45], ['Reading', 30, 29, 120, 80, 35, 20, 7, 2.5, 8], ['Southampton', 25, 16, 110, 80, 27, 12, 6.5, 3.5, 5.4], ['Bournemouth', 19, 10, 90, 12, 25, 13, 5.5, 3.1, 4.5], ['Henley', 7, 6, 5, 7, 8.5, 4.5, 1.2, 0.48, 2], ['Maidenhead', 12, 8, 7, 10, 12, 7, 4.5, 2, 2.3], ['Fareham', 4, 6, 1, 1, 7.5, 3.5, 1.1, 0.48, 1.7], ['Romsey', 2, 2.5, 1, 1, 2.5, 1, 0.4, 0.1, 0.55], ['Ringwood', 2, 3.5, 2, 2, 1.9, 1.2, 0.3, 0.09, 0.4], ], columns=[ 'garage_name', 'staff', 'showroom', 'pop1', 'pop2', 'alpha_enq', 'beta_enq', 'alpha_sales', 'beta_sales', 'profit' ]) garage_data = cas_conn.upload_frame(data=problem_data, casout={ 'name': 'garage_data', 'replace': True }) with so.Workspace(name='efficiency_analysis', session=cas_conn) as w: inputs = so.Set(name='INPUTS', settype=so.string) read_data(table=input_data, index={'target': inputs, 'key': 'input'}) outputs = so.Set(name='OUTPUTS', settype=so.string) read_data(table=output_data, index={ 'target': outputs, 'key': 'output' }) garages = so.Set(name='GARAGES', settype=so.number) garage_name = so.ParameterGroup(garages, name='garage_name', ptype=so.string) input = so.ParameterGroup(inputs, garages, name='input') output = so.ParameterGroup(outputs, garages, name='output') r = read_data(table=garage_data, index={ 'target': garages, 'key': so.N }, columns=[garage_name]) with iterate(inputs, 'i') as i: r.append({'index': i, 'target': input[i, so.N], 'column': i}) with iterate(outputs, 'i') as i: r.append({'index': i, 'target': output[i, so.N], 'column': i}) k = so.Parameter(name='k', ptype=so.number) efficiency_number = so.ParameterGroup(garages, name='efficiency_number') weight_sol = so.ParameterGroup(garages, garages, name='weight_sol') weight = so.VariableGroup(garages, name='Weight', lb=0) inefficiency = so.Variable(name='Inefficiency', lb=0) obj = so.Objective(inefficiency, name='Objective', sense=so.maximize) input_con = so.ConstraintGroup( (so.expr_sum(input[i, j] * weight[j] for j in garages) <= input[i, k] for i in inputs), name='input_con') output_con = so.ConstraintGroup( (so.expr_sum(output[i, j] * weight[j] for j in garages) >= output[i, k] * inefficiency for i in outputs), name='output_con') for kk in cofor_loop(garages): k.set_value(kk) solve() efficiency_number[k] = 1 / inefficiency.sol for j in for_loop(garages): def if_block(): weight_sol[k, j] = weight[j].sol def else_block(): weight_sol[k, j] = None if_condition(weight[j].sol > 1e-6, if_block, else_block) efficient_garages = so.Set( name='EFFICIENT_GARAGES', value=[ j.sym for j in garages if j.sym.under_condition(efficiency_number[j] >= 1) ]) inefficient_garages = so.Set(value=diff(garages, efficient_garages), name='INEFFICIENT_GARAGES') p1 = print_item(garage_name, efficiency_number) ed = create_data(table='efficiency_data', index={'key': ['garage']}, columns=[garage_name, efficiency_number]) with iterate(inefficient_garages, 'inefficient_garage') as i: wd = create_data(table='weight_data_dense', index={ 'key': [i], 'set': [i.get_set()] }, columns=[garage_name, efficiency_number]) with iterate(efficient_garages, 'efficient_garage') as j: wd.append({ 'name': concat('w', j), 'expression': weight_sol[i, j], 'index': j }) filtered_set = so.InlineSet(lambda: ( (g1, g2) for g1 in inefficient_garages for g2 in efficient_garages if inline_condition(weight_sol[g1, g2] != None))) wds = create_data(table='weight_data_sparse', index={ 'key': ['i', 'j'], 'set': [filtered_set] }, columns=[weight_sol]) print(w.to_optmodel()) w.submit() print('Print Table:') print(p1.get_response()) print('Efficiency Data:') print(ed.get_response()) print('Weight Data (Dense):') print(wd.get_response()) print('Weight Data (Sparse):') print(wds.get_response()) if get_tables: return obj.get_value(), ed.get_response() else: return obj.get_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.expr_sum(storage_cost_per_unit * store[p, t] for p in PRODUCTS for t in PERIODS) revenue = so.expr_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.expr_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.expr_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.expr_sum(discount[j] * extractedPerYear[j] for j in YEARS) totalCost = so.expr_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.expr_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.expr_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): 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 = industry_data['init_stocks'] init_productive_capacity = industry_data['init_productive_capacity'] demand = industry_data['demand'] 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.expr_sum(production_coeff[i, j] * static_production[j] for j in INDUSTRIES) for i in INDUSTRIES), name='static_con') m.solve() print(so.get_value_table(static_production)) final_demand = so.get_value_table(static_production)['static_production'] 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(2, num_years + 3), lb=0, name='extra_capacity') productive_capacity = so.ImplicitVar( (init_productive_capacity[i] + so.expr_sum(extra_capacity[i, y] for y in range(2, year + 1)) for i in INDUSTRIES for year in range(1, num_years + 2)), name='productive_capacity') 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.expr_sum(production[i, year] for i in INDUSTRIES for year in [4, 5]) total_manpower = so.expr_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.expr_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.expr_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, productive_capacity) problem1.set_objective(total_productive_capacity, sense=so.MAX, name='total_productive_capacity') problem1.solve() so.pd.display_dense() print( so.get_value_table(production, stock, extra_capacity, productive_capacity).sort_index()) print(so.get_value_table(manpower_con.get_expressions())) # 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_value_table(production, stock, extra_capacity, productive_capacity).sort_index()) print(so.get_value_table(manpower_con.get_expressions())) # 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_value_table(production, stock, extra_capacity, productive_capacity).sort_index()) print(so.get_value_table(manpower_con.get_expressions())) return problem3.get_objective_value()