| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 | 
							- from sympy.core.add import Add
 
- from sympy.core.containers import Tuple
 
- from sympy.core.expr import Expr
 
- from sympy.core.function import AppliedUndef, UndefinedFunction
 
- from sympy.core.mul import Mul
 
- from sympy.core.relational import Equality, Relational
 
- from sympy.core.singleton import S
 
- from sympy.core.symbol import Symbol, Dummy
 
- from sympy.core.sympify import sympify
 
- from sympy.functions.elementary.piecewise import (piecewise_fold,
 
-     Piecewise)
 
- from sympy.logic.boolalg import BooleanFunction
 
- from sympy.matrices.matrices import MatrixBase
 
- from sympy.sets.sets import Interval, Set
 
- from sympy.sets.fancysets import Range
 
- from sympy.tensor.indexed import Idx
 
- from sympy.utilities import flatten
 
- from sympy.utilities.iterables import sift, is_sequence
 
- from sympy.utilities.exceptions import sympy_deprecation_warning
 
- def _common_new(cls, function, *symbols, discrete, **assumptions):
 
-     """Return either a special return value or the tuple,
 
-     (function, limits, orientation). This code is common to
 
-     both ExprWithLimits and AddWithLimits."""
 
-     function = sympify(function)
 
-     if isinstance(function, Equality):
 
-         # This transforms e.g. Integral(Eq(x, y)) to Eq(Integral(x), Integral(y))
 
-         # but that is only valid for definite integrals.
 
-         limits, orientation = _process_limits(*symbols, discrete=discrete)
 
-         if not (limits and all(len(limit) == 3 for limit in limits)):
 
-             sympy_deprecation_warning(
 
-                 """
 
-                 Creating a indefinite integral with an Eq() argument is
 
-                 deprecated.
 
-                 This is because indefinite integrals do not preserve equality
 
-                 due to the arbitrary constants. If you want an equality of
 
-                 indefinite integrals, use Eq(Integral(a, x), Integral(b, x))
 
-                 explicitly.
 
-                 """,
 
-                 deprecated_since_version="1.6",
 
-                 active_deprecations_target="deprecated-indefinite-integral-eq",
 
-                 stacklevel=5,
 
-             )
 
-         lhs = function.lhs
 
-         rhs = function.rhs
 
-         return Equality(cls(lhs, *symbols, **assumptions), \
 
-                         cls(rhs, *symbols, **assumptions))
 
-     if function is S.NaN:
 
-         return S.NaN
 
-     if symbols:
 
-         limits, orientation = _process_limits(*symbols, discrete=discrete)
 
-         for i, li in enumerate(limits):
 
-             if len(li) == 4:
 
-                 function = function.subs(li[0], li[-1])
 
-                 limits[i] = Tuple(*li[:-1])
 
-     else:
 
-         # symbol not provided -- we can still try to compute a general form
 
-         free = function.free_symbols
 
-         if len(free) != 1:
 
-             raise ValueError(
 
-                 "specify dummy variables for %s" % function)
 
-         limits, orientation = [Tuple(s) for s in free], 1
 
-     # denest any nested calls
 
-     while cls == type(function):
 
-         limits = list(function.limits) + limits
 
-         function = function.function
 
-     # Any embedded piecewise functions need to be brought out to the
 
-     # top level. We only fold Piecewise that contain the integration
 
-     # variable.
 
-     reps = {}
 
-     symbols_of_integration = {i[0] for i in limits}
 
-     for p in function.atoms(Piecewise):
 
-         if not p.has(*symbols_of_integration):
 
-             reps[p] = Dummy()
 
-     # mask off those that don't
 
-     function = function.xreplace(reps)
 
-     # do the fold
 
-     function = piecewise_fold(function)
 
-     # remove the masking
 
-     function = function.xreplace({v: k for k, v in reps.items()})
 
-     return function, limits, orientation
 
- def _process_limits(*symbols, discrete=None):
 
-     """Process the list of symbols and convert them to canonical limits,
 
-     storing them as Tuple(symbol, lower, upper). The orientation of
 
-     the function is also returned when the upper limit is missing
 
-     so (x, 1, None) becomes (x, None, 1) and the orientation is changed.
 
-     In the case that a limit is specified as (symbol, Range), a list of
 
-     length 4 may be returned if a change of variables is needed; the
 
-     expression that should replace the symbol in the expression is
 
-     the fourth element in the list.
 
-     """
 
-     limits = []
 
-     orientation = 1
 
