def test_find_badly_scaled_vars(): m = pyo.ConcreteModel() m.x = pyo.Var(initialize=1e6) m.y = pyo.Var(initialize=1e-8) m.z = pyo.Var(initialize=1e-20) m.b = pyo.Block() m.b.w = pyo.Var(initialize=1e10) a = [id(v) for v, sv in sc.badly_scaled_var_generator(m)] assert id(m.x) in a assert id(m.y) in a assert id(m.b.w) in a assert id(m.z) not in a m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.b.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.x] = 1e-6 m.scaling_factor[m.y] = 1e6 m.scaling_factor[m.z] = 1 m.b.scaling_factor[m.b.w] = 1e-5 a = [id(v) for v, sv in sc.badly_scaled_var_generator(m)] assert id(m.x) not in a assert id(m.y) not in a assert id(m.b.w) in a assert id(m.z) not in a
def subSolve(cap, PF,PTDF,line): # initialize sub sub = pyo.ConcreteModel() sub.N = pyo.Set(ordered=True, initialize=[0, 1, 2, 3]) # Set of the 4 nodes in our system sub.Pup = pyo.Var(sub.N,domain=pyo.NonNegativeReals) # Make 4 P-variables that represent increased power generation at each node sub.Pdown = pyo.Var(sub.N, domain=pyo.NonNegativeReals) # Make 4 P-variables that represent decreased power generation at each node sub.constraints = pyo.ConstraintList() # Define the list of all constraints # Define the objective function to be the sum of change in power production def ObjectiveFunction(sub): return sum(sub.Pup[i] + sub.Pdown[i] for i in sub.N) sub.obj = pyo.Objective(rule=ObjectiveFunction, sense=pyo.minimize) # Load balance constraint sub.constraints.add(sum(sub.Pup[i]-sub.Pdown[i] for i in sub.N) == 0) # Constraint for not violation of line 0-2 lhs=-cap - PF[0, 2] mid= sum((sub.Pup[i] - sub.Pdown[i])*PTDF[line,i] for i in sub.N) rhs= cap - PF[0, 2] sub.constraints.add(pyo.inequality(lhs,mid,rhs)) # Solve model opt = SolverFactory("gurobi") sub.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) sub.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT) results = opt.solve(sub, load_solutions=True) return sub
def receive_duals(self): """ Method sets solver suffix to extract information about dual variables from solver. Shadow prices (duals) and reduced costs (rc) are set as attributes of the model. """ # shadow prices self.dual = po.Suffix(direction=po.Suffix.IMPORT) # reduced costs self.rc = po.Suffix(direction=po.Suffix.IMPORT)
def _set_dae_suffixes_from_variables(m, variables, deriv_diff_map): """Write suffixes used by the solver to identify different variable types and associated derivative and differential variables. Args: m: model to search for variables and write suffixes to variables (list): List of time indexed variables at a specific time point deriv_diff_map (ComponentMap): Maps DerivativeVar data objects to differential variable data objects Returns: None """ # The dae_suffix provides the solver information about variables types # algebraic, differential, derivative, or time, see DaeVarTypes m.dae_suffix = pyo.Suffix( direction=pyo.Suffix.EXPORT, datatype=pyo.Suffix.INT, ) # The dae_link suffix provides the solver a link between the differential # and derivative variable, by assigning the pair a unique integer index. m.dae_link = pyo.Suffix( direction=pyo.Suffix.EXPORT, datatype=pyo.Suffix.INT, ) dae_var_link_index = 1 differential_vars = [] i = 0 for var in variables: if var in deriv_diff_map: deriv = var diffvar = deriv_diff_map[deriv] m.dae_suffix[diffvar] = int(DaeVarTypes.DIFFERENTIAL) m.dae_suffix[deriv] = int(DaeVarTypes.DERIVATIVE) m.dae_link[diffvar] = dae_var_link_index m.dae_link[deriv] = dae_var_link_index i += 1 dae_var_link_index += 1 if not diffvar.fixed: differential_vars.append(diffvar) else: raise RuntimeError( f"Problem cannot contain a fixed differential variable and " f"unfixed derivative. Consider either fixing the " f"corresponding derivative or adding a constraint for the " f"differential variable {diffvar} possibly using an " f"explicit time variable.") return differential_vars
def create_pyomo_model1(): m = pyo.ConcreteModel() m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) m.S = pyo.Set(initialize=[i + 1 for i in range(9)]) xb = dict() xb[1] = (-1, 1) xb[2] = (-np.inf, 2) xb[3] = (-3, np.inf) xb[4] = (-np.inf, np.inf) xb[5] = (-5, 5) xb[6] = (-np.inf, 6) xb[7] = (-7, np.inf) xb[8] = (-np.inf, np.inf) xb[9] = (-9, 9) m.x = pyo.Var(m.S, initialize=1.0, bounds=lambda m, i: xb[i]) cb = dict() cb[1] = (-1, 1) cb[2] = (2, 2) cb[3] = (-3, np.inf) cb[4] = (-np.inf, 4) cb[5] = (-5, 5) cb[6] = (-6, -6) cb[7] = (-7, np.inf) cb[8] = (-np.inf, 8) cb[9] = (-9, 9) def c_rule(m, i): return (cb[i][0], sum(i * j * m.x[j] for j in m.S), cb[i][1]) m.c = pyo.Constraint(m.S, rule=c_rule) for i in m.S: m.dual.set_value(m.c[i], i) m.obj = pyo.Objective(expr=sum(i * j * m.x[i] * m.x[j] for i in m.S for j in m.S)) # add scaling parameters for testing m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.obj] = 5 for i in m.S: m.scaling_factor[m.x[i]] = 2 * float(i) for i in m.S: m.scaling_factor[m.c[i]] = 3 * float(i) return m
def createPrimal(self): """Create the primal pyomo model. This is used to compute flows after interdiction. The interdiction is stored in arc_data.xbar.""" model = pe.ConcreteModel() # Tell pyomo to read in dual-variable information from the solver model.dual = pe.Suffix(direction=pe.Suffix.IMPORT) # Add the sets model.node_set = pe.Set(initialize=self.node_set) model.edge_set = pe.Set(initialize=self.arc_set, dimen=2) # Create the variables model.y = pe.Var(model.edge_set, domain=pe.NonNegativeReals) model.UnsatSupply = pe.Var(model.node_set, domain=pe.NonNegativeReals) model.UnsatDemand = pe.Var(model.node_set, domain=pe.NonNegativeReals) # Create the objective def obj_rule(model): return sum( (data['Cost'] + data['xbar'] * (2 * self.nCmax + 1)) * model.y[e] for e, data in self.arc_data.iterrows()) + sum( self.nCmax * (model.UnsatSupply[n] + model.UnsatDemand[n]) for n, data in self.node_data.iterrows()) model.OBJ = pe.Objective(rule=obj_rule, sense=pe.minimize) # Create the constraints, one for each node def flow_bal_rule(model, n): tmp = self.arc_data.reset_index() successors = tmp.ix[tmp.StartNode == n, 'EndNode'].values predecessors = tmp.ix[tmp.EndNode == n, 'StartNode'].values lhs = sum(model.y[(i, n)] for i in predecessors) - sum(model.y[(n, i)] for i in successors) imbalance = self.node_data['SupplyDemand'].get(n, 0) supply_node = int(imbalance < 0) demand_node = int(imbalance > 0) rhs = (imbalance + model.UnsatSupply[n] * (supply_node) - model.UnsatDemand[n] * (demand_node)) constr = (lhs == rhs) if isinstance(constr, bool): return pe.Constraint.Skip return constr model.FlowBalance = pe.Constraint(model.node_set, rule=flow_bal_rule) # Capacity constraints, one for each edge def capacity_rule(model, i, j): capacity = self.arc_data['Capacity'].get((i, j), -1) if capacity < 0: return pe.Constraint.Skip return model.y[(i, j)] <= capacity model.Capacity = pe.Constraint(model.edge_set, rule=capacity_rule) # Store the model self.primal = model
def __init__(self): # Initialize Model self.model = pyo.AbstractModel() self.model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) # Declare Parameters self.model.users = pyo.Param(within=pyo.NonNegativeIntegers) self.model.nodes = pyo.Param(within=pyo.NonNegativeIntegers) self.model.links = pyo.Param(within=pyo.NonNegativeIntegers) self.model.nodes_idx = pyo.Param(within=pyo.NonNegativeIntegers) self.model.operators = pyo.Param(within=pyo.NonNegativeIntegers) # Set initialization self.model.u = pyo.RangeSet(1, self.model.users) self.model.n = pyo.RangeSet(1, self.model.nodes) self.model.l = pyo.RangeSet(1, self.model.links) self.model.i = pyo.RangeSet(1, self.model.nodes_idx) self.model.o = pyo.RangeSet(1, self.model.operators) # Parameters self.model.origin = pyo.Param(self.model.l) self.model.destination = pyo.Param(self.model.l) self.model.t = pyo.Param(self.model.l) self.model.c = pyo.Param(self.model.l) self.model.w = pyo.Param(self.model.l) self.model.link_oper = pyo.Param(self.model.l) self.model.d = pyo.Param(self.model.u) self.model.O = pyo.Param(self.model.u) self.model.D = pyo.Param(self.model.u) self.model.utility = pyo.Param(self.model.u) self.model.N = pyo.Param(self.model.n) self.model.heads = pyo.Param(self.model.i, self.model.i, default=0) self.model.tails = pyo.Param(self.model.i, self.model.i, default=0)
def solve_with_gdp_opt(): m = MethanolModel().model for _d in m.component_data_objects(gdp.Disjunct, descend_into=True, active=True, sort=True): _d.BigM = pe.Suffix() for _c in _d.component_data_objects(pe.Constraint, descend_into=True, active=True, sort=True): lb, ub = compute_bounds_on_expr(_c.body) _d.BigM[_c] = max(abs(lb), abs(ub)) opt = pe.SolverFactory('gdpopt') opt.CONFIG.strategy = 'LOA' opt.CONFIG.mip_solver = 'gams' opt.CONFIG.nlp_solver = 'gams' opt.CONFIG.tee = True res = opt.solve(m) for d in m.component_data_objects(ctype=gdp.Disjunct, active=True, sort=True, descend_into=True): if d.indicator_var.value == 1: print(d.name) print(res) return m
def before_start_at_node(self, problem, relaxed_problem): # We need duals for this, so ask pyomo to import them. if not hasattr(relaxed_problem, 'dual'): relaxed_problem.dual = pe.Suffix(direction=pe.Suffix.IMPORT) lower_bounds = np.zeros(self._num_vars) upper_bounds = np.zeros(self._num_vars) domains = np.zeros(self._num_vars) var_idx_map = self._var_idx_map for var in self._variables: var_idx = var_idx_map[var] lower_bounds[var_idx] = var.lb upper_bounds[var_idx] = var.ub if var.has_lb() and var.has_ub(): domains[var_idx] = var.ub - var.lb else: domains[var_idx] = np.inf self._lower_bounds = lower_bounds self._upper_bounds = upper_bounds self._domains = domains self._agg_list_rescaled = self._rescale_coeffs_for_cut_selection( ) if self._nn_used else self._agg_list self._cut_round = 0
def createInstance(self, data): """ This method is used to instantiate the pyomo model @ In, data, dict, dictionary to initialize pyomo abstract model @ Out, model, pyomo.instance, instance of pyomo model """ model = self.createModel() if not model.is_constructed(): model = model.create_instance(data) # model.pprint() if self.externalConstraints: model = self.addExternalConstraints(model) model.dual = pyomo.Suffix(direction=pyomo.Suffix.IMPORT) # Default to disable some optional constraints if len(self.optionalConstraints) > 0 and self.uncertainties is not None: # if 'consistentConstraintI' in self.optionalConstraints: # model.consistentConstraint.deactivate() if 'consistentConstraintII' in self.optionalConstraints: model.consistentConstraintII.deactivate() logger.debug('Default to deactivate consistent constraint II') for optCon, decision in self.optionalConstraints.items(): if optCon == 'consistentConstraintI' and not decision: model.consistentConstraintI.deactivate() logger.debug('Deactivate consistent constraint I') if optCon == 'consistentConstraintII' and decision: model.consistentConstraintII.activate() logger.debug('Activate consistent constraint II') return model
def finalize_block_construction(self, pyomo_block): # set lower bounds on the variables pyomo_block.inputs['sv'].setlb(0) pyomo_block.inputs['ca'].setlb(0) pyomo_block.inputs['cb'].setlb(0) pyomo_block.inputs['cc'].setlb(0) pyomo_block.inputs['cd'].setlb(0) # initialize the variables pyomo_block.inputs['sv'].value = 1 pyomo_block.inputs['caf'].value = 1 pyomo_block.inputs['ca'].value = 1 pyomo_block.inputs['cb'].value = 1 pyomo_block.inputs['cc'].value = 1 pyomo_block.inputs['cd'].value = 1 pyomo_block.outputs['cb_ratio'].value = 1 m = pyomo_block.model() if not hasattr(m, 'scaling_factor'): # add the scaling factor suffix to the model if it is not already declared m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[pyomo_block.inputs['sv']] = 1.1 m.scaling_factor[pyomo_block.inputs['caf']] = 1.2 m.scaling_factor[pyomo_block.inputs['ca']] = 1.3 m.scaling_factor[pyomo_block.inputs['cb']] = 1.4 m.scaling_factor[pyomo_block.inputs['cc']] = 1.5 m.scaling_factor[pyomo_block.inputs['cd']] = 1.6 m.scaling_factor[pyomo_block.outputs['cb_ratio']] = 1.7
def test_scale_with_ignore_var_scale_constraint_scale(self): """Make sure the Jacobian from Pynumero matches expectation. This is mostly to ensure we understand the interface and catch if things change. """ m = self.model() m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.c1] = 1e-6 m.scaling_factor[m.x] = 1e-3 m.scaling_factor[m.y] = 1e-6 m.scaling_factor[m.z] = 1e-4 jac, jac_scaled, nlp = sc.constraint_autoscale_large_jac( m, ignore_variable_scaling=True) c1_row = nlp._condata_to_idx[m.c1] c2_row = nlp._condata_to_idx[m.c2] c3_row = nlp._condata_to_idx[m.c3] x_col = nlp._vardata_to_idx[m.x] y_col = nlp._vardata_to_idx[m.y] z_col = nlp._vardata_to_idx[m.z] assert jac_scaled[c1_row, x_col] == pytest.approx(-1) assert jac_scaled[c1_row, y_col] == pytest.approx(-1e-3) assert jac_scaled[c1_row, z_col] == pytest.approx(1e-6) assert m.scaling_factor[m.c1] == pytest.approx(1e-6) assert jac_scaled[c2_row, x_col] == pytest.approx(3) assert jac_scaled[c2_row, y_col] == pytest.approx(4) assert jac_scaled[c2_row, z_col] == pytest.approx(2) assert m.scaling_factor[m.c2] == pytest.approx(1) assert jac_scaled[c3_row, z_col] == pytest.approx(3e2) assert m.scaling_factor[m.c1] == pytest.approx(1e-6)
def set_scaling_factor(c, v, data_objects=True): """Set a scaling factor for a model component. This function creates the scaling_factor suffix if needed. Args: c: component to supply scaling factor for v: scaling factor Returns: None """ if isinstance(c, (float, int)): # property packages can return 0 for material balance terms on components # doesn't exist. This handles the case where you get a constant 0 and # need it's scale factor to scale the mass balance. return 1 try: suf = c.parent_block().scaling_factor except AttributeError: c.parent_block().scaling_factor = pyo.Suffix( direction=pyo.Suffix.EXPORT) suf = c.parent_block().scaling_factor suf[c] = v if data_objects and c.is_indexed(): for cdat in c.values(): suf[cdat] = v
def constraint_fd_autoscale(c, min_scale=1e-6, max_grad=100): """Autoscale constraints so that if there maximum partial derivative with respect to any variable is greater than max_grad at the current variable values, the method will attempt to assign a scaling factor to the constraint that makes the maximum derivative max_grad. The min_scale value provides a lower limit allowed for constraint scaling factors. If the caclulated scaling factor to make the maxium derivative max_grad is less than min_scale, min_scale is used instead. Derivatives are approximated using finite differnce. Args: c: constraint object max_grad: the largest derivative after scaling subject to min_scale min_scale: the minimum scale factor allowed Returns: None """ g, v = grad_fd(c, scaled=True) if not hasattr(c.parent_block(), "scaling_factor"): c.parent_block().scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) s0 = c.parent_block().scaling_factor.get(c, 1) maxg = max(map(abs,g)) ming = min(map(abs,g)) if maxg > max_grad: c.parent_block().scaling_factor[c] = s0*max_grad/maxg if c.parent_block().scaling_factor[c] < min_scale: c.parent_block().scaling_factor[c] = min_scale
def __init__(self, initial_variables_by_commodity, scheduled_trips): logging.getLogger('pyomo.core').setLevel(logging.ERROR) self.solver = pyo.opt.SolverFactory('cbc') self.results = "NotExecuted" self.model = pe.ConcreteModel('master_problem') indexes = [] self.cost_vector = {} for commodity in initial_variables_by_commodity.keys(): for index, var in enumerate( initial_variables_by_commodity[commodity]): var.index = (commodity, str(index)) indexes.append(var.index) self.cost_vector[var.index] = var.cost self.model.DK = indexes self.model.var_lambda = pe.Var(self.model.DK, domain=pe.NonNegativeReals) self.model.obj = pe.Objective(expr=sum(self.cost_vector[dk] * self.model.var_lambda[dk] for dk in self.model.DK), sense=pe.minimize) self.model.dual = pe.Suffix(direction=pe.Suffix.IMPORT) # self.model.rc = pe.Suffix(direction=pe.Suffix.IMPORT_EXPORT) self.set_partitioning_constraints(scheduled_trips, initial_variables_by_commodity) self.set_convexity_constraints(initial_variables_by_commodity)
def build_function_with_BM_suffix(): pyomo_model = build_function() bm_suffix = pyomo_model.component("BigM") if bm_suffix is None: bm_suffix = pyomo_model.BigM = pyo.Suffix() bm_suffix[None] = bigM return pyomo_model
def _calculate_scale_factors_from_nominal(m): """PRIVATE FUNCTION For variables and expressions, if a nominal value is provided calculate the scaling factor. Args: m (Block): a pyomo block to calculate scaling factors for Returns: None """ for c in m.component_data_objects((pyo.Var, pyo.Expression)): # Check for a scaling expression. If there is one, use it to calculate # a scaling factor otherwise use autoscaling. if not hasattr(c.parent_block(), "nominal_value"): continue # no scaling expression supplied elif c not in c.parent_block().nominal_value: continue # no scaling expression supplied if not hasattr(c.parent_block(), "scaling_factor"): # if there is no scaling_factor Suffix yet make one c.parent_block().scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) # Add scaling factor from nominal value of variables or expressions c.parent_block().scaling_factor[c] = 1/c.parent_block().nominal_value[c]
def test_duals_mip(): model = pyo.ConcreteModel() model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) model.x = pyo.Var([1, 2], domain=pyo.Boolean) model.y = pyo.Var([1, 2], domain=pyo.NonNegativeReals) # this problem is basically just two generators: # gen1 is cheap, but limited output # gen2 is more expensive model.OBJ = pyo.Objective(expr=2 * model.y[1] + 3 * model.y[2]) model.Constraint1 = pyo.Constraint(expr=model.y[1] <= 50 * model.x[1]) model.Constraint2 = pyo.Constraint(expr=model.y[2] <= 80 * model.x[2]) model.Constraint3 = pyo.Constraint(expr=model.y[1] + model.y[2] == 100) opt = SolverFactory("glpk") opt.solve(model) # make sure the solution is what we'd expect (both gen need to run) assert model.x[1].value == True assert model.x[2].value == True # fix binary variables model.x[1].fixed = True model.x[2].fixed = True opt.solve(model) # make sure the dual is non-zero (constraint is binding) assert model.dual[model.Constraint3] != 0
def create_and_solve_simple_model_with_battery(a, d, c_u, q_u, P_max): model = pyo.ConcreteModel(name="with battery") model.productors_index = range(len(a)) model.q = pyo.Var(model.productors_index, domain=pyo.NonNegativeReals) model.u = pyo.Var(domain=pyo.NonNegativeReals) obj_func = lambda model : (pyo.summation(a, model.q) + c_u*model.u) def equality(model, d): return pyo.summation(model.q) + model.u - d == 0 def prod_constraint(model, i): return model.q[i] <= P_max[i] def battery_constraint(model): return model.u <= q_u model.balance_constraint = pyo.Constraint(rule=lambda model : equality(model, d)) model.production_constraint = pyo.Constraint(model.productors_index, rule=prod_constraint) model.battery = pyo.Constraint(rule=battery_constraint) model.obj = pyo.Objective(rule=obj_func) # Export and import floating point data model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) solver = pyo.SolverFactory('gurobi') solver.solve(model, tee=True) results = [pyo.value(model.q[i]) for i in model.productors_index] return model
def test_param_updates(self, name: str, opt_class: Type[PersistentSolver]): opt = pe.SolverFactory('appsi_' + name) if not opt.available(exception_flag=False): raise unittest.SkipTest m = pe.ConcreteModel() m.x = pe.Var() m.y = pe.Var() m.a1 = pe.Param(mutable=True) m.a2 = pe.Param(mutable=True) m.b1 = pe.Param(mutable=True) m.b2 = pe.Param(mutable=True) m.obj = pe.Objective(expr=m.y) m.c1 = pe.Constraint(expr=(0, m.y - m.a1 * m.x - m.b1, None)) m.c2 = pe.Constraint(expr=(None, -m.y + m.a2 * m.x + m.b2, 0)) m.dual = pe.Suffix(direction=pe.Suffix.IMPORT) params_to_test = [(1, -1, 2, 1), (1, -2, 2, 1), (1, -1, 3, 1)] for (a1, a2, b1, b2) in params_to_test: m.a1.value = a1 m.a2.value = a2 m.b1.value = b1 m.b2.value = b2 res = opt.solve(m) pe.assert_optimal_termination(res) self.assertAlmostEqual(m.x.value, (b2 - b1) / (a1 - a2)) self.assertAlmostEqual(m.y.value, a1 * (b2 - b1) / (a1 - a2) + b1) self.assertAlmostEqual(m.dual[m.c1], (1 + a1 / (a2 - a1))) self.assertAlmostEqual(m.dual[m.c2], a1 / (a2 - a1))
def test_model1_with_scaling(self): m = create_model1() m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.o] = 1e-6 # scale the objective m.scaling_factor[m.c] = 2.0 # scale the equality constraint m.scaling_factor[m.d] = 3.0 # scale the inequality constraint m.scaling_factor[m.x[1]] = 4.0 # scale one of the x variables cynlp = CyIpoptNLP(PyomoNLP(m)) options={'nlp_scaling_method': 'user-scaling', 'output_file': '_cyipopt-scaling.log', 'file_print_level':10, 'max_iter': 0} solver = CyIpoptSolver(cynlp, options=options) x, info = solver.solve() with open('_cyipopt-scaling.log', 'r') as fd: solver_trace = fd.read() os.remove('_cyipopt-scaling.log') # check for the following strings in the log and then delete the log self.assertIn('nlp_scaling_method = user-scaling', solver_trace) self.assertIn('output_file = _cyipopt-scaling.log', solver_trace) self.assertIn('objective scaling factor = 1e-06', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) self.assertIn('d scaling provided', solver_trace) self.assertIn('DenseVector "x scaling vector" with 3 elements:', solver_trace) self.assertIn('x scaling vector[ 1]= 1.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 2]= 1.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 3]= 4.0000000000000000e+00', solver_trace) self.assertIn('DenseVector "c scaling vector" with 1 elements:', solver_trace) self.assertIn('c scaling vector[ 1]= 2.0000000000000000e+00', solver_trace) self.assertIn('DenseVector "d scaling vector" with 1 elements:', solver_trace) self.assertIn('d scaling vector[ 1]= 3.0000000000000000e+00', solver_trace)
def solve(n, B, F, costs, loads, transCap, P=[], dk_dp=[]): # initialize model model = pyo.ConcreteModel() model.N = pyo.Set(ordered=True, initialize=[i for i in range(n) ]) # Set of the n nodes in our system model.P = pyo.Var( model.N, domain=pyo.NonNegativeReals ) # Make 4 P-variables that represent power generated at each node model.delta = pyo.Var( model.N ) # Make 4 variables that represent the voltage angles at each node model.constraints = pyo.ConstraintList( ) # Define the list of all constraints # Define the objective function to be the sum of the costs of the generators times their respective power production def ObjectiveFunction(model): return sum(model.P[i] * costs[i] for i in model.N) model.obj = pyo.Objective(rule=ObjectiveFunction, sense=pyo.minimize) # Set slack bus angle to zero model.constraints.add(model.delta[3] == 0) # Define constraint P+L=B*Delta for i in model.N: lhs = model.P[i] + loads[i] rhs = sum(B[i][c] * model.delta[c] for c in model.N) model.constraints.add(lhs == rhs) # Define constraint -FLmax <= F*Delta <= FLmax for i in model.N: rhs = transCap[2 - i] lhs = -rhs mid = sum(F[i][c] * model.delta[c] for c in model.N) model.constraints.add(pyo.inequality(lhs, mid, rhs)) if len(P): model.constraints.add( sum((model.P[i] - P[i]) * dk_dp[i] for i in model.N) <= 0) # Solve model opt = SolverFactory("gurobi") model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) model.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT) opt.solve(model, load_solutions=True) return model
def LPQPkkta(): KKTsat = False Threshold = 1e-5 m = pyo.ConcreteModel() m.z1 = pyo.Var() m.z2 = pyo.Var() m.obj = pyo.Objective(expr=m.z1**2 + m.z2**2) m.c1 = pyo.Constraint(expr=m.z1 <= -3) m.c2 = pyo.Constraint(expr=m.z2 <= 4) m.c3 = pyo.Constraint(expr=4 * m.z1 + 3 * m.z2 <= 0) m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) res = pyo.SolverFactory('ipopt').solve(m) if res.solver.termination_condition is not TerminationCondition.optimal: KKTsat = False else: zOpt = np.array([m.z1(), m.z2()]) A = np.array([1, 0, 0, 1, 4, 3]).reshape((3, 2)) b = np.array([-3, 4, 0]) # ---------------------don't reshape here --------------------- u = [] for c in m.component_objects(pyo.Constraint, active=True): print("Constraint", c) for index in c: print(m.dual[c[index]]) u.append(m.dual[c[index]]) u = np.asarray(u) for i in range(len(u)): if u[i] < Threshold and u[i] > -Threshold: u[i] = 0 x = A @ zOpt - b flag_ineq = np.any(np.all(x <= Threshold) or np.all(x <= -Threshold)) # flag_ineq = np.any(np.all(A @ zOpt <= b + Threshold) or np.all(A@zOpt <= b -Threshold)) flag_dual = np.all(u >= 0) # flag_cs = np.all(np.multiply(u,x) < Threshold and np.all(np.multiply(u,x) > -Threshold)) flag_cs = np.all(np.multiply(u, x) < Threshold) and np.all( np.multiply(u, x) > -Threshold) # ------------------- pay attention here --------------------- grad_lagrangian = [2 * zOpt[0], 2 * zOpt[1]] + u.T @ A for i, y in enumerate(grad_lagrangian): if y < Threshold and y > -Threshold: grad_lagrangian[i] = 0 flag_grad = np.all(grad_lagrangian == 0) flags = [flag_ineq, flag_dual, flag_cs, flag_grad] flags = np.array(flags) if all(flags == 1): KKTsat = True else: KKTsat = False return KKTsat
def _create_primal(self): # Create the primal pyomo model. # # This is used to compute flows after interdiction. The interdiction # is stored in arc_data.xbar. model = pe.ConcreteModel() # Tell pyomo to read in dual-variable information from the solver: model.dual = pe.Suffix(direction=pe.Suffix.IMPORT) # Add the sets: model.node_set = pe.Set(initialize=self._topology.node_set) model.edge_set = pe.Set(initialize=self._topology.link_set, dimen=2) # Create the variables: model.y = pe.Var(model.edge_set, domain=pe.NonNegativeReals) model.UnsatSupply = pe.Var(model.node_set, domain=pe.NonNegativeReals) model.UnsatDemand = pe.Var(model.node_set, domain=pe.NonNegativeReals) # Create the objective: def obj_rule(model): return sum((data["risk"] + data["xbar"] * (2 * self._nCmax + 1)) * model.y[e] for e, data in self._topology.link_data.iterrows()) \ + sum(self._nCmax * (model.UnsatSupply[n] + model.UnsatDemand[n]) for n, data in self._topology.node_data.iterrows()) model.OBJ = pe.Objective(rule=obj_rule, sense=pe.minimize) # Create the constraints, one for each node: def flow_bal_rule(model, n): tmp = self._topology.link_data.reset_index() successors = tmp.loc[tmp.start_node == n, "end_node"].values predecessors = tmp.loc[tmp.end_node == n, "start_node"].values lhs = sum(model.y[(i, n)] for i in predecessors) \ - sum(model.y[(n, i)] for i in successors) imbalance = self._topology.node_data["supply_demand"].get(n, 0) supply_node = int(imbalance < 0) demand_node = int(imbalance > 0) rhs = (imbalance + model.UnsatSupply[n] * supply_node - model.UnsatDemand[n] * demand_node) constr = (lhs == rhs) if isinstance(constr, bool): return pe.Constraint.Skip return constr model.FlowBalance = pe.Constraint(model.node_set, rule=flow_bal_rule) # Capacity constraints, one for each edge: def capacity_rule(model, i, j): capacity = self._topology.link_data["capacity"].get((i, j), -1) if capacity < 0: return pe.Constraint.Skip return model.y[(i, j)] <= capacity model.Capacity = pe.Constraint(model.edge_set, rule=capacity_rule) # Return the model return model
def multicommodity_minimum_cost_flow(graphs: list, common_arcs: list, integer: bool): modelo = pe.ConcreteModel(name="MCFP") modelo.dual = pe.Suffix(direction=pe.Suffix.IMPORT) commodities_arcs = {(graph_k.commodity_name, str(arc[0])): arc for graph_k in graphs for arc in graph_k.arcs_cost_cap.items()} modelo.var_indexes = commodities_arcs.keys() modelo.var = pe.Var(modelo.var_indexes, within=pe.NonNegativeIntegers if integer else pe.NonNegativeReals) def objetivo(m): return sum(commodities_arcs[index][1][0] * m.var[index] for index in modelo.var_indexes) modelo.obj = pe.Objective(rule=objetivo, sense=pe.minimize) commodities_nodes = [(commodity, node) for commodity in graphs for node in commodity.nodes_demands.items()] def conserva_fluxo(m, index): commodity, node = commodities_nodes[index] from_i = [str(arc) for arc in commodity.arcs_cost_cap.keys() if arc.origin == node[0]] to_i = [str(arc) for arc in commodity.arcs_cost_cap.keys() if arc.destination == node[0]] return sum(m.var[(commodity.commodity_name, v)] for v in from_i) - sum( m.var[(commodity.commodity_name, v)] for v in to_i) == node[1] modelo.commodities_nodes_indexes = range(len(commodities_nodes)) modelo.flow_conservation = pe.Constraint(modelo.commodities_nodes_indexes, rule=conserva_fluxo) def capacidades_conjuntas(m, index): soma = sum(m.var[(commodity.commodity_name, str(common_arcs[index]))] for commodity in graphs if (commodity.commodity_name, str(common_arcs[index])) in modelo.var_indexes) return soma <= common_arcs[index].capacity modelo.capacidade_conjunta_arco = pe.Constraint(range(len(common_arcs)), rule=capacidades_conjuntas) def lower_bound_conjuntas(m, index): soma = sum(m.var[(commodity.commodity_name, str(common_arcs[index]))] for commodity in graphs if (commodity.commodity_name, str(common_arcs[index])) in modelo.var_indexes) return common_arcs[index].lower_bound <= soma modelo.lower_bound_conjunta_arco = pe.Constraint(range(len(common_arcs)), rule=lower_bound_conjuntas) def capacidades(m, commodity, arc): var_index = (commodity, arc) return m.var[var_index] <= commodities_arcs.get(var_index)[1][1] modelo.capacidade = pe.Constraint(modelo.var_indexes, rule=capacidades) solver = pyomo.opt.SolverFactory('cbc') results = solver.solve(modelo) modelo.display() # modelo.pprint() print(results.solver.status) for dk in modelo.var_indexes: if modelo.var[dk].value > 0: print(dk, modelo.var[dk].value) print(modelo.obj())
def create_and_solve_lmp( self, options: Options, sced_instance: OperationsModel, ) -> OperationsModel: lmp_sced_instance = sced_instance.clone() # In case of demand shortfall, the price skyrockets, so we threshold the value. system = lmp_sced_instance.data['system'] for system_key, threshold_value in self._p.get_attrs_to_price_option( options): if threshold_value is not None and ( (system_key not in system) or (system[system_key] > threshold_value)): system[system_key] = threshold_value if self._last_sced_pyo_model is None: self._ptdf_manager.mark_active(lmp_sced_instance) slack_type = _slack_type_to_egret_slack_type[ options.sced_slack_type] network_type = _network_type_to_egret_network_constraints[ options.sced_network_type] pyo_model = create_sced_uc_model( lmp_sced_instance, relaxed=True, ptdf_options=self._ptdf_manager.lmpsced_ptdf_options, PTDF_matrix_dict=self._ptdf_manager.PTDF_matrix_dict, slack_type=slack_type, network_constraints=network_type) pyo_solver = self._sced_solver self._p._zero_out_costs(pyo_model, self._hours_in_objective) else: pyo_model = self._last_sced_pyo_model pyo_solver = self._last_sced_pyo_solver self._transform_for_lmp(pyo_model, pyo_solver, lmp_sced_instance) pyo_model.dual = pe.Suffix(direction=pe.Suffix.IMPORT) try: lmp_sced_results, _, _ = self._p.call_solver( pyo_solver, pyo_model, options, options.sced_solver_options, relaxed=True, set_instance=(self._last_sced_pyo_model is None)) except: print("Some issue with LMP SCED, writing instance") quickstart_uc_filename = options.output_directory + os.sep + "FAILED_LMP_SCED.json" lmp_sced_instance.write(quickstart_uc_filename) print(f"Problematic LMP SCED written to {quickstart_uc_filename}") raise return lmp_sced_results
def m2(self): m = pyo.ConcreteModel() m.factor = pyo.Param(initialize=1.0e-16, mutable=True) m.x = pyo.Var(bounds=(0.5 * m.factor, 1.5 * m.factor), initialize=m.factor) m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.x] = pyo.value(1. / m.factor) m.o = pyo.Objective(expr=m.x / m.factor) return m
def create_and_solve_lmp( self, sced_instance: OperationsModel, options: Options, ) -> OperationsModel: lmp_sced_instance = sced_instance.clone() # In case of demand shortfall, the price skyrockets, so we threshold the value. if 'load_mismatch_cost' not in lmp_sced_instance.data['system'] or \ lmp_sced_instance.data['system']['load_mismatch_cost'] > \ options.price_threshold: lmp_sced_instance.data['system'][ 'load_mismatch_cost'] = options.price_threshold # In case of reserve shortfall, the price skyrockets, so we threshold the value. if 'reserve_shortfall_cost' not in lmp_sced_instance.data['system'] or \ lmp_sced_instance.data['system']['reserve_shortfall_cost'] > \ options.reserve_price_threshold: lmp_sced_instance.data['system']['reserve_shortfall_cost'] = \ options.reserve_price_threshold if self._last_sced_pyo_model is None: self._ptdf_manager.mark_active(lmp_sced_instance) pyo_model = create_sced_uc_model( lmp_sced_instance, relaxed=True, ptdf_options=self._ptdf_manager.lmpsced_ptdf_options, PTDF_matrix_dict=self._ptdf_manager.PTDF_matrix_dict) pyo_solver = self._sced_solver self._p._zero_out_costs(pyo_model, self._hours_in_objective) else: pyo_model = self._last_sced_pyo_model pyo_solver = self._last_sced_pyo_solver self._transform_for_lmp(pyo_model, pyo_solver, lmp_sced_instance) pyo_model.dual = pe.Suffix(direction=pe.Suffix.IMPORT) try: lmp_sced_results, _, _ = self._p.call_solver( pyo_solver, pyo_model, options, options.sced_solver_options, relaxed=True, set_instance=(self._last_sced_pyo_model is None)) except: print("Some issue with LMP SCED, writing instance") quickstart_uc_filename = options.output_directory + os.sep + "FAILED_LMP_SCED.json" lmp_sced_instance.write(quickstart_uc_filename) print(f"Problematic LMP SCED written to {quickstart_uc_filename}") raise self._attach_fake_pyomo_objects(lmp_sced_results) return lmp_sced_results
def _employee(linear=False, **kwargs): """ Factory method for the Employee scheduling problem. Parameters ---------- linear : :py:obj:`bool`, optional Determines whether decision variables will be Reals (True) or Integer (False). **kwargs : optional if any given, returns pyomo concrete model instead, with these passed into pyomo's `create_instance`. Notes ----- Simple model: minimize # of workers employed to meet shift requirements """ def _obj_expression(model): """Objective Expression: Minimizing Number of Workers""" return pyo.summation(model.NumWorkers) def _period_reqs_constraint_rule(model, p): """Constraints for having enough workers per period""" # Get index of current period ind = model.Periods.ord(p) num_periods = len(model.Periods) # Get effective periods based on ShiftLength - loops back effective_periods = [ model.Periods[((ind - 1 - shift) % num_periods) + 1] for shift in range(model.ShiftLength.value) ] # Sum up how many workers are working this period my_sum = sum( [model.NumWorkers[period] for period in effective_periods]) return my_sum >= model.PeriodReqs[p] # Create the abstract model & dual suffix model = pyo.AbstractModel() model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) # Define sets/params that are always used model.Periods = pyo.Set(ordered=True) model.ShiftLength = pyo.Param() # num periods a worker works in a row model.PeriodReqs = pyo.Param(model.Periods) # Define decision variables model.NumWorkers = pyo.Var( model.Periods, within=pyo.NonNegativeReals if linear else pyo.NonNegativeIntegers) # Define objective & constraints model.OBJ = pyo.Objective(rule=_obj_expression, sense=pyo.minimize) model.PeriodReqsConstraint = pyo.Constraint( model.Periods, rule=_period_reqs_constraint_rule) # Check if returning concrete or abstract model if kwargs: return model.create_instance(**kwargs) else: return model
def solve(localsolver, solvername, instance, logfilename='logfile_loadobjective.log', get_suffixes=True, solver_options=None, outputfile=None): # Wall time - clock starts. starttime_modelsolve = time.time() if localsolver: solver = SolverFactory(solvername) # Configure with solver options # file_print_levels (Output Level-of-Detail): # 4 for just # of iterations, and final objective, infeas,etc. values # 6 for summary information about all iterations, but not variable values # 8 for variable values at all iterations # 10 for all iterations if solver_options: for k, v in solver_options.items(): solver.options[k] = v solver.options['OF_mumps_mem_percent'] = '5' # "OF_" prefix signals to Pyomo to create a temporary options file solver.options['OF_output_file'] = outputfile if get_suffixes: instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) instance.ipopt_zL_out = pyo.Suffix(direction=pyo.Suffix.IMPORT) instance.ipopt_zU_out = pyo.Suffix(direction=pyo.Suffix.IMPORT) setattr(instance, 'lambda', pyo.Suffix(direction=pyo.Suffix.IMPORT)) # use setattr because 'lambda' is reserved keyword try: results = solver.solve(instance, tee=True, symbolic_solver_labels=True, keepfiles=False, logfile=logfilename) except pyutilib.common._exceptions.ApplicationError: traceback.print_exc() return None else: opt = SolverFactory("cbc") solver_manager = SolverManagerFactory('neos') instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) instance.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT) instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) # self.instance.slack = pyo.Suffix(direction=pyo.Suffix.IMPORT) opt.options["display_width"] = 170 opt.options["display"] = '_varname, _var.rc, _var.lb, _var, _var.ub, _var.slack' results = solver_manager.solve(instance, opt=opt, solver=solvername, logfile=logfilename) results.write() # Wall time - clock stops. _endtime_modelsolve = time.time() timefor_modelsolve = _endtime_modelsolve - starttime_modelsolve logger.info('*solving done* <- it took %f seconds>' % timefor_modelsolve) feasible = check_whether_feasible(instance, results) return instance, results, feasible