def clone_without_expression_components(expr, substitute): ans = [EXPR.clone_expression(expr, substitute=substitute)] _stack = [ (ans, 0, 1) ] while _stack: _argList, _idx, _len = _stack.pop() while _idx < _len: _sub = _argList[_idx] _idx += 1 if type(_sub) in native_types: pass elif _sub.is_expression(): _stack.append(( _argList, _idx, _len )) if not isinstance(_sub, EXPR._ExpressionBase): _argList[_idx-1] = EXPR.clone_expression( _sub._args[0], substitute=substitute ) elif type(_sub) is coopr3._ProductExpression: if _sub._denominator: _stack.append( (_sub._denominator, 0, len(_sub._denominator)) ) _argList = _sub._numerator else: _argList = _sub._args # HACK: As we may have to replace arguments, if the # _args is a tuple, then we will convert it to a # list. if type(_argList) is tuple: _argList = _sub._args = list(_argList) _idx = 0 _len = len(_argList) return ans[0]
def differentiate(expr, wrt=None, wrt_list=None): if not _sympy_available: raise RuntimeError( "The sympy module is not available. " "Cannot perform automatic symbolic differentiation.") if not (( wrt is None ) ^ ( wrt_list is None )): raise ValueError( "differentiate(): Must specify exactly one of wrt and wrt_list") if wrt is not None: wrt_list = [ wrt ] else: # Copy the list because we will normalize things in place below wrt_list = list(wrt_list) pyomo_vars = list(EXPR.identify_variables(expr)) sympy_vars = [sympy.var('x%s'% i) for i in range(len(pyomo_vars))] sympy2pyomo = dict( zip(sympy_vars, pyomo_vars) ) pyomo2sympy = dict( (id(pyomo_vars[i]), sympy_vars[i]) for i in range(len(pyomo_vars)) ) ans = [] for i, target in enumerate(wrt_list): if target.__class__ is not tuple: wrt_list[i] = target = (target,) mismatch_target = False for var in target: if id(var) not in pyomo2sympy: mismatch_target = True break wrt_list[i] = tuple( pyomo2sympy.get(id(var),None) for var in target ) ans.append(0 if mismatch_target else None) # If there is nothing to do, do nothing if all(i is not None for i in ans): return ans if wrt is None else ans[0] tmp_expr = EXPR.clone_expression( expr, substitute=pyomo2sympy ) tmp_expr = _map_intrinsic_functions(tmp_expr, sympy2pyomo) tmp_expr = str(tmp_expr) sympy_expr = sympy.sympify( tmp_expr, locals=dict((str(x), x) for x in sympy_vars) ) for i, target in enumerate(wrt_list): if ans[i] is None: sympy_ans = sympy_expr.diff(*target) ans[i] = _map_sympy2pyomo(sympy_ans, sympy2pyomo) return ans if wrt is None else ans[0]
def differentiate(expr, wrt=None, wrt_list=None): if not _sympy_available: raise RuntimeError( "The sympy module is not available. " "Cannot perform automatic symbolic differentiation.") if not ((wrt is None) ^ (wrt_list is None)): raise ValueError( "differentiate(): Must specify exactly one of wrt and wrt_list") if wrt is not None: wrt_list = [wrt] else: # Copy the list because we will normalize things in place below wrt_list = list(wrt_list) pyomo_vars = list(EXPR.identify_variables(expr)) sympy_vars = [sympy.var('x%s' % i) for i in range(len(pyomo_vars))] sympy2pyomo = dict(zip(sympy_vars, pyomo_vars)) pyomo2sympy = dict( (id(pyomo_vars[i]), sympy_vars[i]) for i in range(len(pyomo_vars))) ans = [] for i, target in enumerate(wrt_list): if target.__class__ is not tuple: wrt_list[i] = target = (target, ) mismatch_target = False for var in target: if id(var) not in pyomo2sympy: mismatch_target = True break wrt_list[i] = tuple(pyomo2sympy.get(id(var), None) for var in target) ans.append(0 if mismatch_target else None) # If there is nothing to do, do nothing if all(i is not None for i in ans): return ans if wrt is None else ans[0] tmp_expr = EXPR.clone_expression(expr, substitute=pyomo2sympy) tmp_expr = _map_intrinsic_functions(tmp_expr, sympy2pyomo) tmp_expr = str(tmp_expr) sympy_expr = sympy.sympify(tmp_expr, locals=dict((str(x), x) for x in sympy_vars)) for i, target in enumerate(wrt_list): if ans[i] is None: sympy_ans = sympy_expr.diff(*target) ans[i] = _map_sympy2pyomo(sympy_ans, sympy2pyomo) return ans if wrt is None else ans[0]
def _apply_to(self, instance, **kwds): if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug("Calling ConnectorExpander") connectorsFound = False for c in instance.component_data_objects(Connector): connectorsFound = True break if not connectorsFound: return if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug(" Connectors found!") # # At this point, there are connectors in the model, so we must # look for constraints that involve connectors and expand them. # connector_types = set([SimpleConnector, _ConnectorData]) constraint_list = [] connector_list = [] matched_connectors = {} found = dict() for constraint in instance.component_data_objects(Constraint): for c in expr.identify_variables( constraint.body, include_potentially_variable=True): if c.__class__ in connector_types: found[id(c)] = c if not found: continue # Note that it is important to copy the set of found # connectors, since the matching routine below will # manipulate sets in place. found_this_constraint = dict(found) constraint_list.append( (constraint, found_this_constraint) ) # Find all the connectors that are used in the constraint, # so we know which connectors to validate against each # other. Note that the validation must be transitive (that # is, if con1 has a & b and con2 has b & c, then a,b, and c # must all validate against each other. for cId, c in iteritems(found_this_constraint): if cId in matched_connectors: oldSet = matched_connectors[cId] found.update( oldSet ) for _cId in oldSet: matched_connectors[_cId] = found else: connector_list.append(c) matched_connectors[cId] = found # Reset found back to empty (this is more efficient as the # bulk of the constraints in the model will not have # connectors - so if we did this at the top of the loop, we # would spend a lot of time clearing empty sets found = {} # Validate all connector sets and expand the empty ones known_conn_sets = {} for connector in connector_list: conn_set = matched_connectors[id(connector)] if id(conn_set) in known_conn_sets: continue known_conn_sets[id(conn_set)] \ = self._validate_and_expand_connector_set(conn_set) # Expand each constraint for constraint, conn_set in constraint_list: cList = ConstraintList() constraint.parent_block().add_component( '%s.expanded' % ( constraint.local_name, ), cList ) connId = next(iterkeys(conn_set)) ref = known_conn_sets[id(matched_connectors[connId])] for k,v in sorted(iteritems(ref)): if v[1] >= 0: _iter = v[0] else: _iter = (v[0],) for idx in _iter: substitution = {} for c in itervalues(conn_set): if v[1] >= 0: new_v = c.vars[k][idx] elif k in c.aggregators: new_v = c.vars[k].add() else: new_v = c.vars[k] substitution[id(c)] = new_v cList.add(( constraint.lower, expr.clone_expression( constraint.body, substitution ), constraint.upper )) constraint.deactivate() # Now, go back and implement VarList aggregators for conn in connector_list: block = conn.parent_block() for var, aggregator in iteritems(conn.aggregators): c = Constraint(expr=aggregator(block, conn.vars[var])) block.add_component( '%s.%s.aggregate' % (conn.local_name, var), c )
def _apply_to(self, instance, **kwds): if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug("Calling ConnectorExpander") connectorsFound = False for c in instance.component_data_objects(Connector): connectorsFound = True break if not connectorsFound: return if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug(" Connectors found!") # # At this point, there are connectors in the model, so we must # look for constraints that involve connectors and expand them. # connector_types = set([SimpleConnector, _ConnectorData]) constraint_list = [] connector_list = [] matched_connectors = {} found = dict() for constraint in instance.component_data_objects(Constraint): for c in expr.identify_variables( constraint.body, include_potentially_variable=True): if c.__class__ in connector_types: found[id(c)] = c if not found: continue # Note that it is important to copy the set of found # connectors, since the matching routine below will # manipulate sets in place. found_this_constraint = dict(found) constraint_list.append((constraint, found_this_constraint)) # Find all the connectors that are used in the constraint, # so we know which connectors to validate against each # other. Note that the validation must be transitive (that # is, if con1 has a & b and con2 has b & c, then a,b, and c # must all validate against each other. for cId, c in iteritems(found_this_constraint): if cId in matched_connectors: oldSet = matched_connectors[cId] found.update(oldSet) for _cId in oldSet: matched_connectors[_cId] = found else: connector_list.append(c) matched_connectors[cId] = found # Reset found back to empty (this is more efficient as the # bulk of the constraints in the model will not have # connectors - so if we did this at the top of the loop, we # would spend a lot of time clearing empty sets found = {} # Validate all connector sets and expand the empty ones known_conn_sets = {} for connector in connector_list: conn_set = matched_connectors[id(connector)] if id(conn_set) in known_conn_sets: continue known_conn_sets[id(conn_set)] \ = self._validate_and_expand_connector_set(conn_set) # Expand each constraint for constraint, conn_set in constraint_list: cList = ConstraintList() constraint.parent_block().add_component( '%s.expanded' % (constraint.local_name, ), cList) connId = next(iterkeys(conn_set)) ref = known_conn_sets[id(matched_connectors[connId])] for k, v in sorted(iteritems(ref)): if v[1] >= 0: _iter = v[0] else: _iter = (v[0], ) for idx in _iter: substitution = {} for c in itervalues(conn_set): if v[1] >= 0: new_v = c.vars[k][idx] elif k in c.aggregators: new_v = c.vars[k].add() else: new_v = c.vars[k] substitution[id(c)] = new_v cList.add((constraint.lower, expr.clone_expression(constraint.body, substitution), constraint.upper)) constraint.deactivate() # Now, go back and implement VarList aggregators for conn in connector_list: block = conn.parent_block() for var, aggregator in iteritems(conn.aggregators): c = Constraint(expr=aggregator(block, conn.vars[var])) block.add_component('%s.%s.aggregate' % (conn.local_name, var), c)
def to_standard_form(self): # # Add auxilliary variables and constraints that ensure # a monotone transformation of general complementary constraints to # the form: # l1 <= v1 <= u1 OR l2 <= v2 <= u2 # # Note that this transformation creates more variables and constraints # than are strictly necessary. However, we don't have a complete list of # the variables used in a model's complementarity conditions when adding # a single condition, so we add additional variables. # # This has the form: # # e: l1 <= expression <= l2 # v: l3 <= var <= l4 # # where exactly two of l1, l2, l3 and l4 are finite, and with the # equality constraint: # # c: v == expression # _e1 = self._canonical_expression(EXPR.clone_expression(self._args[0])) _e2 = self._canonical_expression(EXPR.clone_expression(self._args[1])) if len(_e1) == 2: # Ignore _e2; _e1 is an equality constraint self.c = Constraint(expr=_e1) return if len(_e2) == 2: # Ignore _e1; _e2 is an equality constraint self.c = Constraint(expr=_e2) return # if (_e1[0] is None) + (_e1[2] is None) + (_e2[0] is None) + ( _e2[2] is None) != 2: raise RuntimeError( "Complementarity condition %s must have exactly two finite bounds" % self.name) # if _e1[0] is None and _e1[2] is None: # Only e2 will be an unconstrained expression _e1, _e2 = _e2, _e1 # if _e2[0] is None and _e2[2] is None: self.c = Constraint(expr=(None, _e2[1], None)) self.c._type = 3 elif _e2[2] is None: self.c = Constraint(expr=_e2[0] <= _e2[1]) self.c._type = 1 elif _e2[0] is None: self.c = Constraint(expr=-_e2[2] <= -_e2[1]) self.c._type = 1 # if not _e1[0] is None and not _e1[2] is None: if not _e1[0].is_constant(): raise RuntimeError( "Cannot express a complementarity problem of the form L < v < U _|_ g(x) where L is not a constant value" ) if not _e1[2].is_constant(): raise RuntimeError( "Cannot express a complementarity problem of the form L < v < U _|_ g(x) where U is not a constant value" ) self.v = Var(bounds=(_e1[0], _e1[2])) self.ve = Constraint(expr=self.v == _e1[1]) elif _e1[2] is None: self.v = Var(bounds=(0, None)) self.ve = Constraint(expr=self.v == _e1[1] - _e1[0]) else: # _e1[0] is None: self.v = Var(bounds=(0, None)) self.ve = Constraint(expr=self.v == _e1[2] - _e1[1])
def to_standard_form(self): # # Add auxilliary variables and constraints that ensure # a monotone transformation of general complementary constraints to # the form: # l1 <= v1 <= u1 OR l2 <= v2 <= u2 # # Note that this transformation creates more variables and constraints # than are strictly necessary. However, we don't have a complete list of # the variables used in a model's complementarity conditions when adding # a single condition, so we add additional variables. # # This has the form: # # e: l1 <= expression <= l2 # v: l3 <= var <= l4 # # where exactly two of l1, l2, l3 and l4 are finite, and with the # equality constraint: # # c: v == expression # _e1 = self._canonical_expression(EXPR.clone_expression(self._args[0])) _e2 = self._canonical_expression(EXPR.clone_expression(self._args[1])) if len(_e1) == 2: # Ignore _e2; _e1 is an equality constraint self.c = Constraint(expr=_e1) return if len(_e2) == 2: # Ignore _e1; _e2 is an equality constraint self.c = Constraint(expr=_e2) return # if (_e1[0] is None) + (_e1[2] is None) + (_e2[0] is None) + (_e2[2] is None) != 2: raise RuntimeError("Complementarity condition %s must have exactly two finite bounds" % self.name) # if _e1[0] is None and _e1[2] is None: # Only e2 will be an unconstrained expression _e1, _e2 = _e2, _e1 # if _e2[0] is None and _e2[2] is None: self.c = Constraint(expr=(None, _e2[1], None)) self.c._type = 3 elif _e2[2] is None: self.c = Constraint(expr=_e2[0] <= _e2[1]) self.c._type = 1 elif _e2[0] is None: self.c = Constraint(expr=- _e2[2] <= - _e2[1]) self.c._type = 1 # if not _e1[0] is None and not _e1[2] is None: if not _e1[0].is_constant(): raise RuntimeError("Cannot express a complementarity problem of the form L < v < U _|_ g(x) where L is not a constant value") if not _e1[2].is_constant(): raise RuntimeError("Cannot express a complementarity problem of the form L < v < U _|_ g(x) where U is not a constant value") self.v = Var(bounds=(_e1[0], _e1[2])) self.ve = Constraint(expr=self.v == _e1[1]) elif _e1[2] is None: self.v = Var(bounds=(0, None)) self.ve = Constraint(expr=self.v == _e1[1] - _e1[0]) else: # _e1[0] is None: self.v = Var(bounds=(0, None)) self.ve = Constraint(expr=self.v == _e1[2] - _e1[1])