Ejemplo n.º 1
0
Archivo: util.py Proyecto: Pyomo/pyomo
def quicksum(args, start=0, linear=None):
    """
    A utility function to compute a sum of Pyomo expressions.

    The behavior of :func:`quicksum` is similar to the builtin :func:`sum`
    function, but this function generates a more compact Pyomo
    expression.

    Args:
        args: A generator for terms in the sum.

        start: A value that is initializes the sum.  If
            this value is not a numeric constant, then the += 
            operator is used to add terms to this object.
            Defaults to zero.

        linear: If :attr:`start` is not a numeric constant, then this 
            option is ignored.  Otherwise, this value indicates
            whether the terms in the sum are linear.  If the value
            is :const:`False`, then the terms are
            treated as nonlinear, and if :const:`True`, then
            the terms are treated as linear.  Default is
            :const:`None`, which indicates that the first term
            in the :attr:`args` is used to determine this value.

    Returns:
        The value of the sum, which may be a Pyomo expression object.
    """
    #
    # If we're starting with a numeric value, then 
    # create a new nonlinear sum expression but 
    # return a static version to the user.
    #
    if start.__class__ in native_numeric_types:
        if linear is None:
            #
            # Get the first term, which we will test for linearity
            #
            try:
                first = next(args, None)
            except:
                try:
                    args = args.__iter__()
                    first = next(args, None)
                except:
                    raise RuntimeError("The argument to quicksum() is not iterable!")
            if first is None:
                return start
            #
            # Check if the first term is linear, and if so return the terms
            #
            linear, terms = decompose_term(first)
            #
            # Right now Pyomo5 expressions can only handle single linear
            # terms.
            #
            # Also, we treat linear expressions as nonlinear if the constant
            # term is not a native numeric type.  Otherwise, large summation
            # objects are created for the constant term.
            #
            if linear:
                nvar=0
                for term in terms:
                    c,v = term
                    if not v is None:
                        nvar += 1
                    elif not c.__class__ in native_numeric_types:
                        linear = False
                if nvar > 1:
                    linear = False
            start = start+first
        if linear:
            with EXPR.linear_expression() as e:
                e += start
                for arg in args:
                    e += arg
            # Return the constant term if the linear expression does not contains variables
            if e.is_constant():
                return e.constant
            return e
        else:
            with EXPR.nonlinear_expression() as e:
                e += start
                for arg in args:
                    e += arg
            if e.nargs() == 0:
                return 0
            elif e.nargs() == 1:
                return e.arg(0)
            return e
    #
    # Otherwise, use the context that is provided and return it.
    #
    e = start
    for arg in args:
        e += arg
    return e
Ejemplo n.º 2
0
def quicksum(args, start=0, linear=None):
    """
    A utility function to compute a sum of Pyomo expressions.

    The behavior of :func:`quicksum` is similar to the builtin :func:`sum`
    function, but this function generates a more compact Pyomo
    expression.

    Args:
        args: A generator for terms in the sum.

        start: A value that is initializes the sum.  If
            this value is not a numeric constant, then the += 
            operator is used to add terms to this object.
            Defaults to zero.

        linear: If :attr:`start` is not a numeric constant, then this 
            option is ignored.  Otherwise, this value indicates
            whether the terms in the sum are linear.  If the value
            is :const:`False`, then the terms are
            treated as nonlinear, and if :const:`True`, then
            the terms are treated as linear.  Default is
            :const:`None`, which indicates that the first term
            in the :attr:`args` is used to determine this value.

    Returns:
        The value of the sum, which may be a Pyomo expression object.
    """
    #
    # If we're starting with a numeric value, then
    # create a new nonlinear sum expression but
    # return a static version to the user.
    #
    if start.__class__ in native_numeric_types:
        if linear is None:
            #
            # Get the first term, which we will test for linearity
            #
            try:
                first = next(args, None)
            except:
                try:
                    args = args.__iter__()
                    first = next(args, None)
                except:
                    raise RuntimeError(
                        "The argument to quicksum() is not iterable!")
            if first is None:
                return start
            #
            # Check if the first term is linear, and if so return the terms
            #
            linear, terms = decompose_term(first)
            #
            # Right now Pyomo5 expressions can only handle single linear
            # terms.
            #
            # Also, we treat linear expressions as nonlinear if the constant
            # term is not a native numeric type.  Otherwise, large summation
            # objects are created for the constant term.
            #
            if linear:
                nvar = 0
                for term in terms:
                    c, v = term
                    if not v is None:
                        nvar += 1
                    elif not c.__class__ in native_numeric_types:
                        linear = False
                if nvar > 1:
                    linear = False
            start = start + first
        if linear:
            with EXPR.linear_expression() as e:
                e += start
                for arg in args:
                    e += arg
            # Return the constant term if the linear expression does not contains variables
            if e.is_constant():
                return e.constant
            return e
        else:
            with EXPR.nonlinear_expression() as e:
                e += start
                for arg in args:
                    e += arg
            if e.nargs() == 0:
                return 0
            elif e.nargs() == 1:
                return e.arg(0)
            return e
    #
    # Otherwise, use the context that is provided and return it.
    #
    e = start
    for arg in args:
        e += arg
    return e
