Beispiel #1
0
def generate_ampl_repn(exp, idMap=None):
    # We need to do this not at the global scope in case someone changed
    # the mode after importing the environment.
    _using_pyomo4_trees = expr_common.mode == expr_common.Mode.pyomo4_trees

    if idMap is None:
        idMap = {}
    if exp is None:
        return AmplRepn()
    degree = exp.polynomial_degree()
    if (degree is None) or (degree > 1):
        repn = _generate_ampl_repn(exp)
        repn.compress()
    elif degree == 0:
        repn = AmplRepn()
        repn._constant = value(exp)
        # compress
        repn._linear_vars = tuple()
        repn._linear_terms_coef = tuple()
        repn._nonlinear_vars = tuple()
    else:  # degree == 1
        repn = AmplRepn()
        if _using_pyomo4_trees:
            canonical_repn = generate_canonical_repn(exp, idMap=idMap)
            # compress
            repn._nonlinear_vars = tuple()
            repn._constant = value(canonical_repn.constant)
            repn._linear_vars = tuple(canonical_repn.variables)
            repn._linear_terms_coef = tuple(
                value(_v) for _v in canonical_repn.linear)
        else:
            # compress
            repn._linear_vars = tuple()
            repn._linear_terms_coef = tuple()
            repn._nonlinear_vars = tuple()
            coef, varmap = collect_linear_canonical_repn(exp, idMap=idMap)
            if None in coef:
                val = coef.pop(None)
                if val:
                    repn._constant = val
            # the six module is inefficient in terms of wrapping
            # iterkeys and itervalues, in the context of Python
            # 2.7. use the native dictionary methods where
            # possible.
            if using_py3 is False:
                repn._linear_terms_coef = tuple(val
                                                for val in coef.itervalues()
                                                if val)
                repn._linear_vars = tuple(
                    (varmap[var_hash] for var_hash, val in coef.iteritems()
                     if val))
            else:
                repn._linear_terms_coef = tuple(val for val in coef.values()
                                                if val)
                repn._linear_vars = tuple((varmap[var_hash]
                                           for var_hash, val in coef.items()
                                           if val))
    return repn
Beispiel #2
0
def generate_ampl_repn(exp, idMap=None):
    # We need to do this not at the global scope in case someone changed
    # the mode after importing the environment.
    _using_pyomo4_trees = expr_common.mode == expr_common.Mode.pyomo4_trees
    _using_pyomo5_trees = expr_common.mode == expr_common.Mode.pyomo5_trees

    if idMap is None:
        idMap = {}
    if _using_pyomo5_trees:
        from pyomo.repn.standard_repn import generate_standard_repn
        return generate_standard_repn(exp, quadratic=False)

    if exp is None:
        return AmplRepn()
    degree = exp.polynomial_degree()
    if (degree is None) or (degree > 1):
        repn = _generate_ampl_repn(exp)
        repn.compress()
    elif degree == 0:
        repn = AmplRepn()
        repn._constant = value(exp)
        # compress
        repn._linear_vars = tuple()
        repn._linear_terms_coef = tuple()
        repn._nonlinear_vars = tuple()
    else: # degree == 1
        repn = AmplRepn()
        if _using_pyomo4_trees:
            canonical_repn = generate_canonical_repn(exp, idMap=idMap)
            # compress
            repn._nonlinear_vars = tuple()
            repn._constant = value(canonical_repn.constant)
            repn._linear_vars = tuple(canonical_repn.variables)
            repn._linear_terms_coef = tuple(value(_v) for _v in canonical_repn.linear)
        else:
            # compress
            repn._linear_vars = tuple()
            repn._linear_terms_coef = tuple()
            repn._nonlinear_vars = tuple()
            coef, varmap = collect_linear_canonical_repn(exp, idMap=idMap)
            if None in coef:
                val = coef.pop(None)
                if val:
                    repn._constant = val
            # the six module is inefficient in terms of wrapping
            # iterkeys and itervalues, in the context of Python
            # 2.7. use the native dictionary methods where
            # possible.
            if using_py3 is False:
                repn._linear_terms_coef = tuple(val for val in coef.itervalues() if val)
                repn._linear_vars = tuple((varmap[var_hash]
                                           for var_hash,val in coef.iteritems() if val))
            else:
                repn._linear_terms_coef = tuple(val for val in coef.values() if val)
                repn._linear_vars = tuple((varmap[var_hash]
                                           for var_hash,val in coef.items() if val))
    return repn
Beispiel #3
0
def generate_ampl_repn(exp, idMap=None):
    if idMap is None:
        idMap = {}
    degree = exp.polynomial_degree()
    if (degree is None) or (degree > 1):
        repn = _generate_ampl_repn(exp)
        repn.compress()
    elif degree == 0:
        repn = AmplRepn()
        repn._constant = value(exp)
        # compress
        repn._linear_vars = tuple()
        repn._linear_terms_coef = tuple()
        repn._nonlinear_vars = tuple()
    else: # degree == 1
        repn = AmplRepn()
        # compress
        repn._linear_vars = tuple()
        repn._linear_terms_coef = tuple()
        repn._nonlinear_vars = tuple()
        coef, varmap = collect_linear_canonical_repn(exp, idMap=idMap)
        if None in coef:
            val = coef.pop(None)
            if val:
                repn._constant = val
        # the six module is inefficient in terms of wrapping iterkeys and itervalues,
        # in the context of Python 2.7. use the native dictionary methods where possible.
        if using_py3 is False:
            repn._linear_terms_coef = tuple(val for val in coef.itervalues() if val)
            repn._linear_vars = tuple((varmap[var_hash] for var_hash,val in coef.iteritems() if val))
        else:
            repn._linear_terms_coef = tuple(val for val in coef.values() if val)
            repn._linear_vars = tuple((varmap[var_hash] for var_hash,val in coef.items() if val))
    return repn
Beispiel #4
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))
Beispiel #5
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))