def _add_indexed_member(self, ndx): new_conval = _ConnectorValue(create_name(self.name,ndx)) new_conval.component = weakref.ref(self) new_conval.index = ndx self._conval[ndx] = new_conval
def _create_using(self, model, **kwds): """ Eliminate inequality constraints. Required arguments: model The model to transform. Optional keyword arguments: slack_root The root name of auxiliary slack variables. Default is 'auxiliary_slack'. excess_root The root name of auxiliary slack variables. Default is 'auxiliary_excess'. lb_suffix The suffix applied to converted upper bound constraints Default is '_lower_bound'. ub_suffix The suffix applied to converted lower bound constraints Default is '_upper_bound'. """ # Optional naming schemes slack_suffix = kwds.pop("slack_suffix", "slack") excess_suffix = kwds.pop("excess_suffix", "excess") lb_suffix = kwds.pop("lb_suffix", "lb") ub_suffix = kwds.pop("ub_suffix", "ub") equality = model.clone() components = collectAbstractComponents(equality) # # Fix all Constraint objects # for con_name in components["Constraint"]: con = equality.__getattribute__(con_name) # # Get all _ConstraintData objects # # We need to get the keys ahead of time because we are modifying # con._data on-the-fly. # indices = con._data.keys() for (ndx, cdata) in [(ndx, con._data[ndx]) for ndx in indices]: qualified_con_name = create_name(con_name, ndx) # Do nothing with equality constraints if cdata.equality: continue # Add an excess variable if the lower bound exists if cdata.lower is not None: # Make the excess variable excess_name = "%s_%s" % (qualified_con_name, excess_suffix) equality.__setattr__(excess_name, Var(within=NonNegativeReals)) # Make a new lower bound constraint lb_name = "%s_%s" % (create_name("", ndx), lb_suffix) excess = equality.__getattribute__(excess_name) new_expr = (cdata.lower == cdata.body - excess) con.add(lb_name, new_expr) # Add a slack variable if the lower bound exists if cdata.upper is not None: # Make the excess variable slack_name = "%s_%s" % (qualified_con_name, slack_suffix) equality.__setattr__(slack_name, Var(within=NonNegativeReals)) # Make a new upper bound constraint ub_name = "%s_%s" % (create_name("", ndx), ub_suffix) slack = equality.__getattribute__(slack_name) new_expr = (cdata.upper == cdata.body + slack) con.add(ub_name, new_expr) # Since we explicitly `continue` for equality constraints, we # can safely remove the old _ConstraintData object del con._data[ndx] return equality.create()
def _create_using(self, model, **kwds): """ Force all variables to lie in the nonnegative orthant. Required arguments: model The model to transform. Optional keyword arguments: pos_suffix The suffix applied to the 'positive' component of converted variables. Default is '_plus'. neg_suffix The suffix applied to the 'positive' component of converted variables. Default is '_minus'. """ # # Optional naming schemes # pos_suffix = kwds.pop("pos_suffix", "_plus") neg_suffix = kwds.pop("neg_suffix", "_minus") # # We first perform an abstract problem transformation. Then, if model # data is available, we instantiate the new model. If not, we construct # a mapping that can later be used to populate the new model. # nonneg = model.clone() components = collectAbstractComponents(nonneg) # Map from variable base names to a {index, rule} map constraint_rules = {} # Map from variable base names to a rule defining the domains for that # variable domain_rules = {} # Map from variable base names to its set of indices var_indices = {} # Map from fully qualified variable names to replacement expressions. # For now, it is actually a map from a variable name to a closure that # must later be evaulated with a model containing the replacement # variables. var_map = {} # # Get the constraints that enforce the bounds and domains of each # variable # for var_name in components["Var"]: var = nonneg.__getattribute__(var_name) # Individual bounds and domains orig_bounds = {} orig_domain = {} # New indices indices = set() # Map from constraint names to a constraint rule. constraints = {} # Map from variable indices to a domain domains = {} for ndx in var: # Fully qualified variable name vname = create_name(str(var_name), ndx) # We convert each index to a string to avoid difficult issues # regarding appending a suffix to tuples. # # If the index is None, this casts the index to a string, # which doesn't match up with how Pyomo treats None indices # internally. Replace with "" to be consistent. if ndx is None: v_ndx = "" else: v_ndx = str(ndx) # Get the variable bounds lb = value(var[ndx].lb) ub = value(var[ndx].ub) orig_bounds[ndx] = (lb, ub) # Get the variable domain if var[ndx].domain is not None: orig_domain[ndx] = var[ndx].domain else: orig_domain[ndx] = var.domain # Determine the replacement expression. Either a new single # variable with the same attributes, or a sum of two new # variables. # # If both the bounds and domain allow for negative values, # replace the variable with the sum of nonnegative ones. bounds_neg = (orig_bounds[ndx] == (None, None) or orig_bounds[ndx][0] is None or orig_bounds[ndx][0] < 0) domain_neg = (orig_domain[ndx] is None or orig_domain[ndx].bounds()[0] is None or orig_domain[ndx].bounds()[0] < 0) if bounds_neg and domain_neg: # Make two new variables. posVarSuffix = "%s%s" % (v_ndx, pos_suffix) negVarSuffix = "%s%s" % (v_ndx, neg_suffix) new_indices = (posVarSuffix, negVarSuffix) # Replace the original variable with a sum expression expr_dict = {posVarSuffix: 1, negVarSuffix: -1} else: # Add the new index. Lie if is 'None', since Pyomo treats # 'None' specially as a key. # # More lies: don't let a blank index exist. Replace it with # '_'. I don't actually have a justification for this other # than that allowing "" as a key will eventually almost # certainly lead to a strange bug. if v_ndx is None: t_ndx = "None" elif v_ndx == "": t_ndx = "_" else: t_ndx = v_ndx new_indices = (t_ndx, ) # Replace the original variable with a sum expression expr_dict = {t_ndx: 1} # Add the new indices for x in new_indices: indices.add(x) # Replace the original variable with an expression var_map[vname] = partial(self.sumRule, var_name, expr_dict) # Enforce bounds as constraints if orig_bounds[ndx] != (None, None): cname = "%s_%s" % (vname, "bounds") tmp = orig_bounds[ndx] constraints[cname] = partial(self.boundsConstraintRule, tmp[0], tmp[1], var_name, expr_dict) # Enforce the bounds of the domain as constraints if orig_domain[ndx] != None: cname = "%s_%s" % (vname, "domain_bounds") tmp = orig_domain[ndx].bounds() constraints[cname] = partial(self.boundsConstraintRule, tmp[0], tmp[1], var_name, expr_dict) # Domain will either be NonNegativeReals, NonNegativeIntegers, # or Binary. We consider Binary because some solvers may # optimize over binary variables. if var[ndx].is_continuous(): for x in new_indices: domains[x] = NonNegativeReals elif var[ndx].is_binary(): for x in new_indices: domains[x] = Binary elif var[ndx].is_integer(): for x in new_indices: domains[x] = NonNegativeIntegers else: logger.warning("Warning: domain '%s' not recognized, " "defaulting to 'NonNegativeReals'" % (var.domain, )) for x in new_indices: domains[x] = NonNegativeReals constraint_rules[var_name] = constraints domain_rules[var_name] = partial(self.exprMapRule, domains) var_indices[var_name] = indices # Remove all existing variables. toRemove = [] for (attr_name, attr) in nonneg.__dict__.items(): if isinstance(attr, Var): toRemove.append(attr_name) for attr_name in toRemove: nonneg.__delattr__(attr_name) # Add the sets defining the variables, then the variables for (k, v) in var_indices.items(): sname = "%s_indices" % k nonneg.__setattr__(sname, Set(initialize=v)) nonneg.__setattr__( k, Var(nonneg.__getattribute__(sname), domain=domain_rules[k], bounds=(0, None))) # Construct the model to get the variables and their indices # recognized in the model ##nonneg = nonneg.create() # Safe to evaluate the modifiedVars mapping for var in var_map: var_map[var] = var_map[var](nonneg) # Map from constraint base names to maps from indices to expressions constraintExprs = {} # # Convert all modified variables in all constraints in the original # problem # for conName in components["Constraint"]: con = nonneg.__getattribute__(conName) # Map from constraint indices to a corrected expression exprMap = {} for (ndx, cdata) in con._data.items(): lower = _walk_expr(cdata.lower, var_map) body = _walk_expr(cdata.body, var_map) upper = _walk_expr(cdata.upper, var_map) # Lie if ndx is None. Pyomo treats 'None' indices specially. if ndx is None: ndx = "None" # Cast indices to strings, otherwise tuples ruin everything exprMap[str(ndx)] = (lower, body, upper) # Add to list of expression maps constraintExprs[conName] = exprMap # Map from constraint base names to maps from indices to expressions objectiveExprs = {} # # Convert all modified variables in all objectives in the original # problem # for objName in components["Objective"]: obj = nonneg.__getattribute__(objName) # Map from objective indices to a corrected expression exprMap = {} for (ndx, odata) in obj._data.items(): exprMap[ndx] = _walk_expr(odata.expr, var_map) # Add to list of expression maps objectiveExprs[objName] = exprMap # Make the modified original constraints for (conName, ruleMap) in constraintExprs.items(): # Make the set of indices sname = conName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _con = Constraint(nonneg.__getattribute__(sname), rule=partial(self.exprMapRule, ruleMap)) nonneg.__setattr__(conName, _con) _con.construct() # Make the bounds constraints for (varName, ruleMap) in constraint_rules.items(): conName = varName + "_constraints" # Make the set of indices sname = conName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _con = Constraint(nonneg.__getattribute__(sname), rule=partial(self.delayedExprMapRule, ruleMap)) nonneg.__setattr__(conName, _con) _con.construct() # Make the objectives for (objName, ruleMap) in objectiveExprs.items(): # Make the set of indices sname = objName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _obj = Objective(nonneg.__getattribute__(sname), rule=partial(self.exprMapRule, ruleMap)) nonneg.__setattr__(objName, _obj) _obj.construct() return nonneg
def _create_using(self, model, **kwds): """ Force all variables to lie in the nonnegative orthant. Required arguments: model The model to transform. Optional keyword arguments: pos_suffix The suffix applied to the 'positive' component of converted variables. Default is '_plus'. neg_suffix The suffix applied to the 'positive' component of converted variables. Default is '_minus'. """ # # Optional naming schemes # pos_suffix = kwds.pop("pos_suffix", "_plus") neg_suffix = kwds.pop("neg_suffix", "_minus") # # We first perform an abstract problem transformation. Then, if model # data is available, we instantiate the new model. If not, we construct # a mapping that can later be used to populate the new model. # nonneg = model.clone() components = collectAbstractComponents(nonneg) # Map from variable base names to a {index, rule} map constraint_rules = {} # Map from variable base names to a rule defining the domains for that # variable domain_rules = {} # Map from variable base names to its set of indices var_indices = {} # Map from fully qualified variable names to replacement expressions. # For now, it is actually a map from a variable name to a closure that # must later be evaulated with a model containing the replacement # variables. var_map = {} # # Get the constraints that enforce the bounds and domains of each # variable # for var_name in components["Var"]: var = nonneg.__getattribute__(var_name) # Individual bounds and domains orig_bounds = {} orig_domain = {} # New indices indices = set() # Map from constraint names to a constraint rule. constraints = {} # Map from variable indices to a domain domains = {} for ndx in var: # Fully qualified variable name vname = create_name(str(var_name), ndx) # We convert each index to a string to avoid difficult issues # regarding appending a suffix to tuples. # # If the index is None, this casts the index to a string, # which doesn't match up with how Pyomo treats None indices # internally. Replace with "" to be consistent. if ndx is None: v_ndx = "" else: v_ndx = str(ndx) # Get the variable bounds lb = var[ndx].lb ub = var[ndx].ub if lb is not None: lb = value(lb) if ub is not None: ub = value(ub) orig_bounds[ndx] = (lb, ub) # Get the variable domain if var[ndx].domain is not None: orig_domain[ndx] = var[ndx].domain else: orig_domain[ndx] = var.domain # Determine the replacement expression. Either a new single # variable with the same attributes, or a sum of two new # variables. # # If both the bounds and domain allow for negative values, # replace the variable with the sum of nonnegative ones. bounds_neg = (orig_bounds[ndx] == (None, None) or orig_bounds[ndx][0] is None or orig_bounds[ndx][0] < 0) domain_neg = (orig_domain[ndx] is None or orig_domain[ndx].bounds()[0] is None or orig_domain[ndx].bounds()[0] < 0) if bounds_neg and domain_neg: # Make two new variables. posVarSuffix = "%s%s" % (v_ndx, pos_suffix) negVarSuffix = "%s%s" % (v_ndx, neg_suffix) new_indices = (posVarSuffix, negVarSuffix) # Replace the original variable with a sum expression expr_dict = {posVarSuffix: 1, negVarSuffix: -1} else: # Add the new index. Lie if is 'None', since Pyomo treats # 'None' specially as a key. # # More lies: don't let a blank index exist. Replace it with # '_'. I don't actually have a justification for this other # than that allowing "" as a key will eventually almost # certainly lead to a strange bug. if v_ndx is None: t_ndx = "None" elif v_ndx == "": t_ndx = "_" else: t_ndx = v_ndx new_indices = (t_ndx,) # Replace the original variable with a sum expression expr_dict = {t_ndx: 1} # Add the new indices for x in new_indices: indices.add(x) # Replace the original variable with an expression var_map[vname] = partial(self.sumRule, var_name, expr_dict) # Enforce bounds as constraints if orig_bounds[ndx] != (None, None): cname = "%s_%s" % (vname, "bounds") tmp = orig_bounds[ndx] constraints[cname] = partial( self.boundsConstraintRule, tmp[0], tmp[1], var_name, expr_dict) # Enforce the bounds of the domain as constraints if orig_domain[ndx] != None: cname = "%s_%s" % (vname, "domain_bounds") tmp = orig_domain[ndx].bounds() constraints[cname] = partial( self.boundsConstraintRule, tmp[0], tmp[1], var_name, expr_dict) # Domain will either be NonNegativeReals, NonNegativeIntegers, # or Binary. We consider Binary because some solvers may # optimize over binary variables. if isinstance(orig_domain[ndx], RealSet): for x in new_indices: domains[x] = NonNegativeReals elif isinstance(orig_domain[ndx], IntegerSet): for x in new_indices: domains[x] = NonNegativeIntegers elif isinstance(orig_domain[ndx], BooleanSet): for x in new_indices: domains[x] = Binary else: print ("Warning: domain '%s' not recognized, " + \ "defaulting to 'Reals'") % (str(var.domain)) for x in new_indices: domains[x] = Reals constraint_rules[var_name] = constraints domain_rules[var_name] = partial(self.exprMapRule, domains) var_indices[var_name] = indices # Remove all existing variables. toRemove = [] for (attr_name, attr) in nonneg.__dict__.items(): if isinstance(attr, Var): toRemove.append(attr_name) for attr_name in toRemove: nonneg.__delattr__(attr_name) # Add the sets defining the variables, then the variables for (k, v) in var_indices.items(): sname = "%s_indices" % k nonneg.__setattr__(sname, Set(initialize=v)) nonneg.__setattr__(k, Var(nonneg.__getattribute__(sname), domain = domain_rules[k], bounds = (0, None))) # Construct the model to get the variables and their indices # recognized in the model ##nonneg = nonneg.create() # Safe to evaluate the modifiedVars mapping for var in var_map: var_map[var] = var_map[var](nonneg) # Map from constraint base names to maps from indices to expressions constraintExprs = {} # # Convert all modified variables in all constraints in the original # problem # for conName in components["Constraint"]: con = nonneg.__getattribute__(conName) # Map from constraint indices to a corrected expression exprMap = {} for (ndx, cdata) in con._data.items(): lower = self._walk_expr(cdata.lower, var_map) body = self._walk_expr(cdata.body, var_map) upper = self._walk_expr(cdata.upper, var_map) # Lie if ndx is None. Pyomo treats 'None' indices specially. if ndx is None: ndx = "None" # Cast indices to strings, otherwise tuples ruin everything exprMap[str(ndx)] = (lower, body, upper) # Add to list of expression maps constraintExprs[conName] = exprMap # Map from constraint base names to maps from indices to expressions objectiveExprs = {} # # Convert all modified variables in all objectives in the original # problem # for objName in components["Objective"]: obj = nonneg.__getattribute__(objName) # Map from objective indices to a corrected expression exprMap = {} for (ndx, odata) in obj._data.items(): exprMap[ndx] = self._walk_expr(odata.expr, var_map) # Add to list of expression maps objectiveExprs[objName] = exprMap # Make the modified original constraints for (conName, ruleMap) in constraintExprs.items(): # Make the set of indices sname = conName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _con = Constraint( nonneg.__getattribute__(sname), rule=partial(self.exprMapRule, ruleMap) ) nonneg.__setattr__(conName, _con) _con.construct() # Make the bounds constraints for (varName, ruleMap) in constraint_rules.items(): conName = varName + "_constraints" # Make the set of indices sname = conName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _con = Constraint(nonneg.__getattribute__(sname), rule=partial(self.delayedExprMapRule, ruleMap)) nonneg.__setattr__(conName, _con) _con.construct() # Make the objectives for (objName, ruleMap) in objectiveExprs.items(): # Make the set of indices sname = objName + "_indices" _set = Set(initialize=ruleMap.keys()) nonneg.__setattr__(sname, _set) _set.construct() # Define the constraint _obj = Objective(nonneg.__getattribute__(sname), rule=partial(self.exprMapRule, ruleMap)) nonneg.__setattr__(objName, _obj) _obj.construct() return nonneg
def _add_indexed_member(self, ndx): new_conval = _ConnectorValue(create_name(self.local_name,ndx)) new_conval.component = weakref.ref(self) new_conval.index = ndx self._conval[ndx] = new_conval