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
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
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)
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)