-     if discrete is None:
 
-         err_msg = 'discrete must be True or False'
 
-     elif discrete:
 
-         err_msg = 'use Range, not Interval or Relational'
 
-     else:
 
-         err_msg = 'use Interval or Relational, not Range'
 
-     for V in symbols:
 
-         if isinstance(V, (Relational, BooleanFunction)):
 
-             if discrete:
 
-                 raise TypeError(err_msg)
 
-             variable = V.atoms(Symbol).pop()
 
-             V = (variable, V.as_set())
 
-         elif isinstance(V, Symbol) or getattr(V, '_diff_wrt', False):
 
-             if isinstance(V, Idx):
 
-                 if V.lower is None or V.upper is None:
 
-                     limits.append(Tuple(V))
 
-                 else:
 
-                     limits.append(Tuple(V, V.lower, V.upper))
 
-             else:
 
-                 limits.append(Tuple(V))
 
-             continue
 
-         if is_sequence(V) and not isinstance(V, Set):
 
-             if len(V) == 2 and isinstance(V[1], Set):
 
-                 V = list(V)
 
-                 if isinstance(V[1], Interval):  # includes Reals
 
-                     if discrete:
 
-                         raise TypeError(err_msg)
 
-                     V[1:] = V[1].inf, V[1].sup
 
-                 elif isinstance(V[1], Range):
 
-                     if not discrete:
 
-                         raise TypeError(err_msg)
 
-                     lo = V[1].inf
 
-                     hi = V[1].sup
 
-                     dx = abs(V[1].step)  # direction doesn't matter
 
-                     if dx == 1:
 
-                         V[1:] = [lo, hi]
 
-                     else:
 
-                         if lo is not S.NegativeInfinity:
 
-                             V = [V[0]] + [0, (hi - lo)//dx, dx*V[0] + lo]
 
-                         else:
 
-                             V = [V[0]] + [0, S.Infinity, -dx*V[0] + hi]
 
-                 else:
 
-                     # more complicated sets would require splitting, e.g.
 
-                     # Union(Interval(1, 3), interval(6,10))
 
-                     raise NotImplementedError(
 
-                         'expecting Range' if discrete else
 
-                         'Relational or single Interval' )
 
-             V = sympify(flatten(V))  # list of sympified elements/None
 
-             if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False):
 
-                 newsymbol = V[0]
 
-                 if len(V) == 3:
 
-                     # general case
 
-                     if V[2] is None and V[1] is not None:
 
-                         orientation *= -1
 
-                     V = [newsymbol] + [i for i in V[1:] if i is not None]
 
-                 lenV = len(V)
 
-                 if not isinstance(newsymbol, Idx) or lenV == 3:
 
-                     if lenV == 4:
 
-                         limits.append(Tuple(*V))
 
-                         continue
 
-                     if lenV == 3:
 
-                         if isinstance(newsymbol, Idx):
 
-                             # Idx represents an integer which may have
 
-                             # specified values it can take on; if it is
 
-                             # given such a value, an error is raised here
 
-                             # if the summation would try to give it a larger
 
-                             # or smaller value than permitted. None and Symbolic
 
-                             # values will not raise an error.
 
-                             lo, hi = newsymbol.lower, newsymbol.upper
 
-                             try:
 
-                                 if lo is not None and not bool(V[1] >= lo):
 
-                                     raise ValueError("Summation will set Idx value too low.")
 
-                             except TypeError:
 
-                                 pass
 
-                             try:
 
-                                 if hi is not None and not bool(V[2] <= hi):
 
-                                     raise ValueError("Summation will set Idx value too high.")
 
-                             except TypeError:
 
-                                 pass
 
-                         limits.append(Tuple(*V))
 
-                         continue
 
-                     if lenV == 1 or (lenV == 2 and V[1] is None):
 
-                         limits.append(Tuple(newsymbol))
 
-                         continue
 
-                     elif lenV == 2:
 
-                         limits.append(Tuple(newsymbol, V[1]))
 
-                         continue
 
-         raise ValueError('Invalid limits given: %s' % str(symbols))
 
-     return limits, orientation
 
- class ExprWithLimits(Expr):
 
-     __slots__ = ('is_commutative',)
 
-     def __new__(cls, function, *symbols, **assumptions):
 
-         from sympy.concrete.products import Product
 
-         pre = _common_new(cls, function, *symbols,
 
-             discrete=issubclass(cls, Product), **assumptions)
 
