Initialisation du repository de Beta
This commit is contained in:
commit
14985f6dbb
9469 changed files with 1903273 additions and 0 deletions
|
|
@ -0,0 +1,603 @@
|
|||
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.matrixbase 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue