Пример #1
0
def pyomo4_generate_canonical_repn(exp, idMap=None, compute_values=True):
    if exp is None:
        return CompiledLinearCanonicalRepn()
    if exp.__class__ in native_numeric_types:
        ans = CompiledLinearCanonicalRepn()
        ans.constant = value(exp)
        return ans
    if not exp.is_expression():
        if exp.is_fixed():
            ans = CompiledLinearCanonicalRepn()
            ans.constant = value(exp)
            return ans
        elif isinstance(exp, _VarData):
            ans = CompiledLinearCanonicalRepn()
            ans.constant = 0
            ans.linear = (1., )
            ans.variables = (exp, )
            return ans
        else:
            raise RuntimeError("Unrecognized expression node: %s" %
                               (type(exp), ))

    degree = exp.polynomial_degree()

    if degree == 1:
        _stack = []
        _args = exp._args
        _idx = 0
        _len = len(_args)
        _result = None
        while 1:
            # Linear expressions just need to be filteres and copied
            if exp.__class__ is expr_pyomo4._LinearExpression:
                _result = expr_pyomo4._LinearExpression(None, 0)
                _result._args = []
                _result._coef.clear()
                _result._const = value(exp._const)
                for v in _args:
                    _id = id(v)
                    if v.is_fixed():
                        _result._const += v.value * value(exp._coef[_id])
                    else:
                        _result._args.append(v)
                        _result._coef[_id] = value(exp._coef[_id])
                _idx = _len

            # Other expressions get their arguments parsed one at a time
            if _idx < _len:
                _stack.append((exp, _args, _idx + 1, _len, _result))
                exp = _args[_idx]
                if exp.__class__ in native_numeric_types:
                    _len = _idx = 0
                    _result = exp
                elif exp.is_expression():
                    _args = exp._args
                    _idx = 0
                    _len = len(_args)
                    _result = None
                    continue
                elif isinstance(exp, _VarData):
                    _len = _idx = 0
                    if exp.is_fixed():
                        _result = exp.value
                    else:
                        _result = expr_pyomo4._LinearExpression(exp, 1.)
                else:
                    raise RuntimeError("Unrecognized expression node: %s" %
                                       (type(exp), ))

            #
            # End of _args... time to move up the stack
            #

            # Top of the stack.  _result had better be a _LinearExpression
            if not _stack:
                ans = CompiledLinearCanonicalRepn()
                # old format
                ans.constant = _result._const
                ans.linear = []
                for v in _result._args:
                    # Note: this also filters out the bogus NONE we added above
                    _coef = _result._coef[id(v)]
                    if _coef:
                        ans.variables.append(v)
                        ans.linear.append(_coef)

                if idMap:
                    if None not in idMap:
                        idMap[None] = {}
                    _test = idMap[None]
                    _key = len(idMap) - 1
                    for v in ans.variables:
                        if id(v) not in _test:
                            _test[id(v)] = _key
                            idMap[_key] = v
                            _key += 1
                return ans

            # Ok ... process the new argument to the node.  Note that
            # _idx is 1-based now...
            _inner_result = _result
            exp, _args, _idx, _len, _result = _stack.pop()
            if exp.__class__ is expr_pyomo4._SumExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result += _inner_result
            elif exp.__class__ is expr_pyomo4._ProductExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result *= _inner_result
            elif exp.__class__ is expr_pyomo4._DivisionExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result /= _inner_result
            elif exp.__class__ is expr_pyomo4._NegationExpression:
                _result = -_inner_result
            elif exp.__class__ is expr_pyomo4._PowExpression:
                # We know this is either constant or linear
                if _idx == 1:
                    _result = _inner_result
                else:
                    coef = value(_inner_result)
                    if not coef:
                        _result = 1.
                    elif coef != 1:
                        _result = _result**coef
            elif exp.__class__ is expr_pyomo4.Expr_if:
                if _idx == 1:
                    _result = [_inner_result]
                else:
                    _result.append(_inner_result)
                if _idx == 3:
                    if value(_result[0]):
                        _result = _result[1]
                    else:
                        _result = _result[2]
            elif exp.__class__ in _identity_collectors:
                _result = _inner_result
            elif exp.is_fixed():
                _result = value(exp)
            else:
                raise RuntimeError("Unknown non-fixed subexpression type %s" %
                                   (type(exp), ))

    elif degree == 0:
        ans = CompiledLinearCanonicalRepn()
        ans.constant = value(exp)
        return ans

    # **Py3k: degree > 1 comparision will error if degree is None
    elif degree and degree > 1:
        raise RuntimeError(
            "generate_canonical_repn does not support nonlinear Pyomo4 expressions"
        )

        ans = collect_general_canonical_repn(exp, idMap, compute_values)
        if 1 in ans:
            linear_terms = {}
            for key, coef in iteritems(ans[1]):
                linear_terms[list(key.keys())[0]] = coef
            ans[1] = linear_terms
        return GeneralCanonicalRepn(ans)
    else:
        return GeneralCanonicalRepn({
            None: exp,
            -1: collect_variables(exp, idMap)
        })