Ejemplo n.º 3
0
Archivo: util.py Proyecto: Pyomo/pyomo
def sum_product(*args, **kwds):
    """
    A utility function to compute a generalized dot product.  

    This function accepts one or more components that provide terms
    that are multiplied together.  These products are added together
    to form a sum.

    Args:
        *args: Variable length argument list of generators that
            create terms in the summation.
        **kwds: Arbitrary keyword arguments.

    Keyword Args:
        index: A set that is used to index the components used to
            create the terms
        denom: A component or tuple of components that are used to
            create the denominator of the terms
        start: The initial value used in the sum

    Returns:
        The value of the sum.
    """
    denom = kwds.pop('denom', tuple() )
    if type(denom) not in (list, tuple):
        denom = [denom]
    nargs = len(args)
    ndenom = len(denom)

    if nargs == 0 and ndenom == 0:
        raise ValueError("The sum_product() command requires at least an " + \
              "argument or a denominator term")

    if 'index' in kwds:
        index=kwds['index']
    else:
        if nargs > 0:
            iarg=args[-1]
            if not isinstance(iarg,pyomo.core.base.var.Var) and not isinstance(iarg, pyomo.core.base.expression.Expression):
                raise ValueError("Error executing sum_product(): The last argument value must be a variable or expression object if no 'index' option is specified")
        else:
            iarg=denom[-1]
            if not isinstance(iarg,pyomo.core.base.var.Var) and not isinstance(iarg, pyomo.core.base.expression.Expression):
                raise ValueError("Error executing sum_product(): The last denom argument value must be a variable or expression object if no 'index' option is specified")
        index = iarg.index_set()

    start = kwds.get("start", 0)
    vars_ = []
    params_ = []
    for arg in args:
        if isinstance(arg, pyomo.core.base.var.Var):
            vars_.append(arg)
        else:
            params_.append(arg)
    nvars = len(vars_)

    num_index = range(0,nargs)
    if ndenom == 0:
        #
        # Sum of polynomial terms
        #
        if start.__class__ in native_numeric_types:
            if nvars == 1:
                v = vars_[0]
                if len(params_) == 0:
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            expr += v[i]
                elif len(params_) == 1:    
                    p = params_[0]
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            expr += p[i]*v[i]
                else:
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            term = 1
                            for j in params_:
                                term *= params_[j][i]
                            expr += term * v[i]
                return expr
            #
            with EXPR.nonlinear_expression() as expr:
                expr += start
                for i in index:
                    term = 1
                    for j in num_index:
                        term *= args[j][i]
                    expr += term
            return expr
        #
        return quicksum((prod(args[j][i] for j in num_index) for i in index), start)
    elif nargs == 0:
        #
        # Sum of reciprocals
        #
        denom_index = range(0,ndenom)
        return quicksum((1/prod(denom[j][i] for j in denom_index) for i in index), start)
    else:
        #
        # Sum of fractions
        #
        denom_index = range(0,ndenom)
        return quicksum((prod(args[j][i] for j in num_index)/prod(denom[j][i] for j in denom_index) for i in index), start)
Ejemplo n.º 4
0
def sum_product(*args, **kwds):
    """
    A utility function to compute a generalized dot product.  

    This function accepts one or more components that provide terms
    that are multiplied together.  These products are added together
    to form a sum.

    Args:
        *args: Variable length argument list of generators that
            create terms in the summation.
        **kwds: Arbitrary keyword arguments.

    Keyword Args:
        index: A set that is used to index the components used to
            create the terms
        denom: A component or tuple of components that are used to
            create the denominator of the terms
        start: The initial value used in the sum

    Returns:
        The value of the sum.
    """
    denom = kwds.pop('denom', tuple())
    if type(denom) not in (list, tuple):
        denom = [denom]
    nargs = len(args)
    ndenom = len(denom)

    if nargs == 0 and ndenom == 0:
        raise ValueError("The sum_product() command requires at least an " + \
              "argument or a denominator term")

    if 'index' in kwds:
        index = kwds['index']
    else:
        if nargs > 0:
            iarg = args[-1]
            if not isinstance(iarg, Var) and not isinstance(iarg, Expression):
                raise ValueError(
                    "Error executing sum_product(): The last argument value must be a variable or expression object if no 'index' option is specified"
                )
        else:
            iarg = denom[-1]
            if not isinstance(iarg, Var) and not isinstance(iarg, Expression):
                raise ValueError(
                    "Error executing sum_product(): The last denom argument value must be a variable or expression object if no 'index' option is specified"
                )
        index = iarg.index_set()

    start = kwds.get("start", 0)
    vars_ = []
    params_ = []
    for arg in args:
        if isinstance(arg, Var):
            vars_.append(arg)
        else:
            params_.append(arg)
    nvars = len(vars_)

    num_index = range(0, nargs)
    if ndenom == 0:
        #
        # Sum of polynomial terms
        #
        if start.__class__ in native_numeric_types:
            if nvars == 1:
                v = vars_[0]
                if len(params_) == 0:
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            expr += v[i]
                elif len(params_) == 1:
                    p = params_[0]
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            expr += p[i] * v[i]
                else:
                    with EXPR.linear_expression() as expr:
                        expr += start
                        for i in index:
                            term = 1
                            for j in params_:
                                term *= params_[j][i]
                            expr += term * v[i]
                return expr
            #
            with EXPR.nonlinear_expression() as expr:
                expr += start
                for i in index:
                    term = 1
                    for j in num_index:
                        term *= args[j][i]
                    expr += term
            return expr
        #
        return quicksum((prod(args[j][i] for j in num_index) for i in index),
                        start)
    elif nargs == 0:
        #
        # Sum of reciprocals
        #
        denom_index = range(0, ndenom)
        return quicksum(
            (1 / prod(denom[j][i] for j in denom_index) for i in index), start)
    else:
        #
        # Sum of fractions
        #
        denom_index = range(0, ndenom)
        return quicksum((prod(args[j][i]
                              for j in num_index) / prod(denom[j][i]
                                                         for j in denom_index)
                         for i in index), start)