def test_knapsack(solver: str): p = [10, 13, 18, 31, 7, 15] w = [11, 15, 20, 35, 10, 33] c, I = 47, range(len(w)) m = Model("knapsack", solver_name=solver) x = [m.add_var(var_type=BINARY) for i in I] m.objective = maximize(xsum(p[i] * x[i] for i in I)) m += xsum(w[i] * x[i] for i in I) <= c, "cap" m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 41 m.constr_by_name("cap").rhs = 60 m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 51 # modifying objective function m.objective = m.objective + 10 * x[0] + 15 * x[1] assert abs(m.objective.expr[x[0]] - 20) <= 1e-10 assert abs(m.objective.expr[x[1]] - 28) <= 1e-10
def relax_constraints(cls, relaxed_model: mip.Model, slack_dict: dict) -> mip.Model: """this method creates a modification of the model `relaxed_model` where all the constraints in the slack_dict are modified in order to add the slack values to make the IIS disappear Args: relaxed_model (mip.Model): model to relax slack_dict (dict): pairs {constraint_name: slack_var.value} Returns: mip.Model: a modification of the original model where all the constraints are modified with the slack values """ for crt_name in slack_dict.keys(): crt_original = relaxed_model.constr_by_name(crt_name) relax_expr = crt_original.expr + slack_dict[crt_name] relaxed_model.add_constr( relax_expr, name=crt_original.name, priority=crt_original.priority ) relaxed_model.remove(crt_original) # remove constraint return relaxed_model
def test_knapsack(solver: str): p = [10, 13, 18, 31, 7, 15] w = [11, 15, 20, 35, 10, 33] c, I = 47, range(len(w)) m = Model('knapsack', solver_name=solver) x = [m.add_var(var_type=BINARY) for i in I] m.objective = maximize(xsum(p[i] * x[i] for i in I)) m += xsum(w[i] * x[i] for i in I) <= c, 'cap' m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 41 m.constr_by_name('cap').rhs = 60 m.optimize() assert m.status == OptimizationStatus.OPTIMAL assert round(m.objective_value) == 51
class InterfaceToSolver: """A wrapper for the mip model class, allows interaction with mip using pd.DataFrames.""" def __init__(self, solver_name='CBC'): self.variables = {} self.linear_mip_variables = {} self.solver_name = solver_name if solver_name == 'CBC': self.mip_model = Model("market", solver_name=CBC) self.linear_mip_model = Model("market", solver_name=CBC) elif solver_name == 'GUROBI': self.mip_model = Model("market", solver_name=GUROBI) self.linear_mip_model = Model("market", solver_name=GUROBI) else: raise ValueError("Solver '{}' not recognised.") self.mip_model.verbose = 0 self.mip_model.solver.set_mip_gap_abs(1e-10) self.mip_model.solver.set_mip_gap(1e-20) self.mip_model.lp_method = LP_Method.DUAL self.linear_mip_model.verbose = 0 self.linear_mip_model.solver.set_mip_gap_abs(1e-10) self.linear_mip_model.solver.set_mip_gap(1e-20) self.linear_mip_model.lp_method = LP_Method.DUAL def add_variables(self, decision_variables): """Add decision variables to the model. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1], ... 'lower_bound': [0.0, 0.0], ... 'upper_bound': [6.0, 1.0], ... 'type': ['continuous', 'binary']}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) The underlying mip_model should now have 2 variables. >>> print(si.mip_model.num_cols) 2 The first one should have the following properties. >>> print(si.mip_model.var_by_name('0').var_type) C >>> print(si.mip_model.var_by_name('0').lb) 0.0 >>> print(si.mip_model.var_by_name('0').ub) 6.0 The second one should have the following properties. >>> print(si.mip_model.var_by_name('1').var_type) B >>> print(si.mip_model.var_by_name('1').lb) 0.0 >>> print(si.mip_model.var_by_name('1').ub) 1.0 """ # Create a mapping between the nempy level names for variable types and the mip representation. variable_types = {'continuous': CONTINUOUS, 'binary': BINARY} # Add each variable to the mip model. for variable_id, lower_bound, upper_bound, variable_type in zip( list(decision_variables['variable_id']), list(decision_variables['lower_bound']), list(decision_variables['upper_bound']), list(decision_variables['type'])): self.variables[variable_id] = self.mip_model.add_var( lb=lower_bound, ub=upper_bound, var_type=variable_types[variable_type], name=str(variable_id)) self.linear_mip_variables[ variable_id] = self.linear_mip_model.add_var( lb=lower_bound, ub=upper_bound, var_type=variable_types[variable_type], name=str(variable_id)) def add_sos_type_2(self, sos_variables, sos_id_columns, position_column): """Add groups of special ordered sets of type 2 two the mip model. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 5.0, 5.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> sos_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'sos_id': ['A', 'A', 'A', 'B', 'B', 'B'], ... 'position': [0, 1, 2, 0, 1, 2]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_sos_type_2(sos_variables, 'sos_id', 'position') """ # Function that adds sets to mip model. def add_sos_vars(sos_group): self.mip_model.add_sos( list(zip(sos_group['vars'], sos_group[position_column])), 2) # For each variable_id get the variable object from the mip model sos_variables['vars'] = sos_variables['variable_id'].apply( lambda x: self.variables[x]) # Break up the sets based on their id and add them to the model separately. sos_variables.groupby(sos_id_columns).apply(add_sos_vars) # This is a hack to make sure mip knows there are binary constraints. self.mip_model.add_var(var_type=BINARY, obj=0.0) def add_sos_type_1(self, sos_variables): # Function that adds sets to mip model. def add_sos_vars(sos_group): self.mip_model.add_sos( list( zip(sos_group['vars'], [1.0 for i in range(len(sos_variables['vars']))])), 1) # For each variable_id get the variable object from the mip model sos_variables['vars'] = sos_variables['variable_id'].apply( lambda x: self.variables[x]) # Break up the sets based on their id and add them to the model separately. sos_variables.groupby('sos_id').apply(add_sos_vars) # This is a hack to make mip knows there are binary constraints. self.mip_model.add_var(var_type=BINARY, obj=0.0) def add_objective_function(self, objective_function): """Add the objective function to the mip model. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 5.0, 5.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> objective_function = pd.DataFrame({ ... 'variable_id': [0, 1, 3, 4, 5], ... 'cost': [1.0, 2.0, -1.0, 5.0, 0.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_objective_function(objective_function) >>> print(si.mip_model.var_by_name('0').obj) 1.0 >>> print(si.mip_model.var_by_name('5').obj) 0.0 """ objective_function = objective_function.sort_values('variable_id') objective_function = objective_function.set_index('variable_id') obj = minimize( xsum(objective_function['cost'][i] * self.variables[i] for i in list(objective_function.index))) self.mip_model.objective = obj self.linear_mip_model.objective = obj def add_constraints(self, constraints_lhs, constraints_type_and_rhs): """Add constraints to the mip model. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 10.0, 10.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> constraints_lhs = pd.DataFrame({ ... 'constraint_id': [1, 1, 2, 2], ... 'variable_id': [0, 1, 3, 4], ... 'coefficient': [1.0, 0.5, 1.0, 2.0]}) >>> constraints_type_and_rhs = pd.DataFrame({ ... 'constraint_id': [1, 2], ... 'type': ['<=', '='], ... 'rhs': [10.0, 20.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_constraints(constraints_lhs, constraints_type_and_rhs) >>> print(si.mip_model.constr_by_name('1')) 1: +1.0 0 +0.5 1 <= 10.0 >>> print(si.mip_model.constr_by_name('2')) 2: +1.0 3 +2.0 4 = 20.0 """ constraints_lhs = constraints_lhs.groupby( ['constraint_id', 'variable_id'], as_index=False).agg({'coefficient': 'sum'}) rows = constraints_lhs.groupby(['constraint_id'], as_index=False) # Make a dictionary so constraint rhs values can be accessed using the constraint id. rhs = dict( zip(constraints_type_and_rhs['constraint_id'], constraints_type_and_rhs['rhs'])) # Make a dictionary so constraint type can be accessed using the constraint id. enq_type = dict( zip(constraints_type_and_rhs['constraint_id'], constraints_type_and_rhs['type'])) var_ids = constraints_lhs['variable_id'].to_numpy() vars = np.asarray([ self.variables[k] if k in self.variables.keys() else None for k in range(0, max(var_ids) + 1) ]) coefficients = constraints_lhs['coefficient'].to_numpy() for row_id, row in rows.indices.items(): # Use the variable_ids to get mip variable objects present in the constraints lhs_variables = vars[var_ids[row]] # Use the positions of the non nan values to the lhs coefficients. lhs = coefficients[row] # Multiply and the variables by their coefficients and sum to create the lhs of the constraint. exp = lhs_variables * lhs exp = exp.tolist() exp = xsum(exp) # Add based on inequality type. if enq_type[row_id] == '<=': new_constraint = exp <= rhs[row_id] elif enq_type[row_id] == '>=': new_constraint = exp >= rhs[row_id] elif enq_type[row_id] == '=': new_constraint = exp == rhs[row_id] else: raise ValueError( "Constraint type not recognised should be one of '<=', '>=' or '='." ) self.mip_model.add_constr(new_constraint, name=str(row_id)) self.linear_mip_model.add_constr(new_constraint, name=str(row_id)) def optimize(self): """Optimize the mip model. If an optimal solution cannot be found and the investigate_infeasibility flag is set to True then remove constraints until a feasible solution is found. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 10.0, 10.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> constraints_lhs = pd.DataFrame({ ... 'constraint_id': [1, 1, 2, 2], ... 'variable_id': [0, 1, 3, 4], ... 'coefficient': [1.0, 0.5, 1.0, 2.0]}) >>> constraints_type_and_rhs = pd.DataFrame({ ... 'constraint_id': [1, 2], ... 'type': ['<=', '='], ... 'rhs': [10.0, 20.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_constraints(constraints_lhs, constraints_type_and_rhs) >>> si.optimize() >>> decision_variables['value'] = si.get_optimal_values_of_decision_variables(decision_variables) >>> print(decision_variables) variable_id lower_bound upper_bound type value 0 0 0.0 5.0 continuous 0.0 1 1 0.0 5.0 continuous 0.0 2 2 0.0 10.0 continuous 0.0 3 3 0.0 10.0 continuous 10.0 4 4 0.0 5.0 continuous 5.0 5 5 0.0 5.0 continuous 0.0 """ status = self.mip_model.optimize() if status != OptimizationStatus.OPTIMAL: # Attempt find constraint causing infeasibility. print('Model infeasible attempting to find problem constraint.') con_index = find_problem_constraint(self.mip_model) print( 'Couldn\'t find an optimal solution, but removing con {} fixed INFEASIBLITY' .format(con_index)) raise ValueError('Linear program infeasible') def get_optimal_values_of_decision_variables(self, variable_definitions): """Get the optimal values for each decision variable. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 10.0, 10.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> constraints_lhs = pd.DataFrame({ ... 'constraint_id': [1, 1, 2, 2], ... 'variable_id': [0, 1, 3, 4], ... 'coefficient': [1.0, 0.5, 1.0, 2.0]}) >>> constraints_type_and_rhs = pd.DataFrame({ ... 'constraint_id': [1, 2], ... 'type': ['<=', '='], ... 'rhs': [10.0, 20.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_constraints(constraints_lhs, constraints_type_and_rhs) >>> si.optimize() >>> decision_variables['value'] = si.get_optimal_values_of_decision_variables(decision_variables) >>> print(decision_variables) variable_id lower_bound upper_bound type value 0 0 0.0 5.0 continuous 0.0 1 1 0.0 5.0 continuous 0.0 2 2 0.0 10.0 continuous 0.0 3 3 0.0 10.0 continuous 10.0 4 4 0.0 5.0 continuous 5.0 5 5 0.0 5.0 continuous 0.0 """ values = variable_definitions['variable_id'].apply( lambda x: self.mip_model.var_by_name(str(x)).x, self.mip_model) return values def get_optimal_values_of_decision_variables_lin(self, variable_definitions): values = variable_definitions['variable_id'].apply( lambda x: self.linear_mip_model.var_by_name(str(x)).x, self.mip_model) return values def get_slack_in_constraints(self, constraints_type_and_rhs): """Get the slack values in each constraint. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 10.0, 10.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> constraints_lhs = pd.DataFrame({ ... 'constraint_id': [1, 1, 2, 2], ... 'variable_id': [0, 1, 3, 4], ... 'coefficient': [1.0, 0.5, 1.0, 2.0]}) >>> constraints_type_and_rhs = pd.DataFrame({ ... 'constraint_id': [1, 2], ... 'type': ['<=', '='], ... 'rhs': [10.0, 20.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_constraints(constraints_lhs, constraints_type_and_rhs) >>> si.optimize() >>> constraints_type_and_rhs['slack'] = si.get_slack_in_constraints(constraints_type_and_rhs) >>> print(constraints_type_and_rhs) constraint_id type rhs slack 0 1 <= 10.0 10.0 1 2 = 20.0 0.0 """ slack = constraints_type_and_rhs['constraint_id'].apply( lambda x: self.mip_model.constr_by_name(str(x)).slack, self.mip_model) return slack def price_constraints(self, constraint_ids_to_price): """For each constraint_id find the marginal value of the constraint. This is done by incrementing the constraint by a value of 1.0 and re-optimizing the model, the marginal cost of the constraint is increase in the objective function value between model runs. Examples -------- >>> decision_variables = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'lower_bound': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ... 'upper_bound': [5.0, 5.0, 10.0, 10.0, 5.0, 5.0], ... 'type': ['continuous', 'continuous', 'continuous', ... 'continuous', 'continuous', 'continuous']}) >>> objective_function = pd.DataFrame({ ... 'variable_id': [0, 1, 2, 3, 4, 5], ... 'cost': [1.0, 3.0, 10.0, 8.0, 9.0, 7.0]}) >>> constraints_lhs = pd.DataFrame({ ... 'constraint_id': [1, 1, 1, 1], ... 'variable_id': [0, 1, 3, 4], ... 'coefficient': [1.0, 1.0, 1.0, 1.0]}) >>> constraints_type_and_rhs = pd.DataFrame({ ... 'constraint_id': [1], ... 'type': ['='], ... 'rhs': [20.0]}) >>> si = InterfaceToSolver() >>> si.add_variables(decision_variables) >>> si.add_constraints(constraints_lhs, constraints_type_and_rhs) >>> si.add_objective_function(objective_function) >>> si.optimize() >>> si.linear_mip_model.optimize() <OptimizationStatus.OPTIMAL: 0> >>> prices = si.price_constraints([1]) >>> print(prices) {1: 8.0} >>> decision_variables['value'] = si.get_optimal_values_of_decision_variables(decision_variables) >>> print(decision_variables) variable_id lower_bound upper_bound type value 0 0 0.0 5.0 continuous 5.0 1 1 0.0 5.0 continuous 5.0 2 2 0.0 10.0 continuous 0.0 3 3 0.0 10.0 continuous 10.0 4 4 0.0 5.0 continuous 0.0 5 5 0.0 5.0 continuous 0.0 """ costs = {} for id in constraint_ids_to_price: costs[id] = self.linear_mip_model.constr_by_name(str(id)).pi return costs def update_rhs(self, constraint_id, violation_degree): constraint = self.linear_mip_model.constr_by_name(str(constraint_id)) constraint.rhs += violation_degree def update_variable_bounds(self, new_bounds): for variable_id, lb, ub in zip(new_bounds['variable_id'], new_bounds['lower_bound'], new_bounds['upper_bound']): self.mip_model.var_by_name(str(variable_id)).lb = lb self.mip_model.var_by_name(str(variable_id)).ub = ub def disable_variables(self, variables): for var_id in variables['variable_id']: var = self.linear_mip_model.var_by_name(str(var_id)) var.lb = 0.0 var.ub = 0.0
def dispatch(decision_variables, constraints_lhs, constraints_rhs_and_type, market_rhs_and_type, constraints_dynamic_rhs_and_type, objective_function): """Create and solve a linear program, returning prices of the market constraints and decision variables values. 0. Create the problem instance as a mip-python object instance 1. Create the decision variables 2. Create the objective function 3. Create the constraints 4. Solve the problem 5. Retrieve optimal values of each variable 6. Retrieve the shadow costs of market constraints :param decision_variables: dict of DataFrames each with the following columns variable_id: int lower_bound: float upper_bound: float type: str one of 'continuous', 'integer' or 'binary' :param constraints_lhs_coefficient: dict of DataFrames each with the following columns variable_id: int constraint_id: int coefficient: float :param constraints_rhs_and_type: dict of DataFrames each with the following columns constraint_id: int type: str one of '=', '<=', '>=' rhs: float :param market_constraints_lhs_coefficients: dict of DataFrames each with the following columns variable_id: int constraint_id: int coefficient: float :param market_rhs_and_type: dict of DataFrames each with the following columns constraint_id: int type: str one of '=', '<=', '>=' rhs: float :param objective_function: dict of DataFrames each with the following columns variable_id: int cost: float :return: decision_variables: dict of DataFrames each with the following columns variable_id: int lower_bound: float upper_bound: float type: str one of 'continuous', 'integer' or 'binary' value: float market_rhs_and_type: dict of DataFrames each with the following columns constraint_id: int type: str one of '=', '<=', '>=' rhs: float price: float """ # 0. Create the problem instance as a mip-python object instance prob = Model("market") prob.verbose = 0 sos_variables = None if 'interpolation_weights' in decision_variables.keys(): sos_variables = decision_variables['interpolation_weights'] # 1. Create the decision variables decision_variables = pd.concat(decision_variables) lp_variables = {} variable_types = {'continuous': CONTINUOUS, 'binary': BINARY} for variable_id, lower_bound, upper_bound, variable_type in zip( list(decision_variables['variable_id']), list(decision_variables['lower_bound']), list(decision_variables['upper_bound']), list(decision_variables['type'])): lp_variables[variable_id] = prob.add_var( lb=lower_bound, ub=upper_bound, var_type=variable_types[variable_type], name=str(variable_id)) def add_sos_vars(sos_group): prob.add_sos(list(zip(sos_group['vars'], sos_group['loss_segment'])), 2) if sos_variables is not None: sos_variables['vars'] = sos_variables['variable_id'].apply( lambda x: lp_variables[x]) sos_variables.groupby('interconnector').apply(add_sos_vars) # 2. Create the objective function if len(objective_function) > 0: objective_function = pd.concat(list(objective_function.values())) objective_function = objective_function.sort_values('variable_id') objective_function = objective_function.set_index('variable_id') prob.objective = minimize( xsum(objective_function['cost'][i] * lp_variables[i] for i in list(objective_function.index))) # 3. Create the constraints sos_constraints = [] if len(constraints_rhs_and_type) > 0: constraints_rhs_and_type = pd.concat( list(constraints_rhs_and_type.values())) else: constraints_rhs_and_type = pd.DataFrame({}) if len(constraints_dynamic_rhs_and_type) > 0: constraints_dynamic_rhs_and_type = pd.concat( list(constraints_dynamic_rhs_and_type.values())) constraints_dynamic_rhs_and_type['rhs'] = constraints_dynamic_rhs_and_type.\ apply(lambda x: lp_variables[x['rhs_variable_id']], axis=1) rhs_and_type = pd.concat([constraints_rhs_and_type] + list(market_rhs_and_type.values()) + [constraints_dynamic_rhs_and_type]) else: rhs_and_type = pd.concat([constraints_rhs_and_type] + list(market_rhs_and_type.values())) constraint_matrix = constraints_lhs.pivot('constraint_id', 'variable_id', 'coefficient') constraint_matrix = constraint_matrix.sort_index(axis=1) constraint_matrix = constraint_matrix.sort_index() column_ids = np.asarray(constraint_matrix.columns) row_ids = np.asarray(constraint_matrix.index) constraint_matrix_np = np.asarray(constraint_matrix) # if len(constraint_matrix.columns) != max(decision_variables['variable_id']) + 1: # raise check.ModelBuildError("Not all variables used in constraint matrix") rhs = dict(zip(rhs_and_type['constraint_id'], rhs_and_type['rhs'])) enq_type = dict(zip(rhs_and_type['constraint_id'], rhs_and_type['type'])) #var_list = np.asarray([lp_variables[k] for k in sorted(list(lp_variables))]) #t0 = time() for row, id in zip(constraint_matrix_np, row_ids): new_constraint = make_constraint(lp_variables, row, rhs[id], column_ids, enq_type[id]) prob.add_constr(new_constraint, name=str(id)) #print(time() - t0) # for row_index in sos_constraints: # sos_set = get_sos(var_list, constraint_matrix_np[row_index], column_ids) # prob.add_sos(list(zip(sos_set, [0 for var in sos_set])), 1) # 4. Solve the problem k = prob.add_var(var_type=BINARY, obj=1.0) #tc = 0 #t0 = time() status = prob.optimize() #tc += time() - t0 #print(tc) if status != OptimizationStatus.OPTIMAL: raise ValueError('Linear program infeasible') # 5. Retrieve optimal values of each variable #t0 = time() decision_variables = decision_variables.droplevel(1) decision_variables['lp_variables'] = [ lp_variables[i] for i in decision_variables['variable_id'] ] decision_variables['value'] = decision_variables['lp_variables'].apply( lambda x: x.x) decision_variables = decision_variables.drop('lp_variables', axis=1) split_decision_variables = {} for variable_group in decision_variables.index.unique(): split_decision_variables[variable_group] = \ decision_variables[decision_variables.index == variable_group].reset_index(drop=True) #print('get values {}'.format(time() - t0)) # 6. Retrieve the shadow costs of market constraints start_obj = prob.objective.x #initial_solution = [(v, v.x) for v in list(sos_variables['vars']) if v.x > 0.01] #print(initial_solution) #prob.start = initial_solution #prob.validate_mip_start() for constraint_group in market_rhs_and_type.keys(): cg = constraint_group market_rhs_and_type[cg]['price'] = 0.0 for id in list(market_rhs_and_type[cg]['constraint_id']): constraint = prob.constr_by_name(str(id)) constraint.rhs += 1.0 #t0 = time() prob.optimize() #tc += time() - t0 marginal_cost = prob.objective.x - start_obj market_rhs_and_type[cg].loc[ market_rhs_and_type[cg]['constraint_id'] == id, 'price'] = marginal_cost constraint.rhs -= 1.0 # market_rhs_and_type[constraint_group]['price'] = \ # market_rhs_and_type[constraint_group].apply(lambda x: get_price(x['constraint_id'], prob), axis=1) #print(tc) return split_decision_variables, market_rhs_and_type