-         if isinstance(pre, tuple):
 
-             function, limits, _ = pre
 
-         else:
 
-             return pre
 
-         # limits must have upper and lower bounds; the indefinite form
 
-         # is not supported. This restriction does not apply to AddWithLimits
 
-         if any(len(l) != 3 or None in l for l in limits):
 
-             raise ValueError('ExprWithLimits requires values for lower and upper bounds.')
 
-         obj = Expr.__new__(cls, **assumptions)
 
-         arglist = [function]
 
-         arglist.extend(limits)
 
-         obj._args = tuple(arglist)
 
-         obj.is_commutative = function.is_commutative  # limits already checked
 
-         return obj
 
-     @property
 
-     def function(self):
 
-         """Return the function applied across limits.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Integral
 
-         >>> from sympy.abc import x
 
-         >>> Integral(x**2, (x,)).function
 
-         x**2
 
-         See Also
 
-         ========
 
-         limits, variables, free_symbols
 
-         """
 
-         return self._args[0]
 
-     @property
 
-     def kind(self):
 
-         return self.function.kind
 
-     @property
 
-     def limits(self):
 
-         """Return the limits of expression.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Integral
 
-         >>> from sympy.abc import x, i
 
-         >>> Integral(x**i, (i, 1, 3)).limits
 
-         ((i, 1, 3),)
 
-         See Also
 
-         ========
 
-         function, variables, free_symbols
 
-         """
 
-         return self._args[1:]
 
-     @property
 
-     def variables(self):
 
-         """Return a list of the limit variables.
 
-         >>> from sympy import Sum
 
-         >>> from sympy.abc import x, i
 
-         >>> Sum(x**i, (i, 1, 3)).variables
 
-         [i]
 
-         See Also
 
-         ========
 
-         function, limits, free_symbols
 
-         as_dummy : Rename dummy variables
 
-         sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable
 
-         """
 
-         return [l[0] for l in self.limits]
 
-     @property
 
-     def bound_symbols(self):
 
-         """Return only variables that are dummy variables.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Integral
 
-         >>> from sympy.abc import x, i, j, k
 
-         >>> Integral(x**i, (i, 1, 3), (j, 2), k).bound_symbols
 
-         [i, j]
 
-         See Also
 
-         ========
 
-         function, limits, free_symbols
 
-         as_dummy : Rename dummy variables
 
-         sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable
 
-         """
 
-         return [l[0] for l in self.limits if len(l) != 1]
 
-     @property
 
-     def free_symbols(self):
 
-         """
 
-         This method returns the symbols in the object, excluding those
 
-         that take on a specific value (i.e. the dummy symbols).
 
-         Examples
 
-         ========
 
-         >>> from sympy import Sum
 
-         >>> from sympy.abc import x, y
 
-         >>> Sum(x, (x, y, 1)).free_symbols
 
-         {y}
 
-         """
 
-         # don't test for any special values -- nominal free symbols
 
-         # should be returned, e.g. don't return set() if the
 
-         # function is zero -- treat it like an unevaluated expression.
 
-         function, limits = self.function, self.limits
 
-         # mask off non-symbol integration variables that have
 
-         # more than themself as a free symbol
 
-         reps = {i[0]: i[0] if i[0].free_symbols == {i[0]} else Dummy()
 
-             for i in self.limits}
 
-         function = function.xreplace(reps)
 
-         isyms = function.free_symbols
 
-         for xab in limits:
 
-             v = reps[xab[0]]
 
-             if len(xab) == 1:
 
-                 isyms.add(v)
 
-                 continue
 
-             # take out the target symbol
 
-             if v in isyms:
 
-                 isyms.remove(v)
 
-             # add in the new symbols
 
-             for i in xab[1:]:
 
-                 isyms.update(i.free_symbols)
 
-         reps = {v: k for k, v in reps.items()}
 
-         return {reps.get(_, _) for _ in isyms}
 
-     @property
 
-     def is_number(self):
 
-         """Return True if the Sum has no free symbols, else False."""
 
-         return not self.free_symbols
 
-     def _eval_interval(self, x, a, b):
 
-         limits = [(i if i[0] != x else (x, a, b)) for i in self.limits]
 
-         integrand = self.function
 
-         return self.func(integrand, *limits)
 
-     def _eval_subs(self, old, new):
 
