def _collect_variables(exp): if is_constant(exp): return {} elif exp.is_expression(): ans = {} if exp.__class__ is pyomo.core.base.expr._ProductExpression: for subexp in exp._numerator: ans.update(EmbeddedSP.\ _collect_variables(subexp)) for subexp in exp._denominator: ans.update(EmbeddedSP.\ _collect_variables(subexp)) else: # This is fragile: we assume that all other expression # objects "play nice" and just use the _args member. for subexp in exp._args: ans.update(EmbeddedSP.\ _collect_variables(subexp)) return ans elif isinstance(exp, _VarData): return {id(exp): exp} elif is_fixed(exp): return {} else: raise ValueError("Unexpected expression type: " + str(exp))
def setlb(self, val): if is_fixed(val): self._lb = val else: raise ValueError( "Non-fixed input of type '%s' supplied as variable lower " "bound - legal types must be fixed expressions or variables." % (type(val), ))
def setub(self, val): """ Set the upper bound for this variable after validating that the value is fixed (or None). """ # Note: is_fixed(None) returns True if is_fixed(val): self._ub = val else: raise ValueError( "Non-fixed input of type '%s' supplied as variable upper " "bound - legal types are fixed expressions or variables." "parameters" % (type(val), ))
def setlb(self, val): """ Set the lower bound for this variable after validating that the value is fixed (or None). """ # Note: is_fixed(None) returns True if is_fixed(val): self._lb = val else: raise ValueError( "Non-fixed input of type '%s' supplied as variable lower " "bound - legal types must be fixed expressions or variables." % (type(val),))
def _process_bound(self, val, bound_type): # Note: is_fixed(None) returns True if not is_fixed(val): raise ValueError( "Non-fixed input of type '%s' supplied as variable %s " "bound - legal types must be constants or fixed expressions." % (type(val), bound_type)) if type(val) in native_numeric_types or val is None: # TODO: warn/error: check if this Var has units: assigning # a dimensionless value to a united variable should be an error pass else: # We want to create an expression and not just convert the # current value so that things like mutable Params behave as # expected. if self.parent_component()._units is not None: val = units.convert(val, to_units=self.parent_component()._units) return val
def _collect_unfixed_variables(exp): if is_fixed(exp): return {} elif exp.is_expression(): ans = {} if exp.__class__ is pyomo.core.base.expr._ProductExpression: for subexp in exp._numerator: ans.update(ImplicitSP.\ _collect_unfixed_variables(subexp)) for subexp in exp._denominator: ans.update(ImplicitSP.\ _collect_unfixed_variables(subexp)) else: # This is fragile: we assume that all other expression # objects "play nice" and just use the _args member. for subexp in exp._args: ans.update(ImplicitSP.\ _collect_unfixed_variables(subexp)) return ans elif isinstance(exp, _VarData): return {id(exp): exp} else: raise ValueError("Unexpected expression type: "+str(exp))
def setlb(self, val): """ Set the lower bound for this variable after validating that the value is fixed (or None). """ # Note: is_fixed(None) returns True if not is_fixed(val): raise ValueError( "Non-fixed input of type '%s' supplied as variable lower " "bound - legal types must be fixed expressions or variables." % (type(val),)) if type(val) in native_numeric_types or val is None: # TODO: warn/error: check if this Var has units: assigning # a dimensionless value to a united variable should be an error pass else: if self.parent_component()._units is not None: _src_magnitude = value(val) _src_units = units.get_units(val) val = units.convert_value( num_value=_src_magnitude, from_units=_src_units, to_units=self.parent_component()._units) self._lb = val
def _get_bound(self, exp): if exp is None: return None if is_fixed(exp): return value(exp) raise ValueError("non-fixed bound: " + str(exp))
def _generate_ampl_repn(exp): ampl_repn = AmplRepn() exp_type = type(exp) if exp_type in native_numeric_types: ampl_repn._constant = value(exp) return ampl_repn # # Expression # elif exp.is_expression(): # # Sum # if _using_pyomo4_trees and (exp_type is Expr._LinearExpression): ampl_repn._constant = value(exp._const) ampl_repn._nonlinear_expr = None for child_exp in exp._args: exp_coef = value(exp._coef[id(child_exp)]) if exp_coef != 0: child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += exp_coef * child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ exp_coef * child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ exp_coef * child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(exp_coef, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (exp_coef, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update( child_repn._nonlinear_vars) return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._SumExpression): ampl_repn._constant = 0.0 ampl_repn._nonlinear_expr = None for child_exp in exp._args: child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(1, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (1, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) return ampl_repn elif exp_type is Expr._SumExpression: assert not _using_pyomo4_trees ampl_repn._constant = exp._const ampl_repn._nonlinear_expr = None for i in xrange(len(exp._args)): exp_coef = exp._coef[i] if exp_coef != 0: child_exp = exp._args[i] child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += exp_coef * child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ exp_coef * child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ exp_coef * child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(exp_coef, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (exp_coef, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update( child_repn._nonlinear_vars) return ampl_repn # # Product # elif (not _using_pyomo4_trees) and \ (exp_type is Expr._ProductExpression): # # Iterate through the denominator. If they # aren't all constants, then simply return this # expression. # denom = 1.0 for e in exp._denominator: if e.is_fixed(): denom *= value(e) else: ampl_repn._nonlinear_expr = exp break if denom == 0.0: raise ZeroDivisionError( "Divide-by-zero error - offending sub-expression: " + str(e)) if ampl_repn._nonlinear_expr is not None: # we have a nonlinear expression ... build up all the vars for e in exp._denominator: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) for e in exp._numerator: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) return ampl_repn # # OK, the denominator is a constant. # # build up the ampl_repns for the numerator n_linear_args = 0 n_nonlinear_args = 0 arg_repns = list() for e in exp._numerator: e_repn = _generate_ampl_repn(e) arg_repns.append(e_repn) # check if the expression is not nonlinear else it is nonlinear if e_repn._nonlinear_expr is not None: n_nonlinear_args += 1 # Check whether the expression is constant or else it is linear elif len(e_repn._linear_vars) > 0: n_linear_args += 1 # At this point we do not have a nonlinear # expression and there are no linear # terms. If the expression constant is zero, # then we have a zero term in the product # expression, so the entire product # expression becomes trivial. elif e_repn._constant == 0.0: ampl_repn = e_repn return ampl_repn is_nonlinear = False if n_linear_args > 1 or n_nonlinear_args > 0: is_nonlinear = True if is_nonlinear: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn = AmplRepn() ampl_repn._nonlinear_expr = exp for repn in arg_repns: ampl_repn._nonlinear_vars.update(repn._linear_vars) ampl_repn._nonlinear_vars.update(repn._nonlinear_vars) return ampl_repn else: # is linear or constant ampl_repn = current_repn = arg_repns[0] for i in xrange(1, len(arg_repns)): e_repn = arg_repns[i] ampl_repn = AmplRepn() # const_c * const_e ampl_repn._constant = current_repn._constant * e_repn._constant # const_e * L_c if e_repn._constant != 0.0: for (var_ID, var) in iteritems(current_repn._linear_vars): ampl_repn._linear_terms_coef[var_ID] = \ current_repn._linear_terms_coef[var_ID] * \ e_repn._constant ampl_repn._linear_vars.update( current_repn._linear_vars) # const_c * L_e if current_repn._constant != 0.0: for (e_var_ID, e_var) in iteritems(e_repn._linear_vars): if e_var_ID in ampl_repn._linear_vars: ampl_repn._linear_terms_coef[e_var_ID] += \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] else: ampl_repn._linear_terms_coef[e_var_ID] = \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] ampl_repn._linear_vars.update(e_repn._linear_vars) current_repn = ampl_repn # now deal with the product expression's coefficient that needs # to be applied to all parts of the ampl_repn ampl_repn._constant *= exp._coef / denom for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] *= exp._coef / denom return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._ProductExpression): # It is assumed this is a binary operator # (x=args[0], y=args[1]) assert len(exp._args) == 2 n_linear_args = 0 n_nonlinear_args = 0 arg_repns = list() for e in exp._args: e_repn = _generate_ampl_repn(e) arg_repns.append(e_repn) # check if the expression is not nonlinear else it is nonlinear if e_repn._nonlinear_expr is not None: n_nonlinear_args += 1 # Check whether the expression is constant or else it is linear elif len(e_repn._linear_vars) > 0: n_linear_args += 1 # At this point we do not have a nonlinear # expression and there are no linear # terms. If the expression constant is zero, # then we have a zero term in the product # expression, so the entire product # expression becomes trivial. elif e_repn._constant == 0.0: ampl_repn = e_repn return ampl_repn is_nonlinear = False if n_linear_args > 1 or n_nonlinear_args > 0: is_nonlinear = True if is_nonlinear: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn = AmplRepn() ampl_repn._nonlinear_expr = exp for repn in arg_repns: ampl_repn._nonlinear_vars.update(repn._linear_vars) ampl_repn._nonlinear_vars.update(repn._nonlinear_vars) return ampl_repn # is linear or constant ampl_repn = current_repn = arg_repns[0] for i in xrange(1, len(arg_repns)): e_repn = arg_repns[i] ampl_repn = AmplRepn() # const_c * const_e ampl_repn._constant = current_repn._constant * e_repn._constant # const_e * L_c if e_repn._constant != 0.0: for (var_ID, var) in iteritems(current_repn._linear_vars): ampl_repn._linear_terms_coef[var_ID] = \ current_repn._linear_terms_coef[var_ID] * \ e_repn._constant ampl_repn._linear_vars.update(current_repn._linear_vars) # const_c * L_e if current_repn._constant != 0.0: for (e_var_ID, e_var) in iteritems(e_repn._linear_vars): if e_var_ID in ampl_repn._linear_vars: ampl_repn._linear_terms_coef[e_var_ID] += \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] else: ampl_repn._linear_terms_coef[e_var_ID] = \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] ampl_repn._linear_vars.update(e_repn._linear_vars) current_repn = ampl_repn return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._DivisionExpression): # It is assumed this is a binary operator # (numerator=args[0], denominator=args[1]) assert len(exp._args) == 2 # # Check the denominator, if it is not constant, # then simply return this expression. # numerator, denominator = exp._args if not is_fixed(denominator): ampl_repn._nonlinear_expr = exp # we have a nonlinear expression, so build up all the vars for e in exp._args: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) return ampl_repn denominator = value(denominator) if denominator == 0: raise ZeroDivisionError( "Divide-by-zero error - offending sub-expression: " + str(exp._args[1])) # # OK, the denominator is a constant. # # build up the ampl_repn for the numerator ampl_repn = _generate_ampl_repn(numerator) # check if the expression is not nonlinear else it is nonlinear if ampl_repn._nonlinear_expr is not None: # do like AMPL and simply return the expression # without extracting the potentially linear part # (be sure to set this to the original expression, # not just the numerators) ampl_repn._nonlinear_expr = exp return ampl_repn # # OK, we have a linear numerator with a constant denominator # # update any constants and coefficients by dividing # by the fixed denominator ampl_repn._constant /= denominator for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] /= denominator return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._NegationExpression): assert len(exp._args) == 1 ampl_repn = _generate_ampl_repn(exp._args[0]) if ampl_repn._nonlinear_expr is not None: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn._nonlinear_expr = exp return ampl_repn # this subexpression is linear, so update any # constants and coefficients by negating them ampl_repn._constant *= -1 for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] *= -1 return ampl_repn # # Power Expressions # elif exp_type is Expr._PowExpression: assert (len(exp._args) == 2) base_repn = _generate_ampl_repn(exp._args[0]) base_repn_fixed = base_repn.is_fixed() exponent_repn = _generate_ampl_repn(exp._args[1]) exponent_repn_fixed = exponent_repn.is_fixed() if base_repn_fixed and exponent_repn_fixed: ampl_repn._constant = base_repn._constant**exponent_repn._constant elif exponent_repn_fixed and exponent_repn._constant == 1.0: ampl_repn = base_repn elif exponent_repn_fixed and exponent_repn._constant == 0.0: ampl_repn._constant = 1.0 else: # instead, let's just return the expression we are given and only # use the ampl_repn for the vars ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = base_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(exponent_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(base_repn._linear_vars) ampl_repn._nonlinear_vars.update(exponent_repn._linear_vars) return ampl_repn # # External Functions # elif exp_type is external._ExternalFunctionExpression: # In theory, the argument are fixed, we can simply evaluate this expression if exp.is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # this is inefficient since it is using much more than what we need ampl_repn._nonlinear_expr = exp for arg in exp._args: if isinstance(arg, basestring): continue child_repn = _generate_ampl_repn(arg) ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(child_repn._linear_vars) return ampl_repn # # Intrinsic Functions # elif isinstance(exp, Expr._IntrinsicFunctionExpression): # Checking isinstance above accounts for the fact that _AbsExpression # is a subclass of _IntrinsicFunctionExpression assert (len(exp._args) == 1) # the argument is fixed, we can simply evaluate this expression if exp._args[0].is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # this is inefficient since it is using much more than what we need child_repn = _generate_ampl_repn(exp._args[0]) ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = child_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(child_repn._linear_vars) return ampl_repn # # AMPL-style If-Then-Else expression # elif exp_type is Expr.Expr_if: if exp._if.is_fixed(): if exp._if(): ampl_repn = _generate_ampl_repn(exp._then) else: ampl_repn = _generate_ampl_repn(exp._else) else: if_repn = _generate_ampl_repn(exp._if) then_repn = _generate_ampl_repn(exp._then) else_repn = _generate_ampl_repn(exp._else) ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = if_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(then_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(else_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(if_repn._linear_vars) ampl_repn._nonlinear_vars.update(then_repn._linear_vars) ampl_repn._nonlinear_vars.update(else_repn._linear_vars) return ampl_repn elif (exp_type is Expr._InequalityExpression) or \ (exp_type is Expr._EqualityExpression): for arg in exp._args: arg_repn = _generate_ampl_repn(arg) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_expr = exp return ampl_repn elif exp.is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # # Expression (the component) # elif isinstance(exp, _ExpressionData): ampl_repn = _generate_ampl_repn(exp.expr) return ampl_repn # # ERROR # else: raise ValueError("Unsupported expression type: " + str(type(exp)) + " (" + str(exp) + ")") # # Constant # elif exp.is_fixed(): ### GAH: Why were we even checking this #if not exp.value.__class__ in native_numeric_types: # ampl_repn = _generate_ampl_repn(exp.value) # return ampl_repn ampl_repn._constant = value(exp) return ampl_repn # # Variable # elif isinstance(exp, _VarData): if exp.fixed: ampl_repn._constant = exp.value return ampl_repn var_ID = id(exp) ampl_repn._linear_terms_coef[var_ID] = 1.0 ampl_repn._linear_vars[var_ID] = exp return ampl_repn # # ERROR # else: raise ValueError("Unexpected expression type: " + str(exp))
def _generate_ampl_repn(exp): ampl_repn = AmplRepn() exp_type = type(exp) if exp_type in native_numeric_types: ampl_repn._constant = value(exp) return ampl_repn # # Expression # elif exp.is_expression(): # # Sum # if _using_pyomo4_trees and (exp_type is Expr._LinearExpression): ampl_repn._constant = value(exp._const) ampl_repn._nonlinear_expr = None for child_exp in exp._args: exp_coef = value(exp._coef[id(child_exp)]) if exp_coef != 0: child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += exp_coef * child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ exp_coef * child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ exp_coef * child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(exp_coef, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (exp_coef, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._SumExpression): ampl_repn._constant = 0.0 ampl_repn._nonlinear_expr = None for child_exp in exp._args: child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(1, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (1, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) return ampl_repn elif exp_type is Expr._SumExpression: assert not _using_pyomo4_trees ampl_repn._constant = exp._const ampl_repn._nonlinear_expr = None for i in xrange(len(exp._args)): exp_coef = exp._coef[i] if exp_coef != 0: child_exp = exp._args[i] child_repn = _generate_ampl_repn(child_exp) # adjust the constant ampl_repn._constant += exp_coef * child_repn._constant # adjust the linear terms for var_ID in child_repn._linear_vars: if var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] += \ exp_coef * child_repn._linear_terms_coef[var_ID] else: ampl_repn._linear_terms_coef[var_ID] = \ exp_coef * child_repn._linear_terms_coef[var_ID] # adjust the linear vars ampl_repn._linear_vars.update(child_repn._linear_vars) # adjust the nonlinear terms if not child_repn._nonlinear_expr is None: if ampl_repn._nonlinear_expr is None: ampl_repn._nonlinear_expr = \ [(exp_coef, child_repn._nonlinear_expr)] else: ampl_repn._nonlinear_expr.append( (exp_coef, child_repn._nonlinear_expr)) # adjust the nonlinear vars ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) return ampl_repn # # Product # elif (not _using_pyomo4_trees) and \ (exp_type is Expr._ProductExpression): # # Iterate through the denominator. If they # aren't all constants, then simply return this # expression. # denom = 1.0 for e in exp._denominator: if e.is_fixed(): denom *= value(e) else: ampl_repn._nonlinear_expr = exp break if denom == 0.0: raise ZeroDivisionError( "Divide-by-zero error - offending sub-expression: "+str(e)) if ampl_repn._nonlinear_expr is not None: # we have a nonlinear expression ... build up all the vars for e in exp._denominator: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) for e in exp._numerator: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) return ampl_repn # # OK, the denominator is a constant. # # build up the ampl_repns for the numerator n_linear_args = 0 n_nonlinear_args = 0 arg_repns = list() for e in exp._numerator: e_repn = _generate_ampl_repn(e) arg_repns.append(e_repn) # check if the expression is not nonlinear else it is nonlinear if e_repn._nonlinear_expr is not None: n_nonlinear_args += 1 # Check whether the expression is constant or else it is linear elif len(e_repn._linear_vars) > 0: n_linear_args += 1 # At this point we do not have a nonlinear # expression and there are no linear # terms. If the expression constant is zero, # then we have a zero term in the product # expression, so the entire product # expression becomes trivial. elif e_repn._constant == 0.0: ampl_repn = e_repn return ampl_repn is_nonlinear = False if n_linear_args > 1 or n_nonlinear_args > 0: is_nonlinear = True if is_nonlinear: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn = AmplRepn() ampl_repn._nonlinear_expr = exp for repn in arg_repns: ampl_repn._nonlinear_vars.update(repn._linear_vars) ampl_repn._nonlinear_vars.update(repn._nonlinear_vars) return ampl_repn else: # is linear or constant ampl_repn = current_repn = arg_repns[0] for i in xrange(1,len(arg_repns)): e_repn = arg_repns[i] ampl_repn = AmplRepn() # const_c * const_e ampl_repn._constant = current_repn._constant * e_repn._constant # const_e * L_c if e_repn._constant != 0.0: for (var_ID, var) in iteritems(current_repn._linear_vars): ampl_repn._linear_terms_coef[var_ID] = \ current_repn._linear_terms_coef[var_ID] * \ e_repn._constant ampl_repn._linear_vars.update(current_repn._linear_vars) # const_c * L_e if current_repn._constant != 0.0: for (e_var_ID,e_var) in iteritems(e_repn._linear_vars): if e_var_ID in ampl_repn._linear_vars: ampl_repn._linear_terms_coef[e_var_ID] += \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] else: ampl_repn._linear_terms_coef[e_var_ID] = \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] ampl_repn._linear_vars.update(e_repn._linear_vars) current_repn = ampl_repn # now deal with the product expression's coefficient that needs # to be applied to all parts of the ampl_repn ampl_repn._constant *= exp._coef/denom for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] *= exp._coef/denom return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._ProductExpression): # It is assumed this is a binary operator # (x=args[0], y=args[1]) assert len(exp._args) == 2 n_linear_args = 0 n_nonlinear_args = 0 arg_repns = list() for e in exp._args: e_repn = _generate_ampl_repn(e) arg_repns.append(e_repn) # check if the expression is not nonlinear else it is nonlinear if e_repn._nonlinear_expr is not None: n_nonlinear_args += 1 # Check whether the expression is constant or else it is linear elif len(e_repn._linear_vars) > 0: n_linear_args += 1 # At this point we do not have a nonlinear # expression and there are no linear # terms. If the expression constant is zero, # then we have a zero term in the product # expression, so the entire product # expression becomes trivial. elif e_repn._constant == 0.0: ampl_repn = e_repn return ampl_repn is_nonlinear = False if n_linear_args > 1 or n_nonlinear_args > 0: is_nonlinear = True if is_nonlinear: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn = AmplRepn() ampl_repn._nonlinear_expr = exp for repn in arg_repns: ampl_repn._nonlinear_vars.update(repn._linear_vars) ampl_repn._nonlinear_vars.update(repn._nonlinear_vars) return ampl_repn # is linear or constant ampl_repn = current_repn = arg_repns[0] for i in xrange(1,len(arg_repns)): e_repn = arg_repns[i] ampl_repn = AmplRepn() # const_c * const_e ampl_repn._constant = current_repn._constant * e_repn._constant # const_e * L_c if e_repn._constant != 0.0: for (var_ID, var) in iteritems(current_repn._linear_vars): ampl_repn._linear_terms_coef[var_ID] = \ current_repn._linear_terms_coef[var_ID] * \ e_repn._constant ampl_repn._linear_vars.update(current_repn._linear_vars) # const_c * L_e if current_repn._constant != 0.0: for (e_var_ID,e_var) in iteritems(e_repn._linear_vars): if e_var_ID in ampl_repn._linear_vars: ampl_repn._linear_terms_coef[e_var_ID] += \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] else: ampl_repn._linear_terms_coef[e_var_ID] = \ current_repn._constant * \ e_repn._linear_terms_coef[e_var_ID] ampl_repn._linear_vars.update(e_repn._linear_vars) current_repn = ampl_repn return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._DivisionExpression): # It is assumed this is a binary operator # (numerator=args[0], denominator=args[1]) assert len(exp._args) == 2 # # Check the denominator, if it is not constant, # then simply return this expression. # numerator, denominator = exp._args if not is_fixed(denominator): ampl_repn._nonlinear_expr = exp # we have a nonlinear expression, so build up all the vars for e in exp._args: arg_repn = _generate_ampl_repn(e) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) return ampl_repn denominator = value(denominator) if denominator == 0: raise ZeroDivisionError( "Divide-by-zero error - offending sub-expression: "+str(exp._args[1])) # # OK, the denominator is a constant. # # build up the ampl_repn for the numerator ampl_repn = _generate_ampl_repn(numerator) # check if the expression is not nonlinear else it is nonlinear if ampl_repn._nonlinear_expr is not None: # do like AMPL and simply return the expression # without extracting the potentially linear part # (be sure to set this to the original expression, # not just the numerators) ampl_repn._nonlinear_expr = exp return ampl_repn # # OK, we have a linear numerator with a constant denominator # # update any constants and coefficients by dividing # by the fixed denominator ampl_repn._constant /= denominator for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] /= denominator return ampl_repn elif _using_pyomo4_trees and (exp_type is Expr._NegationExpression): assert len(exp._args) == 1 ampl_repn = _generate_ampl_repn(exp._args[0]) if ampl_repn._nonlinear_expr is not None: # do like AMPL and simply return the expression # without extracting the potentially linear part ampl_repn._nonlinear_expr = exp return ampl_repn # this subexpression is linear, so update any # constants and coefficients by negating them ampl_repn._constant *= -1 for var_ID in ampl_repn._linear_terms_coef: ampl_repn._linear_terms_coef[var_ID] *= -1 return ampl_repn # # Power Expressions # elif exp_type is Expr._PowExpression: assert(len(exp._args) == 2) base_repn = _generate_ampl_repn(exp._args[0]) base_repn_fixed = base_repn.is_fixed() exponent_repn = _generate_ampl_repn(exp._args[1]) exponent_repn_fixed = exponent_repn.is_fixed() if base_repn_fixed and exponent_repn_fixed: ampl_repn._constant = base_repn._constant**exponent_repn._constant elif exponent_repn_fixed and exponent_repn._constant == 1.0: ampl_repn = base_repn elif exponent_repn_fixed and exponent_repn._constant == 0.0: ampl_repn._constant = 1.0 else: # instead, let's just return the expression we are given and only # use the ampl_repn for the vars ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = base_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(exponent_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(base_repn._linear_vars) ampl_repn._nonlinear_vars.update(exponent_repn._linear_vars) return ampl_repn # # External Functions # elif exp_type is external._ExternalFunctionExpression: # In theory, the argument are fixed, we can simply evaluate this expression if exp.is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # this is inefficient since it is using much more than what we need ampl_repn._nonlinear_expr = exp for arg in exp._args: if isinstance(arg, basestring): continue child_repn = _generate_ampl_repn(arg) ampl_repn._nonlinear_vars.update(child_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(child_repn._linear_vars) return ampl_repn # # Intrinsic Functions # elif isinstance(exp,Expr._IntrinsicFunctionExpression): # Checking isinstance above accounts for the fact that _AbsExpression # is a subclass of _IntrinsicFunctionExpression assert(len(exp._args) == 1) # the argument is fixed, we can simply evaluate this expression if exp._args[0].is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # this is inefficient since it is using much more than what we need child_repn = _generate_ampl_repn(exp._args[0]) ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = child_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(child_repn._linear_vars) return ampl_repn # # AMPL-style If-Then-Else expression # elif exp_type is Expr.Expr_if: if exp._if.is_fixed(): if exp._if(): ampl_repn = _generate_ampl_repn(exp._then) else: ampl_repn = _generate_ampl_repn(exp._else) else: if_repn = _generate_ampl_repn(exp._if) then_repn = _generate_ampl_repn(exp._then) else_repn = _generate_ampl_repn(exp._else) ampl_repn._nonlinear_expr = exp ampl_repn._nonlinear_vars = if_repn._nonlinear_vars ampl_repn._nonlinear_vars.update(then_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(else_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(if_repn._linear_vars) ampl_repn._nonlinear_vars.update(then_repn._linear_vars) ampl_repn._nonlinear_vars.update(else_repn._linear_vars) return ampl_repn elif (exp_type is Expr._InequalityExpression) or \ (exp_type is Expr._EqualityExpression): for arg in exp._args: arg_repn = _generate_ampl_repn(arg) ampl_repn._nonlinear_vars.update(arg_repn._nonlinear_vars) ampl_repn._nonlinear_vars.update(arg_repn._linear_vars) ampl_repn._nonlinear_expr = exp return ampl_repn elif exp.is_fixed(): ampl_repn._constant = value(exp) return ampl_repn # # Expression (the component) # elif isinstance(exp, _ExpressionData): ampl_repn = _generate_ampl_repn(exp.expr) return ampl_repn # # ERROR # else: raise ValueError("Unsupported expression type: "+str(type(exp))+" ("+str(exp)+")") # # Constant # elif exp.is_fixed(): ### GAH: Why were we even checking this #if not exp.value.__class__ in native_numeric_types: # ampl_repn = _generate_ampl_repn(exp.value) # return ampl_repn ampl_repn._constant = value(exp) return ampl_repn # # Variable # elif isinstance(exp, _VarData): if exp.fixed: ampl_repn._constant = exp.value return ampl_repn var_ID = id(exp) ampl_repn._linear_terms_coef[var_ID] = 1.0 ampl_repn._linear_vars[var_ID] = exp return ampl_repn # # ERROR # else: raise ValueError("Unexpected expression type: "+str(exp))