Exemplo n.º 1
0
 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))
Exemplo n.º 2
0
 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), ))
Exemplo n.º 3
0
 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), ))
Exemplo n.º 4
0
 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),))
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
 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))
Exemplo n.º 7
0
 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
Exemplo n.º 8
0
 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))
Exemplo n.º 9
0
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))
Exemplo n.º 10
0
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))
Exemplo n.º 11
0
 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))