-         """
 
-         Perform substitutions over non-dummy variables
 
-         of an expression with limits.  Also, can be used
 
-         to specify point-evaluation of an abstract antiderivative.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Sum, oo
 
-         >>> from sympy.abc import s, n
 
-         >>> Sum(1/n**s, (n, 1, oo)).subs(s, 2)
 
-         Sum(n**(-2), (n, 1, oo))
 
-         >>> from sympy import Integral
 
-         >>> from sympy.abc import x, a
 
-         >>> Integral(a*x**2, x).subs(x, 4)
 
-         Integral(a*x**2, (x, 4))
 
-         See Also
 
-         ========
 
-         variables : Lists the integration variables
 
-         transform : Perform mapping on the dummy variable for integrals
 
-         change_index : Perform mapping on the sum and product dummy variables
 
-         """
 
-         func, limits = self.function, list(self.limits)
 
-         # If one of the expressions we are replacing is used as a func index
 
-         # one of two things happens.
 
-         #   - the old variable first appears as a free variable
 
-         #     so we perform all free substitutions before it becomes
 
-         #     a func index.
 
-         #   - the old variable first appears as a func index, in
 
-         #     which case we ignore.  See change_index.
 
-         # Reorder limits to match standard mathematical practice for scoping
 
-         limits.reverse()
 
-         if not isinstance(old, Symbol) or \
 
-                 old.free_symbols.intersection(self.free_symbols):
 
-             sub_into_func = True
 
-             for i, xab in enumerate(limits):
 
-                 if 1 == len(xab) and old == xab[0]:
 
-                     if new._diff_wrt:
 
-                         xab = (new,)
 
-                     else:
 
-                         xab = (old, old)
 
-                 limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]])
 
-                 if len(xab[0].free_symbols.intersection(old.free_symbols)) != 0:
 
-                     sub_into_func = False
 
-                     break
 
-             if isinstance(old, (AppliedUndef, UndefinedFunction)):
 
-                 sy2 = set(self.variables).intersection(set(new.atoms(Symbol)))
 
-                 sy1 = set(self.variables).intersection(set(old.args))
 
-                 if not sy2.issubset(sy1):
 
-                     raise ValueError(
 
-                         "substitution cannot create dummy dependencies")
 
-                 sub_into_func = True
 
-             if sub_into_func:
 
-                 func = func.subs(old, new)
 
-         else:
 
-             # old is a Symbol and a dummy variable of some limit
 
-             for i, xab in enumerate(limits):
 
-                 if len(xab) == 3:
 
-                     limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]])
 
-                     if old == xab[0]:
 
-                         break
 
-         # simplify redundant limits (x, x)  to (x, )
 
-         for i, xab in enumerate(limits):
 
-             if len(xab) == 2 and (xab[0] - xab[1]).is_zero:
 
-                 limits[i] = Tuple(xab[0], )
 
-         # Reorder limits back to representation-form
 
-         limits.reverse()
 
-         return self.func(func, *limits)
 
-     @property
 
-     def has_finite_limits(self):
 
-         """
 
-         Returns True if the limits are known to be finite, either by the
 
-         explicit bounds, assumptions on the bounds, or assumptions on the
 
-         variables.  False if known to be infinite, based on the bounds.
 
-         None if not enough information is available to determine.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Sum, Integral, Product, oo, Symbol
 
-         >>> x = Symbol('x')
 
-         >>> Sum(x, (x, 1, 8)).has_finite_limits
 
-         True
 
-         >>> Integral(x, (x, 1, oo)).has_finite_limits
 
-         False
 
-         >>> M = Symbol('M')
 
-         >>> Sum(x, (x, 1, M)).has_finite_limits
 
-         >>> N = Symbol('N', integer=True)
 
-         >>> Product(x, (x, 1, N)).has_finite_limits
 
-         True
 
-         See Also
 
-         ========
 
-         has_reversed_limits
 
-         """
 
-         ret_None = False
 
-         for lim in self.limits:
 
-             if len(lim) == 3:
 
-                 if any(l.is_infinite for l in lim[1:]):
 
-                     # Any of the bounds are +/-oo
 
-                     return False
 
-                 elif any(l.is_infinite is None for l in lim[1:]):
 
-                     # Maybe there are assumptions on the variable?
 
-                     if lim[0].is_infinite is None:
 
-                         ret_None = True
 
-             else:
 
-                 if lim[0].is_infinite is None:
 
-                     ret_None = True
 
-         if ret_None:
 
-             return None
 
-         return True
 
-     @property
 
-     def has_reversed_limits(self):
 
