Initialisation du repository de Beta
This commit is contained in:
commit
14985f6dbb
9469 changed files with 1903273 additions and 0 deletions
|
|
@ -0,0 +1,354 @@
|
|||
from sympy.concrete.expr_with_limits import ExprWithLimits
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.relational import Eq
|
||||
|
||||
class ReorderError(NotImplementedError):
|
||||
"""
|
||||
Exception raised when trying to reorder dependent limits.
|
||||
"""
|
||||
def __init__(self, expr, msg):
|
||||
super().__init__(
|
||||
"%s could not be reordered: %s." % (expr, msg))
|
||||
|
||||
class ExprWithIntLimits(ExprWithLimits):
|
||||
"""
|
||||
Superclass for Product and Sum.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.concrete.expr_with_limits.ExprWithLimits
|
||||
sympy.concrete.products.Product
|
||||
sympy.concrete.summations.Sum
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def change_index(self, var, trafo, newvar=None):
|
||||
r"""
|
||||
Change index of a Sum or Product.
|
||||
|
||||
Perform a linear transformation `x \mapsto a x + b` on the index variable
|
||||
`x`. For `a` the only values allowed are `\pm 1`. A new variable to be used
|
||||
after the change of index can also be specified.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the
|
||||
index variable `x` to transform. The transformation ``trafo`` must be linear
|
||||
and given in terms of ``var``. If the optional argument ``newvar`` is
|
||||
provided then ``var`` gets replaced by ``newvar`` in the final expression.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Sum, Product, simplify
|
||||
>>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l
|
||||
|
||||
>>> S = Sum(x, (x, a, b))
|
||||
>>> S.doit()
|
||||
-a**2/2 + a/2 + b**2/2 + b/2
|
||||
|
||||
>>> Sn = S.change_index(x, x + 1, y)
|
||||
>>> Sn
|
||||
Sum(y - 1, (y, a + 1, b + 1))
|
||||
>>> Sn.doit()
|
||||
-a**2/2 + a/2 + b**2/2 + b/2
|
||||
|
||||
>>> Sn = S.change_index(x, -x, y)
|
||||
>>> Sn
|
||||
Sum(-y, (y, -b, -a))
|
||||
>>> Sn.doit()
|
||||
-a**2/2 + a/2 + b**2/2 + b/2
|
||||
|
||||
>>> Sn = S.change_index(x, x+u)
|
||||
>>> Sn
|
||||
Sum(-u + x, (x, a + u, b + u))
|
||||
>>> Sn.doit()
|
||||
-a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
|
||||
>>> simplify(Sn.doit())
|
||||
-a**2/2 + a/2 + b**2/2 + b/2
|
||||
|
||||
>>> Sn = S.change_index(x, -x - u, y)
|
||||
>>> Sn
|
||||
Sum(-u - y, (y, -b - u, -a - u))
|
||||
>>> Sn.doit()
|
||||
-a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
|
||||
>>> simplify(Sn.doit())
|
||||
-a**2/2 + a/2 + b**2/2 + b/2
|
||||
|
||||
>>> P = Product(i*j**2, (i, a, b), (j, c, d))
|
||||
>>> P
|
||||
Product(i*j**2, (i, a, b), (j, c, d))
|
||||
>>> P2 = P.change_index(i, i+3, k)
|
||||
>>> P2
|
||||
Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d))
|
||||
>>> P3 = P2.change_index(j, -j, l)
|
||||
>>> P3
|
||||
Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c))
|
||||
|
||||
When dealing with symbols only, we can make a
|
||||
general linear transformation:
|
||||
|
||||
>>> Sn = S.change_index(x, u*x+v, y)
|
||||
>>> Sn
|
||||
Sum((-v + y)/u, (y, b*u + v, a*u + v))
|
||||
>>> Sn.doit()
|
||||
-v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u
|
||||
>>> simplify(Sn.doit())
|
||||
a**2*u/2 + a/2 - b**2*u/2 + b/2
|
||||
|
||||
However, the last result can be inconsistent with usual
|
||||
summation where the index increment is always 1. This is
|
||||
obvious as we get back the original value only for ``u``
|
||||
equal +1 or -1.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index,
|
||||
reorder_limit,
|
||||
sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder,
|
||||
sympy.concrete.summations.Sum.reverse_order,
|
||||
sympy.concrete.products.Product.reverse_order
|
||||
"""
|
||||
if newvar is None:
|
||||
newvar = var
|
||||
|
||||
limits = []
|
||||
for limit in self.limits:
|
||||
if limit[0] == var:
|
||||
p = trafo.as_poly(var)
|
||||
if p.degree() != 1:
|
||||
raise ValueError("Index transformation is not linear")
|
||||
alpha = p.coeff_monomial(var)
|
||||
beta = p.coeff_monomial(S.One)
|
||||
if alpha.is_number:
|
||||
if alpha == S.One:
|
||||
limits.append((newvar, alpha*limit[1] + beta, alpha*limit[2] + beta))
|
||||
elif alpha == S.NegativeOne:
|
||||
limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta))
|
||||
else:
|
||||
raise ValueError("Linear transformation results in non-linear summation stepsize")
|
||||
else:
|
||||
# Note that the case of alpha being symbolic can give issues if alpha < 0.
|
||||
limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta))
|
||||
else:
|
||||
limits.append(limit)
|
||||
|
||||
function = self.function.subs(var, (var - beta)/alpha)
|
||||
function = function.subs(var, newvar)
|
||||
|
||||
return self.func(function, *limits)
|
||||
|
||||
|
||||
def index(expr, x):
|
||||
"""
|
||||
Return the index of a dummy variable in the list of limits.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``index(expr, x)`` returns the index of the dummy variable ``x`` in the
|
||||
limits of ``expr``. Note that we start counting with 0 at the inner-most
|
||||
limits tuple.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.abc import x, y, a, b, c, d
|
||||
>>> from sympy import Sum, Product
|
||||
>>> Sum(x*y, (x, a, b), (y, c, d)).index(x)
|
||||
0
|
||||
>>> Sum(x*y, (x, a, b), (y, c, d)).index(y)
|
||||
1
|
||||
>>> Product(x*y, (x, a, b), (y, c, d)).index(x)
|
||||
0
|
||||
>>> Product(x*y, (x, a, b), (y, c, d)).index(y)
|
||||
1
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
reorder_limit, reorder, sympy.concrete.summations.Sum.reverse_order,
|
||||
sympy.concrete.products.Product.reverse_order
|
||||
"""
|
||||
variables = [limit[0] for limit in expr.limits]
|
||||
|
||||
if variables.count(x) != 1:
|
||||
raise ValueError(expr, "Number of instances of variable not equal to one")
|
||||
else:
|
||||
return variables.index(x)
|
||||
|
||||
def reorder(expr, *arg):
|
||||
"""
|
||||
Reorder limits in a expression containing a Sum or a Product.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``expr.reorder(*arg)`` reorders the limits in the expression ``expr``
|
||||
according to the list of tuples given by ``arg``. These tuples can
|
||||
contain numerical indices or index variable names or involve both.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Sum, Product
|
||||
>>> from sympy.abc import x, y, z, a, b, c, d, e, f
|
||||
|
||||
>>> Sum(x*y, (x, a, b), (y, c, d)).reorder((x, y))
|
||||
Sum(x*y, (y, c, d), (x, a, b))
|
||||
|
||||
>>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder((x, y), (x, z), (y, z))
|
||||
Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b))
|
||||
|
||||
>>> P = Product(x*y*z, (x, a, b), (y, c, d), (z, e, f))
|
||||
>>> P.reorder((x, y), (x, z), (y, z))
|
||||
Product(x*y*z, (z, e, f), (y, c, d), (x, a, b))
|
||||
|
||||
We can also select the index variables by counting them, starting
|
||||
with the inner-most one:
|
||||
|
||||
>>> Sum(x**2, (x, a, b), (x, c, d)).reorder((0, 1))
|
||||
Sum(x**2, (x, c, d), (x, a, b))
|
||||
|
||||
And of course we can mix both schemes:
|
||||
|
||||
>>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, x))
|
||||
Sum(x*y, (y, c, d), (x, a, b))
|
||||
>>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, 0))
|
||||
Sum(x*y, (y, c, d), (x, a, b))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
reorder_limit, index, sympy.concrete.summations.Sum.reverse_order,
|
||||
sympy.concrete.products.Product.reverse_order
|
||||
"""
|
||||
new_expr = expr
|
||||
|
||||
for r in arg:
|
||||
if len(r) != 2:
|
||||
raise ValueError(r, "Invalid number of arguments")
|
||||
|
||||
index1 = r[0]
|
||||
index2 = r[1]
|
||||
|
||||
if not isinstance(r[0], int):
|
||||
index1 = expr.index(r[0])
|
||||
if not isinstance(r[1], int):
|
||||
index2 = expr.index(r[1])
|
||||
|
||||
new_expr = new_expr.reorder_limit(index1, index2)
|
||||
|
||||
return new_expr
|
||||
|
||||
|
||||
def reorder_limit(expr, x, y):
|
||||
"""
|
||||
Interchange two limit tuples of a Sum or Product expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``expr.reorder_limit(x, y)`` interchanges two limit tuples. The
|
||||
arguments ``x`` and ``y`` are integers corresponding to the index
|
||||
variables of the two limits which are to be interchanged. The
|
||||
expression ``expr`` has to be either a Sum or a Product.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.abc import x, y, z, a, b, c, d, e, f
|
||||
>>> from sympy import Sum, Product
|
||||
|
||||
>>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2)
|
||||
Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b))
|
||||
>>> Sum(x**2, (x, a, b), (x, c, d)).reorder_limit(1, 0)
|
||||
Sum(x**2, (x, c, d), (x, a, b))
|
||||
|
||||
>>> Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2)
|
||||
Product(x*y*z, (z, e, f), (y, c, d), (x, a, b))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
index, reorder, sympy.concrete.summations.Sum.reverse_order,
|
||||
sympy.concrete.products.Product.reverse_order
|
||||
"""
|
||||
var = {limit[0] for limit in expr.limits}
|
||||
limit_x = expr.limits[x]
|
||||
limit_y = expr.limits[y]
|
||||
|
||||
if (len(set(limit_x[1].free_symbols).intersection(var)) == 0 and
|
||||
len(set(limit_x[2].free_symbols).intersection(var)) == 0 and
|
||||
len(set(limit_y[1].free_symbols).intersection(var)) == 0 and
|
||||
len(set(limit_y[2].free_symbols).intersection(var)) == 0):
|
||||
|
||||
limits = []
|
||||
for i, limit in enumerate(expr.limits):
|
||||
if i == x:
|
||||
limits.append(limit_y)
|
||||
elif i == y:
|
||||
limits.append(limit_x)
|
||||
else:
|
||||
limits.append(limit)
|
||||
|
||||
return type(expr)(expr.function, *limits)
|
||||
else:
|
||||
raise ReorderError(expr, "could not interchange the two limits specified")
|
||||
|
||||
@property
|
||||
def has_empty_sequence(self):
|
||||
"""
|
||||
Returns True if the Sum or Product is computed for an empty sequence.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Sum, Product, Symbol
|
||||
>>> m = Symbol('m')
|
||||
>>> Sum(m, (m, 1, 0)).has_empty_sequence
|
||||
True
|
||||
|
||||
>>> Sum(m, (m, 1, 1)).has_empty_sequence
|
||||
False
|
||||
|
||||
>>> M = Symbol('M', integer=True, positive=True)
|
||||
>>> Product(m, (m, 1, M)).has_empty_sequence
|
||||
False
|
||||
|
||||
>>> Product(m, (m, 2, M)).has_empty_sequence
|
||||
|
||||
>>> Product(m, (m, M + 1, M)).has_empty_sequence
|
||||
True
|
||||
|
||||
>>> N = Symbol('N', integer=True, positive=True)
|
||||
>>> Sum(m, (m, N, M)).has_empty_sequence
|
||||
|
||||
>>> N = Symbol('N', integer=True, negative=True)
|
||||
>>> Sum(m, (m, N, M)).has_empty_sequence
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
has_reversed_limits
|
||||
has_finite_limits
|
||||
|
||||
"""
|
||||
ret_None = False
|
||||
for lim in self.limits:
|
||||
dif = lim[1] - lim[2]
|
||||
eq = Eq(dif, 1)
|
||||
if eq == True:
|
||||
return True
|
||||
elif eq == False:
|
||||
continue
|
||||
else:
|
||||
ret_None = True
|
||||
|
||||
if ret_None:
|
||||
return None
|
||||
return False
|
||||
Loading…
Add table
Add a link
Reference in a new issue