def _get_constraint_map_dict(self, transBlock): if not hasattr(transBlock, "_constraintMap"): transBlock._constraintMap = { 'srcConstraints': ComponentMap(), 'transformedConstraints': ComponentMap() } return transBlock._constraintMap
def __init__(self, expression, improved_var_bounds=None): super(MCPP_visitor, self).__init__() self.mcpp = _MCPP_lib() so_file_version = self.mcpp.get_version() if six.PY3: so_file_version = so_file_version.decode("utf-8") if not so_file_version == __version__: raise MCPP_Error( "Shared object file version %s is out of date with MC++ interface version %s. " "Please rebuild the library." % (so_file_version, __version__)) self.missing_value_warnings = [] self.expr = expression vars = list(identify_variables(expression, include_fixed=False)) self.num_vars = len(vars) # Map expression variables to MC variables self.known_vars = ComponentMap() # Map expression variables to their index self.var_to_idx = ComponentMap() # Pre-register all variables inf = float('inf') for i, var in enumerate(vars): self.var_to_idx[var] = i # check if improved variable bound is provided if improved_var_bounds is not None: lb, ub = improved_var_bounds.get(var, (-inf, inf)) else: lb, ub = -inf, inf self.known_vars[var] = self.register_var(var, lb, ub) self.refs = None
def _build_equality_set(model): """Construct an equality set map. Maps all variables to the set of variables that are linked to them by equality. Mapping takes place using id(). That is, if you have x = y, then you would have id(x) -> ComponentSet([x, y]) and id(y) -> ComponentSet([x, y]) in the mapping. """ # Map of variables to their equality set (ComponentSet) eq_var_map = ComponentMap() # Loop through all the active constraints in the model for constraint in model.component_data_objects(ctype=Constraint, active=True, descend_into=True): eq_linked_vars = _get_equality_linked_variables(constraint) if not eq_linked_vars: continue # if we get an empty tuple, skip to next constraint. v1, v2 = eq_linked_vars set1 = eq_var_map.get(v1, ComponentSet((v1, v2))) set2 = eq_var_map.get(v2, (v2, )) # if set1 and set2 are equivalent, skip to next constraint. if set1 is set2: continue # add all elements of set2 to set 1 set1.update(set2) # Update all elements to point to set 1 for v in set1: eq_var_map[v] = set1 return eq_var_map
def _set_instance(self, model, kwds={}): if not isinstance(model, (Model, IBlock, Block, _BlockData)): msg = "The problem instance supplied to the {0} plugin " \ "'_presolve' method must be a Model or a Block".format(type(self)) raise ValueError(msg) self._pyomo_model = model self._symbolic_solver_labels = kwds.pop('symbolic_solver_labels', self._symbolic_solver_labels) self._skip_trivial_constraints = kwds.pop( 'skip_trivial_constraints', self._skip_trivial_constraints) self._output_fixed_variable_bounds = kwds.pop( 'output_fixed_variable_bounds', self._output_fixed_variable_bounds) self._pyomo_var_to_solver_var_map = ComponentMap() self._solver_var_to_pyomo_var_map = dict() self._pyomo_con_to_solver_con_map = dict() self._solver_con_to_pyomo_con_map = dict() self._vars_referenced_by_con = ComponentMap() self._vars_referenced_by_obj = ComponentSet() self._referenced_variables = ComponentMap() self._objective_label = None self._objective = None self._symbol_map = SymbolMap() if self._symbolic_solver_labels: self._labeler = TextLabeler() else: self._labeler = NumericLabeler('x')
def __init__(self, **kwds): # Suffix type information self._direction = None self._datatype = None self._rule = None # The suffix direction direction = kwds.pop('direction', Suffix.LOCAL) # The suffix datatype datatype = kwds.pop('datatype', Suffix.FLOAT) # The suffix construction rule # TODO: deprecate the use of 'rule' self._rule = kwds.pop('rule', None) self._rule = kwds.pop('initialize', self._rule) # Check that keyword values make sense (these function have # internal error checking). self.set_direction(direction) self.set_datatype(datatype) # Initialize base classes kwds.setdefault('ctype', Suffix) ActiveComponent.__init__(self, **kwds) ComponentMap.__init__(self) if self._rule is None: self.construct()
def __setstate__(self, state): """ This method must be defined for deepcopy/pickling because this class relies on component ids. """ ActiveComponent.__setstate__(self, state) ComponentMap.__setstate__(self, state)
def __init__(self, **kwds): kwds.setdefault('type', 'mosek_direct') DirectSolver.__init__(self, **kwds) self._pyomo_cone_to_solver_cone_map = dict() self._solver_cone_to_pyomo_cone_map = ComponentMap() self._name = None try: import mosek self._mosek = mosek self._mosek_env = self._mosek.Env() self._python_api_exists = True self._version = self._mosek_env.getversion() self._name = "MOSEK " + ".".join(str(i) for i in self._version) except ImportError: self._python_api_exists = False except Exception as e: print("Import of MOSEK failed - MOSEK message = " + str(e) + "\n") self._python_api_exists = False self._range_constraint = set() self._max_obj_degree = 2 self._max_constraint_degree = 2 self._termcode = None # Undefined capabilities default to None. self._capabilities.linear = True self._capabilities.quadratic_objective = True self._capabilities.quadratic_constraint = True self._capabilities.integer = True self._capabilities.conic_constraints = True self._capabilities.sos1 = False self._capabilities.sos2 = False
def calc_jacobians(solve_data, config): """ Generates a map of jacobians for the variables in the model This function generates a map of jacobians corresponding to the variables in the model and adds this ComponentMap to solve_data Parameters ---------- solve_data: MindtPy Data Container data container that holds solve-instance data config: MindtPy configurations contains the specific configurations for the algorithm """ # Map nonlinear_constraint --> Map( # variable --> jacobian of constraint wrt. variable) solve_data.jacobians = ComponentMap() if config.differentiate_mode == 'reverse_symbolic': mode = differentiate.Modes.reverse_symbolic elif config.differentiate_mode == 'sympy': mode = differentiate.Modes.sympy for c in solve_data.mip.MindtPy_utils.nonlinear_constraint_list: vars_in_constr = list(EXPR.identify_variables(c.body)) jac_list = differentiate(c.body, wrt_list=vars_in_constr, mode=mode) solve_data.jacobians[c] = ComponentMap( (var, jac_wrt_var) for var, jac_wrt_var in zip(vars_in_constr, jac_list))
def test_update(self): cmap = ComponentMap() self.assertEqual(len(cmap), 0) cmap.update(self._components) self.assertEqual(len(cmap), len(self._components)) for c, val in self._components: self.assertEqual(cmap[c], val)
def _estimate_M(self, expr, name): # If there are fixed variables here, unfix them for this calculation, # and we'll restore them at the end. fixed_vars = ComponentMap() if not self.assume_fixed_vars_permanent: for v in EXPR.identify_variables(expr, include_fixed=True): if v.fixed: fixed_vars[v] = value(v) v.fixed = False expr_lb, expr_ub = compute_bounds_on_expr(expr) if expr_lb is None or expr_ub is None: raise GDP_Error("Cannot estimate M for unbounded " "expressions.\n\t(found while processing " "constraint '%s'). Please specify a value of M " "or ensure all variables that appear in the " "constraint are bounded." % name) else: M = (expr_lb, expr_ub) # clean up if we unfixed things (fixed_vars is empty if we were assuming # fixed vars are fixed for life) for v, val in fixed_vars.items(): v.fix(val) return tuple(M)
def _set_instance(self, model, kwds={}): self._range_constraints = set() DirectOrPersistentSolver._set_instance(self, model, kwds) self._pyomo_con_to_solver_con_map = dict() self._solver_con_to_pyomo_con_map = ComponentMap() self._pyomo_var_to_solver_var_map = ComponentMap() self._solver_var_to_pyomo_var_map = ComponentMap() try: if model.name is not None: self._solver_model = self._gurobipy.Model(model.name) else: self._solver_model = self._gurobipy.Model() except Exception: e = sys.exc_info()[1] msg = ("Unable to create Gurobi model. " "Have you installed the Python " "bindings for Gurobi?\n\n\t"+ "Error message: {0}".format(e)) raise Exception(msg) self._add_block(model) for var, n_ref in self._referenced_variables.items(): if n_ref != 0: if var.fixed: if not self._output_fixed_variable_bounds: raise ValueError( "Encountered a fixed variable (%s) inside " "an active objective or constraint " "expression on model %s, which is usually " "indicative of a preprocessing error. Use " "the IO-option 'output_fixed_variable_bounds=True' " "to suppress this error and fix the variable " "by overwriting its bounds in the Gurobi instance." % (var.name, self._pyomo_model.name,))
def test_perfect_matching(self): model = make_gas_expansion_model() # These are the variables and constraints of the square, # nonsingular subsystem variables = [] variables.extend(model.P.values()) variables.extend(model.T[i] for i in model.streams if i != model.streams.first()) variables.extend(model.rho[i] for i in model.streams if i != model.streams.first()) variables.extend(model.F[i] for i in model.streams if i != model.streams.first()) constraints = list(model.component_data_objects(pyo.Constraint)) imat = get_numeric_incidence_matrix(variables, constraints) con_idx_map = ComponentMap((c, i) for i, c in enumerate(constraints)) n_var = len(variables) matching = maximum_matching(imat) matching = ComponentMap( (c, variables[matching[con_idx_map[c]]]) for c in constraints) values = ComponentSet(matching.values()) self.assertEqual(len(matching), n_var) self.assertEqual(len(values), n_var) # The subset of variables and equations we have identified # do not have a unique perfect matching. But we at least know # this much. self.assertIs(matching[model.ideal_gas[0]], model.P[0])
def _transform_constraintData(self, logical_constraint, new_varlists, transBlocks): # first find all the relevant BooleanVars and associate a binary (if # they don't have one already) for bool_vardata in identify_variables(logical_constraint.expr): if bool_vardata.ctype is BooleanVar: self._transform_boolean_varData(bool_vardata, new_varlists) # now create a transformation block on the constraint's parent block (if # we don't have one already) parent_block = logical_constraint.parent_block() xfrm_block = transBlocks.get(parent_block) if xfrm_block is None: xfrm_block = self._create_transformation_block(parent_block) transBlocks[parent_block] = xfrm_block new_constrlist = xfrm_block.transformed_constraints new_boolvarlist = xfrm_block.augmented_vars new_varlist = xfrm_block.augmented_vars_asbinary old_boolvarlist_length = len(new_boolvarlist) indicator_map = ComponentMap() cnf_statements = to_cnf(logical_constraint.body, new_boolvarlist, indicator_map) logical_constraint.deactivate() # Associate new Boolean vars to new binary variables num_new = len(new_boolvarlist) - old_boolvarlist_length list_o_vars = list(new_boolvarlist.values()) if num_new: for bool_vardata in list_o_vars[-num_new:]: new_binary_vardata = new_varlist.add() bool_vardata.associate_binary_var(new_binary_vardata) # Add constraints associated with each CNF statement for cnf_statement in cnf_statements: for linear_constraint in _cnf_to_linear_constraint_list( cnf_statement): new_constrlist.add(expr=linear_constraint) # Add bigM associated with special atoms # Note: this ad-hoc reformulation may be revisited for tightness in the # future. old_varlist_length = len(new_varlist) for indicator_var, special_atom in indicator_map.items(): for linear_constraint in _cnf_to_linear_constraint_list( special_atom, indicator_var, new_varlist): new_constrlist.add(expr=linear_constraint) # Previous step may have added auxiliary binaries. Associate augmented # Booleans to them. num_new = len(new_varlist) - old_varlist_length list_o_vars = list(new_varlist.values()) if num_new: for binary_vardata in list_o_vars[-num_new:]: new_bool_vardata = new_boolvarlist.add() new_bool_vardata.associate_binary_var(binary_vardata)
def __init__(self): self._config = IpoptConfig() self._solver_options = dict() self._writer = NLWriter() self._filename = None self._dual_sol = dict() self._primal_sol = ComponentMap() self._reduced_costs = ComponentMap()
def test_iter(self): cmap = ComponentMap() self.assertEqual(list(iter(cmap)), []) cmap.update(self._components) ids_seen = set() for c in cmap: ids_seen.add(id(c)) self.assertEqual(ids_seen, set(id(c) for c, val in self._components))
def test_items(self): cmap = ComponentMap(self._components) for x in cmap.items(): self.assertEqual(type(x), tuple) self.assertEqual(len(x), 2) self.assertEqual( sorted(cmap.items(), key=lambda _x: (id(_x[0]), _x[1])), sorted(self._components, key=lambda _x: (id(_x[0]), _x[1])))
def get_reduced_costs(self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None) -> Mapping[_GeneralVarData, float]: if vars_to_load is None: rc = ComponentMap(self._reduced_costs.values()) else: rc = ComponentMap() for v in vars_to_load: rc[v] = self._reduced_costs[id(v)][1] return rc
def test_with_solve(self): m = _make_simple_model() ipopt = pyo.SolverFactory("ipopt") n_scenario = 2 input_values = ComponentMap([ (m.v3, [1.3, 2.3]), (m.v4, [1.4, 2.4]), ]) _v1_val_1 = pyo.sqrt(3*1.4+1.3) _v1_val_2 = pyo.sqrt(3*2.4+2.3) _v2_val_1 = pyo.sqrt(2*1.4 - _v1_val_1) _v2_val_2 = pyo.sqrt(2*2.4 - _v1_val_2) output_values = ComponentMap([ (m.v1, [_v1_val_1, _v1_val_2]), (m.v2, [_v2_val_1, _v2_val_2]), ]) to_fix = [m.v3, m.v4] to_deactivate = [m.con1] to_reset = [m.v1, m.v2] # Initialize values so we don't fail due to bad initialization m.v1.set_value(1.0) m.v2.set_value(1.0) with ParamSweeper(n_scenario, input_values, output_values, to_fix=to_fix, to_deactivate=to_deactivate, to_reset=to_reset, ) as sweeper: self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertTrue(m.v3.fixed) self.assertTrue(m.v4.fixed) self.assertFalse(m.con1.active) self.assertTrue(m.con2.active) self.assertTrue(m.con3.active) for i, (inputs, outputs) in enumerate(sweeper): ipopt.solve(m) for var, val in inputs.items(): # These values should not have been altered. # I believe exact equality should be appropriate here. self.assertEqual(var.value, val) self.assertEqual(var.value, input_values[var][i]) for var, val in outputs.items(): self.assertAlmostEqual(var.value, val, delta=1e-8) self.assertAlmostEqual(var.value, output_values[var][i], delta=1e-8) # Values have been reset after exit. self.assertIs(m.v1.value, 1.0) self.assertIs(m.v2.value, 1.0) self.assertIs(m.v3.value, None) self.assertIs(m.v4.value, None)
def get_reduced_costs( self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None ) -> Mapping[_GeneralVarData, float]: if vars_to_load is None: return ComponentMap((k, v) for k, v in self._reduced_costs.items()) else: return ComponentMap( (v, self._reduced_costs[v]) for v in vars_to_load)
def test_with_exception(self): m = _make_simple_model() n_scenario = 2 input_values = ComponentMap([ (m.v3, [1.3, 2.3]), (m.v4, [1.4, 2.4]), ]) output_values = ComponentMap([ (m.v1, [1.1, 2.1]), (m.v2, [1.2, 2.2]), ]) to_fix = [m.v3, m.v4] to_deactivate = [m.con1] with self.assertRaises(RuntimeError): with ParamSweeper(2, input_values, output_values, to_fix=to_fix, to_deactivate=to_deactivate) as sweeper: self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertTrue(m.v3.fixed) self.assertTrue(m.v4.fixed) self.assertFalse(m.con1.active) self.assertTrue(m.con2.active) self.assertTrue(m.con3.active) for i, (inputs, outputs) in enumerate(sweeper): self.assertEqual(len(inputs), 2) self.assertEqual(len(outputs), 2) self.assertIn(m.v3, inputs) self.assertIn(m.v4, inputs) self.assertIn(m.v1, outputs) self.assertIn(m.v2, outputs) for var, val in inputs.items(): self.assertEqual(var.value, val) self.assertEqual(var.value, input_values[var][i]) for var, val in outputs.items(): self.assertEqual(val, output_values[var][i]) if i == 0: raise RuntimeError() # Values have been reset after exit. self.assertIs(m.v1.value, None) self.assertIs(m.v2.value, None) self.assertIs(m.v3.value, None) self.assertIs(m.v4.value, None) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertFalse(m.v4.fixed)
def __init__(self): self.pyomo2sympy = ComponentMap() self.parent_symbol = ComponentMap() self.sympy2pyomo = {} self.sympy2latex = {} self.used = {} self.i_var = 0 self.i_expr = 0 self.i_func = 0 self.i = 0
def __init__(self, **kwds): kwds['type'] = 'mosek' DirectSolver.__init__(self, **kwds) self._pyomo_var_to_solver_var_map = ComponentMap() self._solver_var_to_pyomo_var_map = ComponentMap() self._pyomo_con_to_solver_con_map = dict() self._solver_con_to_pyomo_con_map = ComponentMap() self._pyomo_cone_to_solver_cone_map = dict() self._solver_cone_to_pyomo_cone_map = ComponentMap() self._init()
def _estimate_M(self, expr, name): # If there are fixed variables here, unfix them for this calculation, # and we'll restore them at the end. fixed_vars = ComponentMap() if not self.assume_fixed_vars_permanent: for v in EXPR.identify_variables(expr, include_fixed=True): if v.fixed: fixed_vars[v] = value(v) v.fixed = False # Calculate a best guess at M repn = generate_standard_repn(expr, quadratic=False) M = [0, 0] if not repn.is_nonlinear(): if repn.constant is not None: for i in (0, 1): if M[i] is not None: M[i] += repn.constant for i, coef in enumerate(repn.linear_coefs or []): var = repn.linear_vars[i] bounds = (value(var.lb), value(var.ub)) for i in (0, 1): # reverse the bounds if the coefficient is negative if coef > 0: j = i else: j = 1 - i if bounds[i] is not None: M[j] += value(bounds[i]) * coef else: raise GDP_Error( "Cannot estimate M for " "expressions with unbounded variables." "\n\t(found unbounded var '%s' while processing " "constraint '%s')" % (var.name, name)) else: # expression is nonlinear. Try using `contrib.fbbt` to estimate. expr_lb, expr_ub = compute_bounds_on_expr(expr) if expr_lb is None or expr_ub is None: raise GDP_Error("Cannot estimate M for unbounded nonlinear " "expressions.\n\t(found while processing " "constraint '%s')" % name) else: M = (expr_lb, expr_ub) # clean up if we unfixed things (fixed_vars is empty if we were assuming # fixed vars are fixed for life) for v, val in fixed_vars.items(): v.fix(val) return tuple(M)
def __init__(self, **kwds): if 'type' not in kwds: kwds['type'] = 'gurobi_direct' super(GurobiDirect, self).__init__(**kwds) self._pyomo_var_to_solver_var_map = ComponentMap() self._solver_var_to_pyomo_var_map = ComponentMap() self._pyomo_con_to_solver_con_map = dict() self._solver_con_to_pyomo_con_map = ComponentMap() self._needs_updated = True # flag that indicates if solver_model.update() needs called before getting variable and constraint attributes self._callback = None self._callback_func = None self._name = None try: import gurobipy self._gurobipy = gurobipy self._python_api_exists = True self._version = self._gurobipy.gurobi.version() self._name = "Gurobi %s.%s%s" % self._version while len(self._version) < 4: self._version += (0, ) self._version = self._version[:4] self._version_major = self._version[0] except ImportError: self._python_api_exists = False except Exception as e: # other forms of exceptions can be thrown by the gurobi python # import. for example, a gurobipy.GurobiError exception is thrown # if all tokens for Gurobi are already in use. assuming, of # course, the license is a token license. unfortunately, you can't # import without a license, which means we can't test for the # exception above! logger.error("Import of gurobipy failed - gurobi message=%s\n" % (e, )) self._python_api_exists = False self._range_constraints = set() self._max_obj_degree = 2 self._max_constraint_degree = 2 # Note: Undefined capabilites default to None self._capabilities.linear = True self._capabilities.quadratic_objective = True self._capabilities.quadratic_constraint = True self._capabilities.integer = True self._capabilities.sos1 = True self._capabilities.sos2 = True # fix for compatibility with pre-5.0 Gurobi if self._python_api_exists and \ (self._version_major < 5): self._max_constraint_degree = 1 self._capabilities.quadratic_constraint = False
def _set_input(self, relaxation_side=RelaxationSide.BOTH, persistent_solvers=None, use_linear_relaxation=True, large_eval_tol=math.inf): self._partitions = ComponentMap() self._saved_partitions = list() BaseRelaxationData._set_input( self, relaxation_side=relaxation_side, persistent_solvers=persistent_solvers, use_linear_relaxation=use_linear_relaxation, large_eval_tol=large_eval_tol)
def _apply_to(self, instance, **kwds): self._generate_debug_messages = is_debug_set(logger) self.used_args = ComponentMap() # If everything was sure to go well, # this could be a dictionary. But if # someone messes up and gives us a Var # as a key in bigMargs, I need the error # not to be when I try to put it into # this map! try: self._apply_to_impl(instance, **kwds) finally: # same for our bookkeeping about what we used from bigM arg dict self.used_args.clear()
def determine_valid_values(block, discr_var_to_constrs_map, config): """Calculate valid values for each effectively discrete variable. We need the set of possible values for the effectively discrete variable in order to do the reformulations. Right now, we select a naive approach where we look for variables in the discreteness-inducing constraints. We then adjust their values and see if things are stil feasible. Based on their coefficient values, we can infer a set of allowable values for the effectively discrete variable. Args: block: The model or a disjunct on the model. """ possible_values = ComponentMap() for eff_discr_var, constrs in discr_var_to_constrs_map.items(): # get the superset of possible values by looking through the # constraints for constr in constrs: repn = generate_standard_repn(constr.body) var_coef = sum(coef for i, coef in enumerate(repn.linear_coefs) if repn.linear_vars[i] is eff_discr_var) const = -(repn.constant - constr.upper) / var_coef possible_vals = set((const, )) for i, var in enumerate(repn.linear_vars): if var is eff_discr_var: continue coef = -repn.linear_coefs[i] / var_coef if var.is_binary(): var_values = (0, coef) elif var.is_integer(): var_values = [v * coef for v in range(var.lb, var.ub + 1)] else: raise ValueError( '%s has unacceptable variable domain: %s' % (var.name, var.domain)) possible_vals = set( (v1 + v2 for v1 in possible_vals for v2 in var_values)) old_possible_vals = possible_values.get(eff_discr_var, None) if old_possible_vals is not None: possible_values[ eff_discr_var] = old_possible_vals & possible_vals else: possible_values[eff_discr_var] = possible_vals possible_values = prune_possible_values(block, possible_values, config) return possible_values
def test_getsetdelitem(self): cmap = ComponentMap() for c, val in self._components: self.assertTrue(c not in cmap) for c, val in self._components: cmap[c] = val self.assertEqual(cmap[c], val) self.assertEqual(cmap.get(c), val) del cmap[c] with self.assertRaises(KeyError): cmap[c] with self.assertRaises(KeyError): del cmap[c] self.assertEqual(cmap.get(c), None)
def _set_instance(self, model, kwds={}): self._range_constraints = set() super(MOSEKDirect, self)._set_instance(model, kwds) self._pyomo_cone_to_solver_cone_map = dict() self._solver_cone_to_pyomo_cone_map = ComponentMap() self._whichsol = getattr(self._mosek.soltype, kwds.pop('soltype', 'bas')) try: self._solver_model = self._mosek.Env().Task() except: err_msg = sys.exc_info()[1] logger.error("MOSEK task creation failed. " + "Reason: {}".format(err_msg)) raise self._add_block(model)
def __init__(self, component=None): # # These lines represent in-lining of the # following constructors: # - ComponentData # - NumericValue self._component = weakref_ref(component) if (component is not None) \ else None self.vars = {} self._arcs = [] self._sources = [] self._dests = [] self._rules = {} self._splitfracs = ComponentMap()