-         """
 
-         Returns True if the limits are known to be in reversed order, either
 
-         by the explicit bounds, assumptions on the bounds, or assumptions on the
 
-         variables.  False if known to be in normal order, based on the bounds.
 
-         None if not enough information is available to determine.
 
-         Examples
 
-         ========
 
-         >>> from sympy import Sum, Integral, Product, oo, Symbol
 
-         >>> x = Symbol('x')
 
-         >>> Sum(x, (x, 8, 1)).has_reversed_limits
 
-         True
 
-         >>> Sum(x, (x, 1, oo)).has_reversed_limits
 
-         False
 
-         >>> M = Symbol('M')
 
-         >>> Integral(x, (x, 1, M)).has_reversed_limits
 
-         >>> N = Symbol('N', integer=True, positive=True)
 
-         >>> Sum(x, (x, 1, N)).has_reversed_limits
 
-         False
 
-         >>> Product(x, (x, 2, N)).has_reversed_limits
 
-         >>> Product(x, (x, 2, N)).subs(N, N + 2).has_reversed_limits
 
-         False
 
-         See Also
 
-         ========
 
-         sympy.concrete.expr_with_intlimits.ExprWithIntLimits.has_empty_sequence
 
-         """
 
-         ret_None = False
 
-         for lim in self.limits:
 
-             if len(lim) == 3:
 
-                 var, a, b = lim
 
-                 dif = b - a
 
-                 if dif.is_extended_negative:
 
-                     return True
 
-                 elif dif.is_extended_nonnegative:
 
-                     continue
 
-                 else:
 
-                     ret_None = True
 
-             else:
 
-                 return None
 
-         if ret_None:
 
-             return None
 
-         return False
 
- class AddWithLimits(ExprWithLimits):
 
-     r"""Represents unevaluated oriented additions.
 
-         Parent class for Integral and Sum.
 
-     """
 
-     __slots__ = ()
 
-     def __new__(cls, function, *symbols, **assumptions):
 
-         from sympy.concrete.summations import Sum
 
-         pre = _common_new(cls, function, *symbols,
 
-             discrete=issubclass(cls, Sum), **assumptions)
 
-         if isinstance(pre, tuple):
 
-             function, limits, orientation = pre
 
-         else:
 
-             return pre
 
-         obj = Expr.__new__(cls, **assumptions)
 
-         arglist = [orientation*function]  # orientation not used in ExprWithLimits
 
-         arglist.extend(limits)
 
-         obj._args = tuple(arglist)
 
-         obj.is_commutative = function.is_commutative  # limits already checked
 
-         return obj
 
-     def _eval_adjoint(self):
 
-         if all(x.is_real for x in flatten(self.limits)):
 
-             return self.func(self.function.adjoint(), *self.limits)
 
-         return None
 
-     def _eval_conjugate(self):
 
-         if all(x.is_real for x in flatten(self.limits)):
 
-             return self.func(self.function.conjugate(), *self.limits)
 
-         return None
 
-     def _eval_transpose(self):
 
-         if all(x.is_real for x in flatten(self.limits)):
 
-             return self.func(self.function.transpose(), *self.limits)
 
-         return None
 
-     def _eval_factor(self, **hints):
 
-         if 1 == len(self.limits):
 
-             summand = self.function.factor(**hints)
 
-             if summand.is_Mul:
 
-                 out = sift(summand.args, lambda w: w.is_commutative \
 
-                     and not set(self.variables) & w.free_symbols)
 
-                 return Mul(*out[True])*self.func(Mul(*out[False]), \
 
-                     *self.limits)
 
-         else:
 
-             summand = self.func(self.function, *self.limits[0:-1]).factor()
 
-             if not summand.has(self.variables[-1]):
 
-                 return self.func(1, [self.limits[-1]]).doit()*summand
 
-             elif isinstance(summand, Mul):
 
-                 return self.func(summand, self.limits[-1]).factor()
 
-         return self
 
-     def _eval_expand_basic(self, **hints):
 
-         summand = self.function.expand(**hints)
 
-         force = hints.get('force', False)
 
-         if (summand.is_Add and (force or summand.is_commutative and
 
-                  self.has_finite_limits is not False)):
 
-             return Add(*[self.func(i, *self.limits) for i in summand.args])
 
-         elif isinstance(summand, MatrixBase):
 
-             return summand.applyfunc(lambda x: self.func(x, *self.limits))
 
-         elif summand != self.function:
 
-             return self.func(summand, *self.limits)
 
-         return self
 
 
  |