Пример #2
0
def pyomo4_generate_canonical_repn(exp, idMap=None, compute_values=True):
    if exp is None:
        return CompiledLinearCanonicalRepn()
    if exp.__class__ in native_numeric_types:
        ans = CompiledLinearCanonicalRepn()
        ans.constant = value(exp)
        return ans
    if not exp.is_expression():
        if exp.is_fixed():
            ans = CompiledLinearCanonicalRepn()
            ans.constant = value(exp)
            return ans
        elif isinstance(exp, _VarData):
            ans = CompiledLinearCanonicalRepn()
            ans.constant = 0
            ans.linear = (1.,)
            ans.variables = (exp,)
            return ans
        else:
            raise RuntimeError(
                "Unrecognized expression node: %s" % (type(exp),) )

    degree = exp.polynomial_degree()

    if degree == 1:
        _stack = []
        _args = exp._args
        _idx = 0
        _len = len(_args)
        _result = None
        while 1:
            # Linear expressions just need to be filteres and copied
            if exp.__class__ is expr_pyomo4._LinearExpression:
                _result = expr_pyomo4._LinearExpression(None, 0)
                _result._args = []
                _result._coef.clear()
                _result._const = value(exp._const)
                for v in _args:
                    _id = id(v)
                    if v.is_fixed():
                        _result._const += v.value * value(exp._coef[_id])
                    else:
                        _result._args.append(v)
                        _result._coef[_id] = value(exp._coef[_id])
                _idx = _len

            # Other expressions get their arguments parsed one at a time
            if _idx < _len:
                _stack.append((exp, _args, _idx+1, _len, _result))
                exp = _args[_idx]
                if exp.__class__ in native_numeric_types:
                    _len = _idx = 0
                    _result = exp
                elif exp.is_expression():
                    _args = exp._args
                    _idx = 0
                    _len = len(_args)
                    _result = None
                    continue
                elif isinstance(exp, _VarData):
                    _len = _idx = 0
                    if exp.is_fixed():
                        _result = exp.value
                    else:
                        _result = expr_pyomo4._LinearExpression(exp, 1.)
                else:
                    raise RuntimeError(
                        "Unrecognized expression node: %s" % (type(exp),) )

            #
            # End of _args... time to move up the stack
            #

            # Top of the stack.  _result had better be a _LinearExpression
            if not _stack:
                ans = CompiledLinearCanonicalRepn()
                # old format
                ans.constant = _result._const
                ans.linear = []
                for v in _result._args:
                    # Note: this also filters out the bogus NONE we added above
                    _coef = _result._coef[id(v)]
                    if _coef:
                        ans.variables.append(v)
                        ans.linear.append(_coef)

                if idMap:
                    if None not in idMap:
                        idMap[None] = {}
                    _test = idMap[None]
                    _key = len(idMap) - 1
                    for v in ans.variables:
                        if id(v) not in _test:
                            _test[id(v)] = _key
                            idMap[_key] = v
                            _key += 1
                return ans

            # Ok ... process the new argument to the node.  Note that
            # _idx is 1-based now...
            _inner_result = _result
            exp, _args, _idx, _len, _result = _stack.pop()
            if exp.__class__ is expr_pyomo4._SumExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result += _inner_result
            elif exp.__class__ is expr_pyomo4._ProductExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result *= _inner_result
            elif exp.__class__ is expr_pyomo4._DivisionExpression:
                if _idx == 1:
                    _result = _inner_result
                else:
                    _result /= _inner_result
            elif exp.__class__ is expr_pyomo4._NegationExpression:
                _result = -_inner_result
            elif exp.__class__ is expr_pyomo4._PowExpression:
                # We know this is either constant or linear
                if _idx == 1:
                    _result = _inner_result
                else:
                    coef = value(_inner_result)
                    if not coef:
                        _result = 1.
                    elif coef != 1:
                        _result = _result ** coef
            elif exp.__class__ is expr_pyomo4.Expr_if:
                if _idx == 1:
                    _result = [_inner_result]
                else:
                    _result.append(_inner_result)
                if _idx == 3:
                    if value(_result[0]):
                        _result = _result[1]
                    else:
                        _result = _result[2]
            elif exp.__class__ in _identity_collectors:
                _result = _inner_result
            elif exp.is_fixed():
                _result = value(exp)
            else:
                raise RuntimeError(
                    "Unknown non-fixed subexpression type %s" % (type(exp),) )

    elif degree == 0:
        ans = CompiledLinearCanonicalRepn()
        ans.constant = value(exp)
        return ans


    # **Py3k: degree > 1 comparision will error if degree is None
    elif degree and degree > 1:
        raise RuntimeError("generate_canonical_repn does not support nonlinear Pyomo4 expressions")

        ans = collect_general_canonical_repn(exp, idMap, compute_values)
        if 1 in ans:
            linear_terms = {}
            for key, coef in iteritems(ans[1]):
                linear_terms[list(key.keys())[0]] = coef
            ans[1] = linear_terms
        return GeneralCanonicalRepn(ans)
    else:
        return GeneralCanonicalRepn(
            { None: exp, -1 : collect_variables(exp, idMap) } )