I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1 @@
# Stub __init__.py for sympy.functions.elementary

View File

@ -0,0 +1,261 @@
r"""A module for special angle formulas for trigonometric functions
TODO
====
This module should be developed in the future to contain direct square root
representation of
.. math
F(\frac{n}{m} \pi)
for every
- $m \in \{ 3, 5, 17, 257, 65537 \}$
- $n \in \mathbb{N}$, $0 \le n < m$
- $F \in \{\sin, \cos, \tan, \csc, \sec, \cot\}$
Without multi-step rewrites
(e.g. $\tan \to \cos/\sin \to \cos/\sqrt \to \ sqrt$)
or using chebyshev identities
(e.g. $\cos \to \cos + \cos^2 + \cdots \to \sqrt{} + \sqrt{}^2 + \cdots $),
which are trivial to implement in sympy,
and had used to give overly complicated expressions.
The reference can be found below, if anyone may need help implementing them.
References
==========
.. [*] Gottlieb, Christian. (1999). The Simple and straightforward construction
of the regular 257-gon. The Mathematical Intelligencer. 21. 31-37.
10.1007/BF03024829.
.. [*] https://resources.wolframcloud.com/FunctionRepository/resources/Cos2PiOverFermatPrime
"""
from __future__ import annotations
from typing import Callable
from functools import reduce
from sympy.core.expr import Expr
from sympy.core.singleton import S
from sympy.core.intfunc import igcdex
from sympy.core.numbers import Integer
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.core.cache import cacheit
def migcdex(*x: int) -> tuple[tuple[int, ...], int]:
r"""Compute extended gcd for multiple integers.
Explanation
===========
Given the integers $x_1, \cdots, x_n$ and
an extended gcd for multiple arguments are defined as a solution
$(y_1, \cdots, y_n), g$ for the diophantine equation
$x_1 y_1 + \cdots + x_n y_n = g$ such that
$g = \gcd(x_1, \cdots, x_n)$.
Examples
========
>>> from sympy.functions.elementary._trigonometric_special import migcdex
>>> migcdex()
((), 0)
>>> migcdex(4)
((1,), 4)
>>> migcdex(4, 6)
((-1, 1), 2)
>>> migcdex(6, 10, 15)
((1, 1, -1), 1)
"""
if not x:
return (), 0
if len(x) == 1:
return (1,), x[0]
if len(x) == 2:
u, v, h = igcdex(x[0], x[1])
return (u, v), h
y, g = migcdex(*x[1:])
u, v, h = igcdex(x[0], g)
return (u, *(v * i for i in y)), h
def ipartfrac(*denoms: int) -> tuple[int, ...]:
r"""Compute the partial fraction decomposition.
Explanation
===========
Given a rational number $\frac{1}{q_1 \cdots q_n}$ where all
$q_1, \cdots, q_n$ are pairwise coprime,
A partial fraction decomposition is defined as
.. math::
\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}
And it can be derived from solving the following diophantine equation for
the $p_1, \cdots, p_n$
.. math::
1 = p_1 \prod_{i \ne 1}q_i + \cdots + p_n \prod_{i \ne n}q_i
Where $q_1, \cdots, q_n$ being pairwise coprime implies
$\gcd(\prod_{i \ne 1}q_i, \cdots, \prod_{i \ne n}q_i) = 1$,
which guarantees the existence of the solution.
It is sufficient to compute partial fraction decomposition only
for numerator $1$ because partial fraction decomposition for any
$\frac{n}{q_1 \cdots q_n}$ can be easily computed by multiplying
the result by $n$ afterwards.
Parameters
==========
denoms : int
The pairwise coprime integer denominators $q_i$ which defines the
rational number $\frac{1}{q_1 \cdots q_n}$
Returns
=======
tuple[int, ...]
The list of numerators which semantically corresponds to $p_i$ of the
partial fraction decomposition
$\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}$
Examples
========
>>> from sympy import Rational, Mul
>>> from sympy.functions.elementary._trigonometric_special import ipartfrac
>>> denoms = 2, 3, 5
>>> numers = ipartfrac(2, 3, 5)
>>> numers
(1, 7, -14)
>>> Rational(1, Mul(*denoms))
1/30
>>> out = 0
>>> for n, d in zip(numers, denoms):
... out += Rational(n, d)
>>> out
1/30
"""
if not denoms:
return ()
def mul(x: int, y: int) -> int:
return x * y
denom = reduce(mul, denoms)
a = [denom // x for x in denoms]
h, _ = migcdex(*a)
return h
def fermat_coords(n: int) -> list[int] | None:
"""If n can be factored in terms of Fermat primes with
multiplicity of each being 1, return those primes, else
None
"""
primes = []
for p in [3, 5, 17, 257, 65537]:
quotient, remainder = divmod(n, p)
if remainder == 0:
n = quotient
primes.append(p)
if n == 1:
return primes
return None
@cacheit
def cos_3() -> Expr:
r"""Computes $\cos \frac{\pi}{3}$ in square roots"""
return S.Half
@cacheit
def cos_5() -> Expr:
r"""Computes $\cos \frac{\pi}{5}$ in square roots"""
return (sqrt(5) + 1) / 4
@cacheit
def cos_17() -> Expr:
r"""Computes $\cos \frac{\pi}{17}$ in square roots"""
return sqrt(
(15 + sqrt(17)) / 32 + sqrt(2) * (sqrt(17 - sqrt(17)) +
sqrt(sqrt(2) * (-8 * sqrt(17 + sqrt(17)) - (1 - sqrt(17))
* sqrt(17 - sqrt(17))) + 6 * sqrt(17) + 34)) / 32)
@cacheit
def cos_257() -> Expr:
r"""Computes $\cos \frac{\pi}{257}$ in square roots
References
==========
.. [*] https://math.stackexchange.com/questions/516142/how-does-cos2-pi-257-look-like-in-real-radicals
.. [*] https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
"""
def f1(a: Expr, b: Expr) -> tuple[Expr, Expr]:
return (a + sqrt(a**2 + b)) / 2, (a - sqrt(a**2 + b)) / 2
def f2(a: Expr, b: Expr) -> Expr:
return (a - sqrt(a**2 + b))/2
t1, t2 = f1(S.NegativeOne, Integer(256))
z1, z3 = f1(t1, Integer(64))
z2, z4 = f1(t2, Integer(64))
y1, y5 = f1(z1, 4*(5 + t1 + 2*z1))
y6, y2 = f1(z2, 4*(5 + t2 + 2*z2))
y3, y7 = f1(z3, 4*(5 + t1 + 2*z3))
y8, y4 = f1(z4, 4*(5 + t2 + 2*z4))
x1, x9 = f1(y1, -4*(t1 + y1 + y3 + 2*y6))
x2, x10 = f1(y2, -4*(t2 + y2 + y4 + 2*y7))
x3, x11 = f1(y3, -4*(t1 + y3 + y5 + 2*y8))
x4, x12 = f1(y4, -4*(t2 + y4 + y6 + 2*y1))
x5, x13 = f1(y5, -4*(t1 + y5 + y7 + 2*y2))
x6, x14 = f1(y6, -4*(t2 + y6 + y8 + 2*y3))
x15, x7 = f1(y7, -4*(t1 + y7 + y1 + 2*y4))
x8, x16 = f1(y8, -4*(t2 + y8 + y2 + 2*y5))
v1 = f2(x1, -4*(x1 + x2 + x3 + x6))
v2 = f2(x2, -4*(x2 + x3 + x4 + x7))
v3 = f2(x8, -4*(x8 + x9 + x10 + x13))
v4 = f2(x9, -4*(x9 + x10 + x11 + x14))
v5 = f2(x10, -4*(x10 + x11 + x12 + x15))
v6 = f2(x16, -4*(x16 + x1 + x2 + x5))
u1 = -f2(-v1, -4*(v2 + v3))
u2 = -f2(-v4, -4*(v5 + v6))
w1 = -2*f2(-u1, -4*u2)
return sqrt(sqrt(2)*sqrt(w1 + 4)/8 + S.Half)
def cos_table() -> dict[int, Callable[[], Expr]]:
r"""Lazily evaluated table for $\cos \frac{\pi}{n}$ in square roots for
$n \in \{3, 5, 17, 257, 65537\}$.
Notes
=====
65537 is the only other known Fermat prime and it is nearly impossible to
build in the current SymPy due to performance issues.
References
==========
https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
"""
return {
3: cos_3,
5: cos_5,
17: cos_17,
257: cos_257
}

View File

@ -0,0 +1,11 @@
from sympy.core.symbol import symbols
from sympy.functions.elementary.exponential import exp
x, y = symbols('x,y')
e = exp(2*x)
q = exp(3*x)
def timeit_exp_subs():
e.subs(q, y)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,645 @@
from typing import Tuple as tTuple
from sympy.core.basic import Basic
from sympy.core.expr import Expr
from sympy.core import Add, S
from sympy.core.evalf import get_integer_part, PrecisionExhausted
from sympy.core.function import Function
from sympy.core.logic import fuzzy_or
from sympy.core.numbers import Integer, int_valued
from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq
from sympy.core.sympify import _sympify
from sympy.functions.elementary.complexes import im, re
from sympy.multipledispatch import dispatch
###############################################################################
######################### FLOOR and CEILING FUNCTIONS #########################
###############################################################################
class RoundFunction(Function):
"""Abstract base class for rounding functions."""
args: tTuple[Expr]
@classmethod
def eval(cls, arg):
v = cls._eval_number(arg)
if v is not None:
return v
if arg.is_integer or arg.is_finite is False:
return arg
if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
i = im(arg)
if not i.has(S.ImaginaryUnit):
return cls(i)*S.ImaginaryUnit
return cls(arg, evaluate=False)
# Integral, numerical, symbolic part
ipart = npart = spart = S.Zero
# Extract integral (or complex integral) terms
intof = lambda x: int(x) if int_valued(x) else (
x if x.is_integer else None)
for t in Add.make_args(arg):
if t.is_imaginary and (i := intof(im(t))) is not None:
ipart += i*S.ImaginaryUnit
elif (i := intof(t)) is not None:
ipart += i
elif t.is_number:
npart += t
else:
spart += t
if not (npart or spart):
return ipart
# Evaluate npart numerically if independent of spart
if npart and (
not spart or
npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or
npart.is_imaginary and spart.is_real):
try:
r, i = get_integer_part(
npart, cls._dir, {}, return_ints=True)
ipart += Integer(r) + Integer(i)*S.ImaginaryUnit
npart = S.Zero
except (PrecisionExhausted, NotImplementedError):
pass
spart += npart
if not spart:
return ipart
elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real:
return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit
elif isinstance(spart, (floor, ceiling)):
return ipart + spart
else:
return ipart + cls(spart, evaluate=False)
@classmethod
def _eval_number(cls, arg):
raise NotImplementedError()
def _eval_is_finite(self):
return self.args[0].is_finite
def _eval_is_real(self):
return self.args[0].is_real
def _eval_is_integer(self):
return self.args[0].is_real
class floor(RoundFunction):
"""
Floor is a univariate function which returns the largest integer
value not greater than its argument. This implementation
generalizes floor to complex numbers by taking the floor of the
real and imaginary parts separately.
Examples
========
>>> from sympy import floor, E, I, S, Float, Rational
>>> floor(17)
17
>>> floor(Rational(23, 10))
2
>>> floor(2*E)
5
>>> floor(-Float(0.567))
-1
>>> floor(-I/2)
-I
>>> floor(S(5)/2 + 5*I/2)
2 + 2*I
See Also
========
sympy.functions.elementary.integers.ceiling
References
==========
.. [1] "Concrete mathematics" by Graham, pp. 87
.. [2] https://mathworld.wolfram.com/FloorFunction.html
"""
_dir = -1
@classmethod
def _eval_number(cls, arg):
if arg.is_Number:
return arg.floor()
elif any(isinstance(i, j)
for i in (arg, -arg) for j in (floor, ceiling)):
return arg
if arg.is_NumberSymbol:
return arg.approximation_interval(Integer)[0]
def _eval_as_leading_term(self, x, logx=None, cdir=0):
from sympy.calculus.accumulationbounds import AccumBounds
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0 is S.NaN or isinstance(arg0, AccumBounds):
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
r = floor(arg0)
if arg0.is_finite:
if arg0 == r:
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
if ndir.is_negative:
return r - 1
elif ndir.is_positive:
return r
else:
raise NotImplementedError("Not sure of sign of %s" % ndir)
else:
return r
return arg.as_leading_term(x, logx=logx, cdir=cdir)
def _eval_nseries(self, x, n, logx, cdir=0):
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0 is S.NaN:
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
r = floor(arg0)
if arg0.is_infinite:
from sympy.calculus.accumulationbounds import AccumBounds
from sympy.series.order import Order
s = arg._eval_nseries(x, n, logx, cdir)
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0)
return s + o
if arg0 == r:
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
if ndir.is_negative:
return r - 1
elif ndir.is_positive:
return r
else:
raise NotImplementedError("Not sure of sign of %s" % ndir)
else:
return r
def _eval_is_negative(self):
return self.args[0].is_negative
def _eval_is_nonnegative(self):
return self.args[0].is_nonnegative
def _eval_rewrite_as_ceiling(self, arg, **kwargs):
return -ceiling(-arg)
def _eval_rewrite_as_frac(self, arg, **kwargs):
return arg - frac(arg)
def __le__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] < other + 1
if other.is_number and other.is_real:
return self.args[0] < ceiling(other)
if self.args[0] == other and other.is_real:
return S.true
if other is S.Infinity and self.is_finite:
return S.true
return Le(self, other, evaluate=False)
def __ge__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] >= other
if other.is_number and other.is_real:
return self.args[0] >= ceiling(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.NegativeInfinity and self.is_finite:
return S.true
return Ge(self, other, evaluate=False)
def __gt__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] >= other + 1
if other.is_number and other.is_real:
return self.args[0] >= ceiling(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.NegativeInfinity and self.is_finite:
return S.true
return Gt(self, other, evaluate=False)
def __lt__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] < other
if other.is_number and other.is_real:
return self.args[0] < ceiling(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.Infinity and self.is_finite:
return S.true
return Lt(self, other, evaluate=False)
@dispatch(floor, Expr)
def _eval_is_eq(lhs, rhs): # noqa:F811
return is_eq(lhs.rewrite(ceiling), rhs) or \
is_eq(lhs.rewrite(frac),rhs)
class ceiling(RoundFunction):
"""
Ceiling is a univariate function which returns the smallest integer
value not less than its argument. This implementation
generalizes ceiling to complex numbers by taking the ceiling of the
real and imaginary parts separately.
Examples
========
>>> from sympy import ceiling, E, I, S, Float, Rational
>>> ceiling(17)
17
>>> ceiling(Rational(23, 10))
3
>>> ceiling(2*E)
6
>>> ceiling(-Float(0.567))
0
>>> ceiling(I/2)
I
>>> ceiling(S(5)/2 + 5*I/2)
3 + 3*I
See Also
========
sympy.functions.elementary.integers.floor
References
==========
.. [1] "Concrete mathematics" by Graham, pp. 87
.. [2] https://mathworld.wolfram.com/CeilingFunction.html
"""
_dir = 1
@classmethod
def _eval_number(cls, arg):
if arg.is_Number:
return arg.ceiling()
elif any(isinstance(i, j)
for i in (arg, -arg) for j in (floor, ceiling)):
return arg
if arg.is_NumberSymbol:
return arg.approximation_interval(Integer)[1]
def _eval_as_leading_term(self, x, logx=None, cdir=0):
from sympy.calculus.accumulationbounds import AccumBounds
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0 is S.NaN or isinstance(arg0, AccumBounds):
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
r = ceiling(arg0)
if arg0.is_finite:
if arg0 == r:
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
if ndir.is_negative:
return r
elif ndir.is_positive:
return r + 1
else:
raise NotImplementedError("Not sure of sign of %s" % ndir)
else:
return r
return arg.as_leading_term(x, logx=logx, cdir=cdir)
def _eval_nseries(self, x, n, logx, cdir=0):
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0 is S.NaN:
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
r = ceiling(arg0)
if arg0.is_infinite:
from sympy.calculus.accumulationbounds import AccumBounds
from sympy.series.order import Order
s = arg._eval_nseries(x, n, logx, cdir)
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1)
return s + o
if arg0 == r:
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
if ndir.is_negative:
return r
elif ndir.is_positive:
return r + 1
else:
raise NotImplementedError("Not sure of sign of %s" % ndir)
else:
return r
def _eval_rewrite_as_floor(self, arg, **kwargs):
return -floor(-arg)
def _eval_rewrite_as_frac(self, arg, **kwargs):
return arg + frac(-arg)
def _eval_is_positive(self):
return self.args[0].is_positive
def _eval_is_nonpositive(self):
return self.args[0].is_nonpositive
def __lt__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] <= other - 1
if other.is_number and other.is_real:
return self.args[0] <= floor(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.Infinity and self.is_finite:
return S.true
return Lt(self, other, evaluate=False)
def __gt__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] > other
if other.is_number and other.is_real:
return self.args[0] > floor(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.NegativeInfinity and self.is_finite:
return S.true
return Gt(self, other, evaluate=False)
def __ge__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] > other - 1
if other.is_number and other.is_real:
return self.args[0] > floor(other)
if self.args[0] == other and other.is_real:
return S.true
if other is S.NegativeInfinity and self.is_finite:
return S.true
return Ge(self, other, evaluate=False)
def __le__(self, other):
other = S(other)
if self.args[0].is_real:
if other.is_integer:
return self.args[0] <= other
if other.is_number and other.is_real:
return self.args[0] <= floor(other)
if self.args[0] == other and other.is_real:
return S.false
if other is S.Infinity and self.is_finite:
return S.true
return Le(self, other, evaluate=False)
@dispatch(ceiling, Basic) # type:ignore
def _eval_is_eq(lhs, rhs): # noqa:F811
return is_eq(lhs.rewrite(floor), rhs) or is_eq(lhs.rewrite(frac),rhs)
class frac(Function):
r"""Represents the fractional part of x
For real numbers it is defined [1]_ as
.. math::
x - \left\lfloor{x}\right\rfloor
Examples
========
>>> from sympy import Symbol, frac, Rational, floor, I
>>> frac(Rational(4, 3))
1/3
>>> frac(-Rational(4, 3))
2/3
returns zero for integer arguments
>>> n = Symbol('n', integer=True)
>>> frac(n)
0
rewrite as floor
>>> x = Symbol('x')
>>> frac(x).rewrite(floor)
x - floor(x)
for complex arguments
>>> r = Symbol('r', real=True)
>>> t = Symbol('t', real=True)
>>> frac(t + I*r)
I*frac(r) + frac(t)
See Also
========
sympy.functions.elementary.integers.floor
sympy.functions.elementary.integers.ceiling
References
===========
.. [1] https://en.wikipedia.org/wiki/Fractional_part
.. [2] https://mathworld.wolfram.com/FractionalPart.html
"""
@classmethod
def eval(cls, arg):
from sympy.calculus.accumulationbounds import AccumBounds
def _eval(arg):
if arg in (S.Infinity, S.NegativeInfinity):
return AccumBounds(0, 1)
if arg.is_integer:
return S.Zero
if arg.is_number:
if arg is S.NaN:
return S.NaN
elif arg is S.ComplexInfinity:
return S.NaN
else:
return arg - floor(arg)
return cls(arg, evaluate=False)
real, imag = S.Zero, S.Zero
for t in Add.make_args(arg):
# Two checks are needed for complex arguments
# see issue-7649 for details
if t.is_imaginary or (S.ImaginaryUnit*t).is_real:
i = im(t)
if not i.has(S.ImaginaryUnit):
imag += i
else:
real += t
else:
real += t
real = _eval(real)
imag = _eval(imag)
return real + S.ImaginaryUnit*imag
def _eval_rewrite_as_floor(self, arg, **kwargs):
return arg - floor(arg)
def _eval_rewrite_as_ceiling(self, arg, **kwargs):
return arg + ceiling(-arg)
def _eval_is_finite(self):
return True
def _eval_is_real(self):
return self.args[0].is_extended_real
def _eval_is_imaginary(self):
return self.args[0].is_imaginary
def _eval_is_integer(self):
return self.args[0].is_integer
def _eval_is_zero(self):
return fuzzy_or([self.args[0].is_zero, self.args[0].is_integer])
def _eval_is_negative(self):
return False
def __ge__(self, other):
if self.is_extended_real:
other = _sympify(other)
# Check if other <= 0
if other.is_extended_nonpositive:
return S.true
# Check if other >= 1
res = self._value_one_or_more(other)
if res is not None:
return not(res)
return Ge(self, other, evaluate=False)
def __gt__(self, other):
if self.is_extended_real:
other = _sympify(other)
# Check if other < 0
res = self._value_one_or_more(other)
if res is not None:
return not(res)
# Check if other >= 1
if other.is_extended_negative:
return S.true
return Gt(self, other, evaluate=False)
def __le__(self, other):
if self.is_extended_real:
other = _sympify(other)
# Check if other < 0
if other.is_extended_negative:
return S.false
# Check if other >= 1
res = self._value_one_or_more(other)
if res is not None:
return res
return Le(self, other, evaluate=False)
def __lt__(self, other):
if self.is_extended_real:
other = _sympify(other)
# Check if other <= 0
if other.is_extended_nonpositive:
return S.false
# Check if other >= 1
res = self._value_one_or_more(other)
if res is not None:
return res
return Lt(self, other, evaluate=False)
def _value_one_or_more(self, other):
if other.is_extended_real:
if other.is_number:
res = other >= 1
if res and not isinstance(res, Relational):
return S.true
if other.is_integer and other.is_positive:
return S.true
def _eval_as_leading_term(self, x, logx=None, cdir=0):
from sympy.calculus.accumulationbounds import AccumBounds
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0.is_finite:
if r.is_zero:
ndir = arg.dir(x, cdir=cdir)
if ndir.is_negative:
return S.One
return (arg - arg0).as_leading_term(x, logx=logx, cdir=cdir)
else:
return r
elif arg0 in (S.ComplexInfinity, S.Infinity, S.NegativeInfinity):
return AccumBounds(0, 1)
return arg.as_leading_term(x, logx=logx, cdir=cdir)
def _eval_nseries(self, x, n, logx, cdir=0):
from sympy.series.order import Order
arg = self.args[0]
arg0 = arg.subs(x, 0)
r = self.subs(x, 0)
if arg0.is_infinite:
from sympy.calculus.accumulationbounds import AccumBounds
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1) + Order(x**n, (x, 0))
return o
else:
res = (arg - arg0)._eval_nseries(x, n, logx=logx, cdir=cdir)
if r.is_zero:
ndir = arg.dir(x, cdir=cdir)
res += S.One if ndir.is_negative else S.Zero
else:
res += r
return res
@dispatch(frac, Basic) # type:ignore
def _eval_is_eq(lhs, rhs): # noqa:F811
if (lhs.rewrite(floor) == rhs) or \
(lhs.rewrite(ceiling) == rhs):
return True
# Check if other < 0
if rhs.is_extended_negative:
return False
# Check if other >= 1
res = lhs._value_one_or_more(rhs)
if res is not None:
return False

View File

@ -0,0 +1,915 @@
from sympy.core import Function, S, sympify, NumberKind
from sympy.utilities.iterables import sift
from sympy.core.add import Add
from sympy.core.containers import Tuple
from sympy.core.operations import LatticeOp, ShortCircuit
from sympy.core.function import (Application, Lambda,
ArgumentIndexError)
from sympy.core.expr import Expr
from sympy.core.exprtools import factor_terms
from sympy.core.mod import Mod
from sympy.core.mul import Mul
from sympy.core.numbers import Rational
from sympy.core.power import Pow
from sympy.core.relational import Eq, Relational
from sympy.core.singleton import Singleton
from sympy.core.sorting import ordered
from sympy.core.symbol import Dummy
from sympy.core.rules import Transform
from sympy.core.logic import fuzzy_and, fuzzy_or, _torf
from sympy.core.traversal import walk
from sympy.core.numbers import Integer
from sympy.logic.boolalg import And, Or
def _minmax_as_Piecewise(op, *args):
# helper for Min/Max rewrite as Piecewise
from sympy.functions.elementary.piecewise import Piecewise
ec = []
for i, a in enumerate(args):
c = [Relational(a, args[j], op) for j in range(i + 1, len(args))]
ec.append((a, And(*c)))
return Piecewise(*ec)
class IdentityFunction(Lambda, metaclass=Singleton):
"""
The identity function
Examples
========
>>> from sympy import Id, Symbol
>>> x = Symbol('x')
>>> Id(x)
x
"""
_symbol = Dummy('x')
@property
def signature(self):
return Tuple(self._symbol)
@property
def expr(self):
return self._symbol
Id = S.IdentityFunction
###############################################################################
############################# ROOT and SQUARE ROOT FUNCTION ###################
###############################################################################
def sqrt(arg, evaluate=None):
"""Returns the principal square root.
Parameters
==========
evaluate : bool, optional
The parameter determines if the expression should be evaluated.
If ``None``, its value is taken from
``global_parameters.evaluate``.
Examples
========
>>> from sympy import sqrt, Symbol, S
>>> x = Symbol('x')
>>> sqrt(x)
sqrt(x)
>>> sqrt(x)**2
x
Note that sqrt(x**2) does not simplify to x.
>>> sqrt(x**2)
sqrt(x**2)
This is because the two are not equal to each other in general.
For example, consider x == -1:
>>> from sympy import Eq
>>> Eq(sqrt(x**2), x).subs(x, -1)
False
This is because sqrt computes the principal square root, so the square may
put the argument in a different branch. This identity does hold if x is
positive:
>>> y = Symbol('y', positive=True)
>>> sqrt(y**2)
y
You can force this simplification by using the powdenest() function with
the force option set to True:
>>> from sympy import powdenest
>>> sqrt(x**2)
sqrt(x**2)
>>> powdenest(sqrt(x**2), force=True)
x
To get both branches of the square root you can use the rootof function:
>>> from sympy import rootof
>>> [rootof(x**2-3,i) for i in (0,1)]
[-sqrt(3), sqrt(3)]
Although ``sqrt`` is printed, there is no ``sqrt`` function so looking for
``sqrt`` in an expression will fail:
>>> from sympy.utilities.misc import func_name
>>> func_name(sqrt(x))
'Pow'
>>> sqrt(x).has(sqrt)
False
To find ``sqrt`` look for ``Pow`` with an exponent of ``1/2``:
>>> (x + 1/sqrt(x)).find(lambda i: i.is_Pow and abs(i.exp) is S.Half)
{1/sqrt(x)}
See Also
========
sympy.polys.rootoftools.rootof, root, real_root
References
==========
.. [1] https://en.wikipedia.org/wiki/Square_root
.. [2] https://en.wikipedia.org/wiki/Principal_value
"""
# arg = sympify(arg) is handled by Pow
return Pow(arg, S.Half, evaluate=evaluate)
def cbrt(arg, evaluate=None):
"""Returns the principal cube root.
Parameters
==========
evaluate : bool, optional
The parameter determines if the expression should be evaluated.
If ``None``, its value is taken from
``global_parameters.evaluate``.
Examples
========
>>> from sympy import cbrt, Symbol
>>> x = Symbol('x')
>>> cbrt(x)
x**(1/3)
>>> cbrt(x)**3
x
Note that cbrt(x**3) does not simplify to x.
>>> cbrt(x**3)
(x**3)**(1/3)
This is because the two are not equal to each other in general.
For example, consider `x == -1`:
>>> from sympy import Eq
>>> Eq(cbrt(x**3), x).subs(x, -1)
False
This is because cbrt computes the principal cube root, this
identity does hold if `x` is positive:
>>> y = Symbol('y', positive=True)
>>> cbrt(y**3)
y
See Also
========
sympy.polys.rootoftools.rootof, root, real_root
References
==========
.. [1] https://en.wikipedia.org/wiki/Cube_root
.. [2] https://en.wikipedia.org/wiki/Principal_value
"""
return Pow(arg, Rational(1, 3), evaluate=evaluate)
def root(arg, n, k=0, evaluate=None):
r"""Returns the *k*-th *n*-th root of ``arg``.
Parameters
==========
k : int, optional
Should be an integer in $\{0, 1, ..., n-1\}$.
Defaults to the principal root if $0$.
evaluate : bool, optional
The parameter determines if the expression should be evaluated.
If ``None``, its value is taken from
``global_parameters.evaluate``.
Examples
========
>>> from sympy import root, Rational
>>> from sympy.abc import x, n
>>> root(x, 2)
sqrt(x)
>>> root(x, 3)
x**(1/3)
>>> root(x, n)
x**(1/n)
>>> root(x, -Rational(2, 3))
x**(-3/2)
To get the k-th n-th root, specify k:
>>> root(-2, 3, 2)
-(-1)**(2/3)*2**(1/3)
To get all n n-th roots you can use the rootof function.
The following examples show the roots of unity for n
equal 2, 3 and 4:
>>> from sympy import rootof
>>> [rootof(x**2 - 1, i) for i in range(2)]
[-1, 1]
>>> [rootof(x**3 - 1,i) for i in range(3)]
[1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2]
>>> [rootof(x**4 - 1,i) for i in range(4)]
[-1, 1, -I, I]
SymPy, like other symbolic algebra systems, returns the
complex root of negative numbers. This is the principal
root and differs from the text-book result that one might
be expecting. For example, the cube root of -8 does not
come back as -2:
>>> root(-8, 3)
2*(-1)**(1/3)
The real_root function can be used to either make the principal
result real (or simply to return the real root directly):
>>> from sympy import real_root
>>> real_root(_)
-2
>>> real_root(-32, 5)
-2
Alternatively, the n//2-th n-th root of a negative number can be
computed with root:
>>> root(-32, 5, 5//2)
-2
See Also
========
sympy.polys.rootoftools.rootof
sympy.core.intfunc.integer_nthroot
sqrt, real_root
References
==========
.. [1] https://en.wikipedia.org/wiki/Square_root
.. [2] https://en.wikipedia.org/wiki/Real_root
.. [3] https://en.wikipedia.org/wiki/Root_of_unity
.. [4] https://en.wikipedia.org/wiki/Principal_value
.. [5] https://mathworld.wolfram.com/CubeRoot.html
"""
n = sympify(n)
if k:
return Mul(Pow(arg, S.One/n, evaluate=evaluate), S.NegativeOne**(2*k/n), evaluate=evaluate)
return Pow(arg, 1/n, evaluate=evaluate)
def real_root(arg, n=None, evaluate=None):
r"""Return the real *n*'th-root of *arg* if possible.
Parameters
==========
n : int or None, optional
If *n* is ``None``, then all instances of
$(-n)^{1/\text{odd}}$ will be changed to $-n^{1/\text{odd}}$.
This will only create a real root of a principal root.
The presence of other factors may cause the result to not be
real.
evaluate : bool, optional
The parameter determines if the expression should be evaluated.
If ``None``, its value is taken from
``global_parameters.evaluate``.
Examples
========
>>> from sympy import root, real_root
>>> real_root(-8, 3)
-2
>>> root(-8, 3)
2*(-1)**(1/3)
>>> real_root(_)
-2
If one creates a non-principal root and applies real_root, the
result will not be real (so use with caution):
>>> root(-8, 3, 2)
-2*(-1)**(2/3)
>>> real_root(_)
-2*(-1)**(2/3)
See Also
========
sympy.polys.rootoftools.rootof
sympy.core.intfunc.integer_nthroot
root, sqrt
"""
from sympy.functions.elementary.complexes import Abs, im, sign
from sympy.functions.elementary.piecewise import Piecewise
if n is not None:
return Piecewise(
(root(arg, n, evaluate=evaluate), Or(Eq(n, S.One), Eq(n, S.NegativeOne))),
(Mul(sign(arg), root(Abs(arg), n, evaluate=evaluate), evaluate=evaluate),
And(Eq(im(arg), S.Zero), Eq(Mod(n, 2), S.One))),
(root(arg, n, evaluate=evaluate), True))
rv = sympify(arg)
n1pow = Transform(lambda x: -(-x.base)**x.exp,
lambda x:
x.is_Pow and
x.base.is_negative and
x.exp.is_Rational and
x.exp.p == 1 and x.exp.q % 2)
return rv.xreplace(n1pow)
###############################################################################
############################# MINIMUM and MAXIMUM #############################
###############################################################################
class MinMaxBase(Expr, LatticeOp):
def __new__(cls, *args, **assumptions):
from sympy.core.parameters import global_parameters
evaluate = assumptions.pop('evaluate', global_parameters.evaluate)
args = (sympify(arg) for arg in args)
# first standard filter, for cls.zero and cls.identity
# also reshape Max(a, Max(b, c)) to Max(a, b, c)
if evaluate:
try:
args = frozenset(cls._new_args_filter(args))
except ShortCircuit:
return cls.zero
# remove redundant args that are easily identified
args = cls._collapse_arguments(args, **assumptions)
# find local zeros
args = cls._find_localzeros(args, **assumptions)
args = frozenset(args)
if not args:
return cls.identity
if len(args) == 1:
return list(args).pop()
# base creation
obj = Expr.__new__(cls, *ordered(args), **assumptions)
obj._argset = args
return obj
@classmethod
def _collapse_arguments(cls, args, **assumptions):
"""Remove redundant args.
Examples
========
>>> from sympy import Min, Max
>>> from sympy.abc import a, b, c, d, e
Any arg in parent that appears in any
parent-like function in any of the flat args
of parent can be removed from that sub-arg:
>>> Min(a, Max(b, Min(a, c, d)))
Min(a, Max(b, Min(c, d)))
If the arg of parent appears in an opposite-than parent
function in any of the flat args of parent that function
can be replaced with the arg:
>>> Min(a, Max(b, Min(c, d, Max(a, e))))
Min(a, Max(b, Min(a, c, d)))
"""
if not args:
return args
args = list(ordered(args))
if cls == Min:
other = Max
else:
other = Min
# find global comparable max of Max and min of Min if a new
# value is being introduced in these args at position 0 of
# the ordered args
if args[0].is_number:
sifted = mins, maxs = [], []
for i in args:
for v in walk(i, Min, Max):
if v.args[0].is_comparable:
sifted[isinstance(v, Max)].append(v)
small = Min.identity
for i in mins:
v = i.args[0]
if v.is_number and (v < small) == True:
small = v
big = Max.identity
for i in maxs:
v = i.args[0]
if v.is_number and (v > big) == True:
big = v
# at the point when this function is called from __new__,
# there may be more than one numeric arg present since
# local zeros have not been handled yet, so look through
# more than the first arg
if cls == Min:
for arg in args:
if not arg.is_number:
break
if (arg < small) == True:
small = arg
elif cls == Max:
for arg in args:
if not arg.is_number:
break
if (arg > big) == True:
big = arg
T = None
if cls == Min:
if small != Min.identity:
other = Max
T = small
elif big != Max.identity:
other = Min
T = big
if T is not None:
# remove numerical redundancy
for i in range(len(args)):
a = args[i]
if isinstance(a, other):
a0 = a.args[0]
if ((a0 > T) if other == Max else (a0 < T)) == True:
args[i] = cls.identity
# remove redundant symbolic args
def do(ai, a):
if not isinstance(ai, (Min, Max)):
return ai
cond = a in ai.args
if not cond:
return ai.func(*[do(i, a) for i in ai.args],
evaluate=False)
if isinstance(ai, cls):
return ai.func(*[do(i, a) for i in ai.args if i != a],
evaluate=False)
return a
for i, a in enumerate(args):
args[i + 1:] = [do(ai, a) for ai in args[i + 1:]]
# factor out common elements as for
# Min(Max(x, y), Max(x, z)) -> Max(x, Min(y, z))
# and vice versa when swapping Min/Max -- do this only for the
# easy case where all functions contain something in common;
# trying to find some optimal subset of args to modify takes
# too long
def factor_minmax(args):
is_other = lambda arg: isinstance(arg, other)
other_args, remaining_args = sift(args, is_other, binary=True)
if not other_args:
return args
# Min(Max(x, y, z), Max(x, y, u, v)) -> {x,y}, ({z}, {u,v})
arg_sets = [set(arg.args) for arg in other_args]
common = set.intersection(*arg_sets)
if not common:
return args
new_other_args = list(common)
arg_sets_diff = [arg_set - common for arg_set in arg_sets]
# If any set is empty after removing common then all can be
# discarded e.g. Min(Max(a, b, c), Max(a, b)) -> Max(a, b)
if all(arg_sets_diff):
other_args_diff = [other(*s, evaluate=False) for s in arg_sets_diff]
new_other_args.append(cls(*other_args_diff, evaluate=False))
other_args_factored = other(*new_other_args, evaluate=False)
return remaining_args + [other_args_factored]
if len(args) > 1:
args = factor_minmax(args)
return args
@classmethod
def _new_args_filter(cls, arg_sequence):
"""
Generator filtering args.
first standard filter, for cls.zero and cls.identity.
Also reshape ``Max(a, Max(b, c))`` to ``Max(a, b, c)``,
and check arguments for comparability
"""
for arg in arg_sequence:
# pre-filter, checking comparability of arguments
if not isinstance(arg, Expr) or arg.is_extended_real is False or (
arg.is_number and
not arg.is_comparable):
raise ValueError("The argument '%s' is not comparable." % arg)
if arg == cls.zero:
raise ShortCircuit(arg)
elif arg == cls.identity:
continue
elif arg.func == cls:
yield from arg.args
else:
yield arg
@classmethod
def _find_localzeros(cls, values, **options):
"""
Sequentially allocate values to localzeros.
When a value is identified as being more extreme than another member it
replaces that member; if this is never true, then the value is simply
appended to the localzeros.
"""
localzeros = set()
for v in values:
is_newzero = True
localzeros_ = list(localzeros)
for z in localzeros_:
if id(v) == id(z):
is_newzero = False
else:
con = cls._is_connected(v, z)
if con:
is_newzero = False
if con is True or con == cls:
localzeros.remove(z)
localzeros.update([v])
if is_newzero:
localzeros.update([v])
return localzeros
@classmethod
def _is_connected(cls, x, y):
"""
Check if x and y are connected somehow.
"""
for i in range(2):
if x == y:
return True
t, f = Max, Min
for op in "><":
for j in range(2):
try:
if op == ">":
v = x >= y
else:
v = x <= y
except TypeError:
return False # non-real arg
if not v.is_Relational:
return t if v else f
t, f = f, t
x, y = y, x
x, y = y, x # run next pass with reversed order relative to start
# simplification can be expensive, so be conservative
# in what is attempted
x = factor_terms(x - y)
y = S.Zero
return False
def _eval_derivative(self, s):
# f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s)
i = 0
l = []
for a in self.args:
i += 1
da = a.diff(s)
if da.is_zero:
continue
try:
df = self.fdiff(i)
except ArgumentIndexError:
df = Function.fdiff(self, i)
l.append(df * da)
return Add(*l)
def _eval_rewrite_as_Abs(self, *args, **kwargs):
from sympy.functions.elementary.complexes import Abs
s = (args[0] + self.func(*args[1:]))/2
d = abs(args[0] - self.func(*args[1:]))/2
return (s + d if isinstance(self, Max) else s - d).rewrite(Abs)
def evalf(self, n=15, **options):
return self.func(*[a.evalf(n, **options) for a in self.args])
def n(self, *args, **kwargs):
return self.evalf(*args, **kwargs)
_eval_is_algebraic = lambda s: _torf(i.is_algebraic for i in s.args)
_eval_is_antihermitian = lambda s: _torf(i.is_antihermitian for i in s.args)
_eval_is_commutative = lambda s: _torf(i.is_commutative for i in s.args)
_eval_is_complex = lambda s: _torf(i.is_complex for i in s.args)
_eval_is_composite = lambda s: _torf(i.is_composite for i in s.args)
_eval_is_even = lambda s: _torf(i.is_even for i in s.args)
_eval_is_finite = lambda s: _torf(i.is_finite for i in s.args)
_eval_is_hermitian = lambda s: _torf(i.is_hermitian for i in s.args)
_eval_is_imaginary = lambda s: _torf(i.is_imaginary for i in s.args)
_eval_is_infinite = lambda s: _torf(i.is_infinite for i in s.args)
_eval_is_integer = lambda s: _torf(i.is_integer for i in s.args)
_eval_is_irrational = lambda s: _torf(i.is_irrational for i in s.args)
_eval_is_negative = lambda s: _torf(i.is_negative for i in s.args)
_eval_is_noninteger = lambda s: _torf(i.is_noninteger for i in s.args)
_eval_is_nonnegative = lambda s: _torf(i.is_nonnegative for i in s.args)
_eval_is_nonpositive = lambda s: _torf(i.is_nonpositive for i in s.args)
_eval_is_nonzero = lambda s: _torf(i.is_nonzero for i in s.args)
_eval_is_odd = lambda s: _torf(i.is_odd for i in s.args)
_eval_is_polar = lambda s: _torf(i.is_polar for i in s.args)
_eval_is_positive = lambda s: _torf(i.is_positive for i in s.args)
_eval_is_prime = lambda s: _torf(i.is_prime for i in s.args)
_eval_is_rational = lambda s: _torf(i.is_rational for i in s.args)
_eval_is_real = lambda s: _torf(i.is_real for i in s.args)
_eval_is_extended_real = lambda s: _torf(i.is_extended_real for i in s.args)
_eval_is_transcendental = lambda s: _torf(i.is_transcendental for i in s.args)
_eval_is_zero = lambda s: _torf(i.is_zero for i in s.args)
class Max(MinMaxBase, Application):
r"""
Return, if possible, the maximum value of the list.
When number of arguments is equal one, then
return this argument.
When number of arguments is equal two, then
return, if possible, the value from (a, b) that is $\ge$ the other.
In common case, when the length of list greater than 2, the task
is more complicated. Return only the arguments, which are greater
than others, if it is possible to determine directional relation.
If is not possible to determine such a relation, return a partially
evaluated result.
Assumptions are used to make the decision too.
Also, only comparable arguments are permitted.
It is named ``Max`` and not ``max`` to avoid conflicts
with the built-in function ``max``.
Examples
========
>>> from sympy import Max, Symbol, oo
>>> from sympy.abc import x, y, z
>>> p = Symbol('p', positive=True)
>>> n = Symbol('n', negative=True)
>>> Max(x, -2)
Max(-2, x)
>>> Max(x, -2).subs(x, 3)
3
>>> Max(p, -2)
p
>>> Max(x, y)
Max(x, y)
>>> Max(x, y) == Max(y, x)
True
>>> Max(x, Max(y, z))
Max(x, y, z)
>>> Max(n, 8, p, 7, -oo)
Max(8, p)
>>> Max (1, x, oo)
oo
* Algorithm
The task can be considered as searching of supremums in the
directed complete partial orders [1]_.
The source values are sequentially allocated by the isolated subsets
in which supremums are searched and result as Max arguments.
If the resulted supremum is single, then it is returned.
The isolated subsets are the sets of values which are only the comparable
with each other in the current set. E.g. natural numbers are comparable with
each other, but not comparable with the `x` symbol. Another example: the
symbol `x` with negative assumption is comparable with a natural number.
Also there are "least" elements, which are comparable with all others,
and have a zero property (maximum or minimum for all elements).
For example, in case of $\infty$, the allocation operation is terminated
and only this value is returned.
Assumption:
- if $A > B > C$ then $A > C$
- if $A = B$ then $B$ can be removed
References
==========
.. [1] https://en.wikipedia.org/wiki/Directed_complete_partial_order
.. [2] https://en.wikipedia.org/wiki/Lattice_%28order%29
See Also
========
Min : find minimum values
"""
zero = S.Infinity
identity = S.NegativeInfinity
def fdiff( self, argindex ):
from sympy.functions.special.delta_functions import Heaviside
n = len(self.args)
if 0 < argindex and argindex <= n:
argindex -= 1
if n == 2:
return Heaviside(self.args[argindex] - self.args[1 - argindex])
newargs = tuple([self.args[i] for i in range(n) if i != argindex])
return Heaviside(self.args[argindex] - Max(*newargs))
else:
raise ArgumentIndexError(self, argindex)
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
from sympy.functions.special.delta_functions import Heaviside
return Add(*[j*Mul(*[Heaviside(j - i) for i in args if i!=j]) \
for j in args])
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
return _minmax_as_Piecewise('>=', *args)
def _eval_is_positive(self):
return fuzzy_or(a.is_positive for a in self.args)
def _eval_is_nonnegative(self):
return fuzzy_or(a.is_nonnegative for a in self.args)
def _eval_is_negative(self):
return fuzzy_and(a.is_negative for a in self.args)
class Min(MinMaxBase, Application):
"""
Return, if possible, the minimum value of the list.
It is named ``Min`` and not ``min`` to avoid conflicts
with the built-in function ``min``.
Examples
========
>>> from sympy import Min, Symbol, oo
>>> from sympy.abc import x, y
>>> p = Symbol('p', positive=True)
>>> n = Symbol('n', negative=True)
>>> Min(x, -2)
Min(-2, x)
>>> Min(x, -2).subs(x, 3)
-2
>>> Min(p, -3)
-3
>>> Min(x, y)
Min(x, y)
>>> Min(n, 8, p, -7, p, oo)
Min(-7, n)
See Also
========
Max : find maximum values
"""
zero = S.NegativeInfinity
identity = S.Infinity
def fdiff( self, argindex ):
from sympy.functions.special.delta_functions import Heaviside
n = len(self.args)
if 0 < argindex and argindex <= n:
argindex -= 1
if n == 2:
return Heaviside( self.args[1-argindex] - self.args[argindex] )
newargs = tuple([ self.args[i] for i in range(n) if i != argindex])
return Heaviside( Min(*newargs) - self.args[argindex] )
else:
raise ArgumentIndexError(self, argindex)
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
from sympy.functions.special.delta_functions import Heaviside
return Add(*[j*Mul(*[Heaviside(i-j) for i in args if i!=j]) \
for j in args])
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
return _minmax_as_Piecewise('<=', *args)
def _eval_is_positive(self):
return fuzzy_and(a.is_positive for a in self.args)
def _eval_is_nonnegative(self):
return fuzzy_and(a.is_nonnegative for a in self.args)
def _eval_is_negative(self):
return fuzzy_or(a.is_negative for a in self.args)
class Rem(Function):
"""Returns the remainder when ``p`` is divided by ``q`` where ``p`` is finite
and ``q`` is not equal to zero. The result, ``p - int(p/q)*q``, has the same sign
as the divisor.
Parameters
==========
p : Expr
Dividend.
q : Expr
Divisor.
Notes
=====
``Rem`` corresponds to the ``%`` operator in C.
Examples
========
>>> from sympy.abc import x, y
>>> from sympy import Rem
>>> Rem(x**3, y)
Rem(x**3, y)
>>> Rem(x**3, y).subs({x: -5, y: 3})
-2
See Also
========
Mod
"""
kind = NumberKind
@classmethod
def eval(cls, p, q):
"""Return the function remainder if both p, q are numbers and q is not
zero.
"""
if q.is_zero:
raise ZeroDivisionError("Division by zero")
if p is S.NaN or q is S.NaN or p.is_finite is False or q.is_finite is False:
return S.NaN
if p is S.Zero or p in (q, -q) or (p.is_integer and q == 1):
return S.Zero
if q.is_Number:
if p.is_Number:
return p - Integer(p/q)*q

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,813 @@
from sympy.assumptions.refine import refine
from sympy.calculus.accumulationbounds import AccumBounds
from sympy.concrete.products import Product
from sympy.concrete.summations import Sum
from sympy.core.function import expand_log
from sympy.core.numbers import (E, Float, I, Rational, nan, oo, pi, zoo)
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.complexes import (adjoint, conjugate, re, sign, transpose)
from sympy.functions.elementary.exponential import (LambertW, exp, exp_polar, log)
from sympy.functions.elementary.hyperbolic import (cosh, sinh, tanh)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cos, sin, tan)
from sympy.matrices.expressions.matexpr import MatrixSymbol
from sympy.polys.polytools import gcd
from sympy.series.order import O
from sympy.simplify.simplify import simplify
from sympy.core.parameters import global_parameters
from sympy.functions.elementary.exponential import match_real_imag
from sympy.abc import x, y, z
from sympy.core.expr import unchanged
from sympy.core.function import ArgumentIndexError
from sympy.testing.pytest import raises, XFAIL, _both_exp_pow
@_both_exp_pow
def test_exp_values():
if global_parameters.exp_is_pow:
assert type(exp(x)) is Pow
else:
assert type(exp(x)) is exp
k = Symbol('k', integer=True)
assert exp(nan) is nan
assert exp(oo) is oo
assert exp(-oo) == 0
assert exp(0) == 1
assert exp(1) == E
assert exp(-1 + x).as_base_exp() == (S.Exp1, x - 1)
assert exp(1 + x).as_base_exp() == (S.Exp1, x + 1)
assert exp(pi*I/2) == I
assert exp(pi*I) == -1
assert exp(pi*I*Rational(3, 2)) == -I
assert exp(2*pi*I) == 1
assert refine(exp(pi*I*2*k)) == 1
assert refine(exp(pi*I*2*(k + S.Half))) == -1
assert refine(exp(pi*I*2*(k + Rational(1, 4)))) == I
assert refine(exp(pi*I*2*(k + Rational(3, 4)))) == -I
assert exp(log(x)) == x
assert exp(2*log(x)) == x**2
assert exp(pi*log(x)) == x**pi
assert exp(17*log(x) + E*log(y)) == x**17 * y**E
assert exp(x*log(x)) != x**x
assert exp(sin(x)*log(x)) != x
assert exp(3*log(x) + oo*x) == exp(oo*x) * x**3
assert exp(4*log(x)*log(y) + 3*log(x)) == x**3 * exp(4*log(x)*log(y))
assert exp(-oo, evaluate=False).is_finite is True
assert exp(oo, evaluate=False).is_finite is False
@_both_exp_pow
def test_exp_period():
assert exp(I*pi*Rational(9, 4)) == exp(I*pi/4)
assert exp(I*pi*Rational(46, 18)) == exp(I*pi*Rational(5, 9))
assert exp(I*pi*Rational(25, 7)) == exp(I*pi*Rational(-3, 7))
assert exp(I*pi*Rational(-19, 3)) == exp(-I*pi/3)
assert exp(I*pi*Rational(37, 8)) - exp(I*pi*Rational(-11, 8)) == 0
assert exp(I*pi*Rational(-5, 3)) / exp(I*pi*Rational(11, 5)) * exp(I*pi*Rational(148, 15)) == 1
assert exp(2 - I*pi*Rational(17, 5)) == exp(2 + I*pi*Rational(3, 5))
assert exp(log(3) + I*pi*Rational(29, 9)) == 3 * exp(I*pi*Rational(-7, 9))
n = Symbol('n', integer=True)
e = Symbol('e', even=True)
assert exp(e*I*pi) == 1
assert exp((e + 1)*I*pi) == -1
assert exp((1 + 4*n)*I*pi/2) == I
assert exp((-1 + 4*n)*I*pi/2) == -I
@_both_exp_pow
def test_exp_log():
x = Symbol("x", real=True)
assert log(exp(x)) == x
assert exp(log(x)) == x
if not global_parameters.exp_is_pow:
assert log(x).inverse() == exp
assert exp(x).inverse() == log
y = Symbol("y", polar=True)
assert log(exp_polar(z)) == z
assert exp(log(y)) == y
@_both_exp_pow
def test_exp_expand():
e = exp(log(Rational(2))*(1 + x) - log(Rational(2))*x)
assert e.expand() == 2
assert exp(x + y) != exp(x)*exp(y)
assert exp(x + y).expand() == exp(x)*exp(y)
@_both_exp_pow
def test_exp__as_base_exp():
assert exp(x).as_base_exp() == (E, x)
assert exp(2*x).as_base_exp() == (E, 2*x)
assert exp(x*y).as_base_exp() == (E, x*y)
assert exp(-x).as_base_exp() == (E, -x)
# Pow( *expr.as_base_exp() ) == expr invariant should hold
assert E**x == exp(x)
assert E**(2*x) == exp(2*x)
assert E**(x*y) == exp(x*y)
assert exp(x).base is S.Exp1
assert exp(x).exp == x
@_both_exp_pow
def test_exp_infinity():
assert exp(I*y) != nan
assert refine(exp(I*oo)) is nan
assert refine(exp(-I*oo)) is nan
assert exp(y*I*oo) != nan
assert exp(zoo) is nan
x = Symbol('x', extended_real=True, finite=False)
assert exp(x).is_complex is None
@_both_exp_pow
def test_exp_subs():
x = Symbol('x')
e = (exp(3*log(x), evaluate=False)) # evaluates to x**3
assert e.subs(x**3, y**3) == e
assert e.subs(x**2, 5) == e
assert (x**3).subs(x**2, y) != y**Rational(3, 2)
assert exp(exp(x) + exp(x**2)).subs(exp(exp(x)), y) == y * exp(exp(x**2))
assert exp(x).subs(E, y) == y**x
x = symbols('x', real=True)
assert exp(5*x).subs(exp(7*x), y) == y**Rational(5, 7)
assert exp(2*x + 7).subs(exp(3*x), y) == y**Rational(2, 3) * exp(7)
x = symbols('x', positive=True)
assert exp(3*log(x)).subs(x**2, y) == y**Rational(3, 2)
# differentiate between E and exp
assert exp(exp(x + E)).subs(exp, 3) == 3**(3**(x + E))
assert exp(exp(x + E)).subs(exp, sin) == sin(sin(x + E))
assert exp(exp(x + E)).subs(E, 3) == 3**(3**(x + 3))
assert exp(3).subs(E, sin) == sin(3)
def test_exp_adjoint():
assert adjoint(exp(x)) == exp(adjoint(x))
def test_exp_conjugate():
assert conjugate(exp(x)) == exp(conjugate(x))
@_both_exp_pow
def test_exp_transpose():
assert transpose(exp(x)) == exp(transpose(x))
@_both_exp_pow
def test_exp_rewrite():
assert exp(x).rewrite(sin) == sinh(x) + cosh(x)
assert exp(x*I).rewrite(cos) == cos(x) + I*sin(x)
assert exp(1).rewrite(cos) == sinh(1) + cosh(1)
assert exp(1).rewrite(sin) == sinh(1) + cosh(1)
assert exp(1).rewrite(sin) == sinh(1) + cosh(1)
assert exp(x).rewrite(tanh) == (1 + tanh(x/2))/(1 - tanh(x/2))
assert exp(pi*I/4).rewrite(sqrt) == sqrt(2)/2 + sqrt(2)*I/2
assert exp(pi*I/3).rewrite(sqrt) == S.Half + sqrt(3)*I/2
if not global_parameters.exp_is_pow:
assert exp(x*log(y)).rewrite(Pow) == y**x
assert exp(log(x)*log(y)).rewrite(Pow) in [x**log(y), y**log(x)]
assert exp(log(log(x))*y).rewrite(Pow) == log(x)**y
n = Symbol('n', integer=True)
assert Sum((exp(pi*I/2)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == Rational(4, 5) + I*2/5
assert Sum((exp(pi*I/4)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == 1/(1 - sqrt(2)*(1 + I)/4)
assert (Sum((exp(pi*I/3)/2)**n, (n, 0, oo)).rewrite(sqrt).doit().cancel()
== 4*I/(sqrt(3) + 3*I))
@_both_exp_pow
def test_exp_leading_term():
assert exp(x).as_leading_term(x) == 1
assert exp(2 + x).as_leading_term(x) == exp(2)
assert exp((2*x + 3) / (x+1)).as_leading_term(x) == exp(3)
# The following tests are commented, since now SymPy returns the
# original function when the leading term in the series expansion does
# not exist.
# raises(NotImplementedError, lambda: exp(1/x).as_leading_term(x))
# raises(NotImplementedError, lambda: exp((x + 1) / x**2).as_leading_term(x))
# raises(NotImplementedError, lambda: exp(x + 1/x).as_leading_term(x))
@_both_exp_pow
def test_exp_taylor_term():
x = symbols('x')
assert exp(x).taylor_term(1, x) == x
assert exp(x).taylor_term(3, x) == x**3/6
assert exp(x).taylor_term(4, x) == x**4/24
assert exp(x).taylor_term(-1, x) is S.Zero
def test_exp_MatrixSymbol():
A = MatrixSymbol("A", 2, 2)
assert exp(A).has(exp)
def test_exp_fdiff():
x = Symbol('x')
raises(ArgumentIndexError, lambda: exp(x).fdiff(2))
def test_log_values():
assert log(nan) is nan
assert log(oo) is oo
assert log(-oo) is oo
assert log(zoo) is zoo
assert log(-zoo) is zoo
assert log(0) is zoo
assert log(1) == 0
assert log(-1) == I*pi
assert log(E) == 1
assert log(-E).expand() == 1 + I*pi
assert unchanged(log, pi)
assert log(-pi).expand() == log(pi) + I*pi
assert unchanged(log, 17)
assert log(-17) == log(17) + I*pi
assert log(I) == I*pi/2
assert log(-I) == -I*pi/2
assert log(17*I) == I*pi/2 + log(17)
assert log(-17*I).expand() == -I*pi/2 + log(17)
assert log(oo*I) is oo
assert log(-oo*I) is oo
assert log(0, 2) is zoo
assert log(0, 5) is zoo
assert exp(-log(3))**(-1) == 3
assert log(S.Half) == -log(2)
assert log(2*3).func is log
assert log(2*3**2).func is log
def test_match_real_imag():
x, y = symbols('x,y', real=True)
i = Symbol('i', imaginary=True)
assert match_real_imag(S.One) == (1, 0)
assert match_real_imag(I) == (0, 1)
assert match_real_imag(3 - 5*I) == (3, -5)
assert match_real_imag(-sqrt(3) + S.Half*I) == (-sqrt(3), S.Half)
assert match_real_imag(x + y*I) == (x, y)
assert match_real_imag(x*I + y*I) == (0, x + y)
assert match_real_imag((x + y)*I) == (0, x + y)
assert match_real_imag(Rational(-2, 3)*i*I) == (None, None)
assert match_real_imag(1 - 2*i) == (None, None)
assert match_real_imag(sqrt(2)*(3 - 5*I)) == (None, None)
def test_log_exact():
# check for pi/2, pi/3, pi/4, pi/6, pi/8, pi/12; pi/5, pi/10:
for n in range(-23, 24):
if gcd(n, 24) != 1:
assert log(exp(n*I*pi/24).rewrite(sqrt)) == n*I*pi/24
for n in range(-9, 10):
assert log(exp(n*I*pi/10).rewrite(sqrt)) == n*I*pi/10
assert log(S.Half - I*sqrt(3)/2) == -I*pi/3
assert log(Rational(-1, 2) + I*sqrt(3)/2) == I*pi*Rational(2, 3)
assert log(-sqrt(2)/2 - I*sqrt(2)/2) == -I*pi*Rational(3, 4)
assert log(-sqrt(3)/2 - I*S.Half) == -I*pi*Rational(5, 6)
assert log(Rational(-1, 4) + sqrt(5)/4 - I*sqrt(sqrt(5)/8 + Rational(5, 8))) == -I*pi*Rational(2, 5)
assert log(sqrt(Rational(5, 8) - sqrt(5)/8) + I*(Rational(1, 4) + sqrt(5)/4)) == I*pi*Rational(3, 10)
assert log(-sqrt(sqrt(2)/4 + S.Half) + I*sqrt(S.Half - sqrt(2)/4)) == I*pi*Rational(7, 8)
assert log(-sqrt(6)/4 - sqrt(2)/4 + I*(-sqrt(6)/4 + sqrt(2)/4)) == -I*pi*Rational(11, 12)
assert log(-1 + I*sqrt(3)) == log(2) + I*pi*Rational(2, 3)
assert log(5 + 5*I) == log(5*sqrt(2)) + I*pi/4
assert log(sqrt(-12)) == log(2*sqrt(3)) + I*pi/2
assert log(-sqrt(6) + sqrt(2) - I*sqrt(6) - I*sqrt(2)) == log(4) - I*pi*Rational(7, 12)
assert log(-sqrt(6-3*sqrt(2)) - I*sqrt(6+3*sqrt(2))) == log(2*sqrt(3)) - I*pi*Rational(5, 8)
assert log(1 + I*sqrt(2-sqrt(2))/sqrt(2+sqrt(2))) == log(2/sqrt(sqrt(2) + 2)) + I*pi/8
assert log(cos(pi*Rational(7, 12)) + I*sin(pi*Rational(7, 12))) == I*pi*Rational(7, 12)
assert log(cos(pi*Rational(6, 5)) + I*sin(pi*Rational(6, 5))) == I*pi*Rational(-4, 5)
assert log(5*(1 + I)/sqrt(2)) == log(5) + I*pi/4
assert log(sqrt(2)*(-sqrt(3) + 1 - sqrt(3)*I - I)) == log(4) - I*pi*Rational(7, 12)
assert log(-sqrt(2)*(1 - I*sqrt(3))) == log(2*sqrt(2)) + I*pi*Rational(2, 3)
assert log(sqrt(3)*I*(-sqrt(6 - 3*sqrt(2)) - I*sqrt(3*sqrt(2) + 6))) == log(6) - I*pi/8
zero = (1 + sqrt(2))**2 - 3 - 2*sqrt(2)
assert log(zero - I*sqrt(3)) == log(sqrt(3)) - I*pi/2
assert unchanged(log, zero + I*zero) or log(zero + zero*I) is zoo
# bail quickly if no obvious simplification is possible:
assert unchanged(log, (sqrt(2)-1/sqrt(sqrt(3)+I))**1000)
# beware of non-real coefficients
assert unchanged(log, sqrt(2-sqrt(5))*(1 + I))
def test_log_base():
assert log(1, 2) == 0
assert log(2, 2) == 1
assert log(3, 2) == log(3)/log(2)
assert log(6, 2) == 1 + log(3)/log(2)
assert log(6, 3) == 1 + log(2)/log(3)
assert log(2**3, 2) == 3
assert log(3**3, 3) == 3
assert log(5, 1) is zoo
assert log(1, 1) is nan
assert log(Rational(2, 3), 10) == log(Rational(2, 3))/log(10)
assert log(Rational(2, 3), Rational(1, 3)) == -log(2)/log(3) + 1
assert log(Rational(2, 3), Rational(2, 5)) == \
log(Rational(2, 3))/log(Rational(2, 5))
# issue 17148
assert log(Rational(8, 3), 2) == -log(3)/log(2) + 3
def test_log_symbolic():
assert log(x, exp(1)) == log(x)
assert log(exp(x)) != x
assert log(x, exp(1)) == log(x)
assert log(x*y) != log(x) + log(y)
assert log(x/y).expand() != log(x) - log(y)
assert log(x/y).expand(force=True) == log(x) - log(y)
assert log(x**y).expand() != y*log(x)
assert log(x**y).expand(force=True) == y*log(x)
assert log(x, 2) == log(x)/log(2)
assert log(E, 2) == 1/log(2)
p, q = symbols('p,q', positive=True)
r = Symbol('r', real=True)
assert log(p**2) != 2*log(p)
assert log(p**2).expand() == 2*log(p)
assert log(x**2).expand() != 2*log(x)
assert log(p**q) != q*log(p)
assert log(exp(p)) == p
assert log(p*q) != log(p) + log(q)
assert log(p*q).expand() == log(p) + log(q)
assert log(-sqrt(3)) == log(sqrt(3)) + I*pi
assert log(-exp(p)) != p + I*pi
assert log(-exp(x)).expand() != x + I*pi
assert log(-exp(r)).expand() == r + I*pi
assert log(x**y) != y*log(x)
assert (log(x**-5)**-1).expand() != -1/log(x)/5
assert (log(p**-5)**-1).expand() == -1/log(p)/5
assert log(-x).func is log and log(-x).args[0] == -x
assert log(-p).func is log and log(-p).args[0] == -p
def test_log_exp():
assert log(exp(4*I*pi)) == 0 # exp evaluates
assert log(exp(-5*I*pi)) == I*pi # exp evaluates
assert log(exp(I*pi*Rational(19, 4))) == I*pi*Rational(3, 4)
assert log(exp(I*pi*Rational(25, 7))) == I*pi*Rational(-3, 7)
assert log(exp(-5*I)) == -5*I + 2*I*pi
@_both_exp_pow
def test_exp_assumptions():
r = Symbol('r', real=True)
i = Symbol('i', imaginary=True)
for e in exp, exp_polar:
assert e(x).is_real is None
assert e(x).is_imaginary is None
assert e(i).is_real is None
assert e(i).is_imaginary is None
assert e(r).is_real is True
assert e(r).is_imaginary is False
assert e(re(x)).is_extended_real is True
assert e(re(x)).is_imaginary is False
assert Pow(E, I*pi, evaluate=False).is_imaginary == False
assert Pow(E, 2*I*pi, evaluate=False).is_imaginary == False
assert Pow(E, I*pi/2, evaluate=False).is_imaginary == True
assert Pow(E, I*pi/3, evaluate=False).is_imaginary is None
assert exp(0, evaluate=False).is_algebraic
a = Symbol('a', algebraic=True)
an = Symbol('an', algebraic=True, nonzero=True)
r = Symbol('r', rational=True)
rn = Symbol('rn', rational=True, nonzero=True)
assert exp(a).is_algebraic is None
assert exp(an).is_algebraic is False
assert exp(pi*r).is_algebraic is None
assert exp(pi*rn).is_algebraic is False
assert exp(0, evaluate=False).is_algebraic is True
assert exp(I*pi/3, evaluate=False).is_algebraic is True
assert exp(I*pi*r, evaluate=False).is_algebraic is True
@_both_exp_pow
def test_exp_AccumBounds():
assert exp(AccumBounds(1, 2)) == AccumBounds(E, E**2)
def test_log_assumptions():
p = symbols('p', positive=True)
n = symbols('n', negative=True)
z = symbols('z', zero=True)
x = symbols('x', infinite=True, extended_positive=True)
assert log(z).is_positive is False
assert log(x).is_extended_positive is True
assert log(2) > 0
assert log(1, evaluate=False).is_zero
assert log(1 + z).is_zero
assert log(p).is_zero is None
assert log(n).is_zero is False
assert log(0.5).is_negative is True
assert log(exp(p) + 1).is_positive
assert log(1, evaluate=False).is_algebraic
assert log(42, evaluate=False).is_algebraic is False
assert log(1 + z).is_rational
def test_log_hashing():
assert x != log(log(x))
assert hash(x) != hash(log(log(x)))
assert log(x) != log(log(log(x)))
e = 1/log(log(x) + log(log(x)))
assert e.base.func is log
e = 1/log(log(x) + log(log(log(x))))
assert e.base.func is log
e = log(log(x))
assert e.func is log
assert x.func is not log
assert hash(log(log(x))) != hash(x)
assert e != x
def test_log_sign():
assert sign(log(2)) == 1
def test_log_expand_complex():
assert log(1 + I).expand(complex=True) == log(2)/2 + I*pi/4
assert log(1 - sqrt(2)).expand(complex=True) == log(sqrt(2) - 1) + I*pi
def test_log_apply_evalf():
value = (log(3)/log(2) - 1).evalf()
assert value.epsilon_eq(Float("0.58496250072115618145373"))
def test_log_leading_term():
p = Symbol('p')
# Test for STEP 3
assert log(1 + x + x**2).as_leading_term(x, cdir=1) == x
# Test for STEP 4
assert log(2*x).as_leading_term(x, cdir=1) == log(x) + log(2)
assert log(2*x).as_leading_term(x, cdir=-1) == log(x) + log(2)
assert log(-2*x).as_leading_term(x, cdir=1, logx=p) == p + log(2) + I*pi
assert log(-2*x).as_leading_term(x, cdir=-1, logx=p) == p + log(2) - I*pi
# Test for STEP 5
assert log(-2*x + (3 - I)*x**2).as_leading_term(x, cdir=1) == log(x) + log(2) - I*pi
assert log(-2*x + (3 - I)*x**2).as_leading_term(x, cdir=-1) == log(x) + log(2) - I*pi
assert log(2*x + (3 - I)*x**2).as_leading_term(x, cdir=1) == log(x) + log(2)
assert log(2*x + (3 - I)*x**2).as_leading_term(x, cdir=-1) == log(x) + log(2) - 2*I*pi
assert log(-1 + x - I*x**2 + I*x**3).as_leading_term(x, cdir=1) == -I*pi
assert log(-1 + x - I*x**2 + I*x**3).as_leading_term(x, cdir=-1) == -I*pi
assert log(-1/(1 - x)).as_leading_term(x, cdir=1) == I*pi
assert log(-1/(1 - x)).as_leading_term(x, cdir=-1) == I*pi
def test_log_nseries():
p = Symbol('p')
assert log(1/x)._eval_nseries(x, 4, logx=-p, cdir=1) == p
assert log(1/x)._eval_nseries(x, 4, logx=-p, cdir=-1) == p + 2*I*pi
assert log(x - 1)._eval_nseries(x, 4, None, I) == I*pi - x - x**2/2 - x**3/3 + O(x**4)
assert log(x - 1)._eval_nseries(x, 4, None, -I) == -I*pi - x - x**2/2 - x**3/3 + O(x**4)
assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x + x**2/2 + O(x**3)
assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == -I*pi - I*x + x**2/2 + O(x**3)
assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x**2 + O(x**3)
assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == I*pi - I*x**2 + O(x**3)
assert log(2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, 1) == log(2) + log(x) + \
x*(S(3)/2 - I/2) + x**2*(-1 + 3*I/4) + O(x**3)
assert log(2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, -1) == -2*I*pi + log(2) + \
log(x) - x*(-S(3)/2 + I/2) + x**2*(-1 + 3*I/4) + O(x**3)
assert log(-2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, 1) == -I*pi + log(2) + log(x) + \
x*(-S(3)/2 + I/2) + x**2*(-1 + 3*I/4) + O(x**3)
assert log(-2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, -1) == -I*pi + log(2) + log(x) - \
x*(S(3)/2 - I/2) + x**2*(-1 + 3*I/4) + O(x**3)
assert log(sqrt(-I*x**2 - 3)*sqrt(-I*x**2 - 1) - 2)._eval_nseries(x, 3, None, 1) == -I*pi + \
log(sqrt(3) + 2) + I*x**2*(-2 + 4*sqrt(3)/3) + O(x**3)
assert log(-1/(1 - x))._eval_nseries(x, 3, None, 1) == I*pi + x + x**2/2 + O(x**3)
assert log(-1/(1 - x))._eval_nseries(x, 3, None, -1) == I*pi + x + x**2/2 + O(x**3)
def test_log_series():
# Note Series at infinities other than oo/-oo were introduced as a part of
# pull request 23798. Refer https://github.com/sympy/sympy/pull/23798 for
# more information.
expr1 = log(1 + x)
expr2 = log(x + sqrt(x**2 + 1))
assert expr1.series(x, x0=I*oo, n=4) == 1/(3*x**3) - 1/(2*x**2) + 1/x + \
I*pi/2 - log(I/x) + O(x**(-4), (x, oo*I))
assert expr1.series(x, x0=-I*oo, n=4) == 1/(3*x**3) - 1/(2*x**2) + 1/x - \
I*pi/2 - log(-I/x) + O(x**(-4), (x, -oo*I))
assert expr2.series(x, x0=I*oo, n=4) == 1/(4*x**2) + I*pi/2 + log(2) - \
log(I/x) + O(x**(-4), (x, oo*I))
assert expr2.series(x, x0=-I*oo, n=4) == -1/(4*x**2) - I*pi/2 - log(2) + \
log(-I/x) + O(x**(-4), (x, -oo*I))
def test_log_expand():
w = Symbol("w", positive=True)
e = log(w**(log(5)/log(3)))
assert e.expand() == log(5)/log(3) * log(w)
x, y, z = symbols('x,y,z', positive=True)
assert log(x*(y + z)).expand(mul=False) == log(x) + log(y + z)
assert log(log(x**2)*log(y*z)).expand() in [log(2*log(x)*log(y) +
2*log(x)*log(z)), log(log(x)*log(z) + log(y)*log(x)) + log(2),
log((log(y) + log(z))*log(x)) + log(2)]
assert log(x**log(x**2)).expand(deep=False) == log(x)*log(x**2)
assert log(x**log(x**2)).expand() == 2*log(x)**2
x, y = symbols('x,y')
assert log(x*y).expand(force=True) == log(x) + log(y)
assert log(x**y).expand(force=True) == y*log(x)
assert log(exp(x)).expand(force=True) == x
# there's generally no need to expand out logs since this requires
# factoring and if simplification is sought, it's cheaper to put
# logs together than it is to take them apart.
assert log(2*3**2).expand() != 2*log(3) + log(2)
@XFAIL
def test_log_expand_fail():
x, y, z = symbols('x,y,z', positive=True)
assert (log(x*(y + z))*(x + y)).expand(mul=True, log=True) == y*log(
x) + y*log(y + z) + z*log(x) + z*log(y + z)
def test_log_simplify():
x = Symbol("x", positive=True)
assert log(x**2).expand() == 2*log(x)
assert expand_log(log(x**(2 + log(2)))) == (2 + log(2))*log(x)
z = Symbol('z')
assert log(sqrt(z)).expand() == log(z)/2
assert expand_log(log(z**(log(2) - 1))) == (log(2) - 1)*log(z)
assert log(z**(-1)).expand() != -log(z)
assert log(z**(x/(x+1))).expand() == x*log(z)/(x + 1)
def test_log_AccumBounds():
assert log(AccumBounds(1, E)) == AccumBounds(0, 1)
assert log(AccumBounds(0, E)) == AccumBounds(-oo, 1)
assert log(AccumBounds(-1, E)) == S.NaN
assert log(AccumBounds(0, oo)) == AccumBounds(-oo, oo)
assert log(AccumBounds(-oo, 0)) == S.NaN
assert log(AccumBounds(-oo, oo)) == S.NaN
@_both_exp_pow
def test_lambertw():
k = Symbol('k')
assert LambertW(x, 0) == LambertW(x)
assert LambertW(x, 0, evaluate=False) != LambertW(x)
assert LambertW(0) == 0
assert LambertW(E) == 1
assert LambertW(-1/E) == -1
assert LambertW(100*log(100)) == log(100)
assert LambertW(-log(2)/2) == -log(2)
assert LambertW(81*log(3)) == 3*log(3)
assert LambertW(sqrt(E)/2) == S.Half
assert LambertW(oo) is oo
assert LambertW(0, 1) is -oo
assert LambertW(0, 42) is -oo
assert LambertW(-pi/2, -1) == -I*pi/2
assert LambertW(-1/E, -1) == -1
assert LambertW(-2*exp(-2), -1) == -2
assert LambertW(2*log(2)) == log(2)
assert LambertW(-pi/2) == I*pi/2
assert LambertW(exp(1 + E)) == E
assert LambertW(x**2).diff(x) == 2*LambertW(x**2)/x/(1 + LambertW(x**2))
assert LambertW(x, k).diff(x) == LambertW(x, k)/x/(1 + LambertW(x, k))
assert LambertW(sqrt(2)).evalf(30).epsilon_eq(
Float("0.701338383413663009202120278965", 30), 1e-29)
assert re(LambertW(2, -1)).evalf().epsilon_eq(Float("-0.834310366631110"))
assert LambertW(-1).is_real is False # issue 5215
assert LambertW(2, evaluate=False).is_real
p = Symbol('p', positive=True)
assert LambertW(p, evaluate=False).is_real
assert LambertW(p**(p+1)*log(p)) == p*log(p)
assert LambertW(p - 1, evaluate=False).is_real is None
assert LambertW(-p - 2/S.Exp1, evaluate=False).is_real is False
assert LambertW(S.Half, -1, evaluate=False).is_real is False
assert LambertW(Rational(-1, 10), -1, evaluate=False).is_real
assert LambertW(-10, -1, evaluate=False).is_real is False
assert LambertW(-2, 2, evaluate=False).is_real is False
assert LambertW(0, evaluate=False).is_algebraic
na = Symbol('na', nonzero=True, algebraic=True)
assert LambertW(na).is_algebraic is False
assert LambertW(p).is_zero is False
n = Symbol('n', negative=True)
assert LambertW(n).is_zero is False
def test_issue_5673():
e = LambertW(-1)
assert e.is_comparable is False
assert e.is_positive is not True
e2 = 1 - 1/(1 - exp(-1000))
assert e2.is_positive is not True
e3 = -2 + exp(exp(LambertW(log(2)))*LambertW(log(2)))
assert e3.is_nonzero is not True
def test_log_fdiff():
x = Symbol('x')
raises(ArgumentIndexError, lambda: log(x).fdiff(2))
def test_log_taylor_term():
x = symbols('x')
assert log(x).taylor_term(0, x) == x
assert log(x).taylor_term(1, x) == -x**2/2
assert log(x).taylor_term(4, x) == x**5/5
assert log(x).taylor_term(-1, x) is S.Zero
def test_exp_expand_NC():
A, B, C = symbols('A,B,C', commutative=False)
assert exp(A + B).expand() == exp(A + B)
assert exp(A + B + C).expand() == exp(A + B + C)
assert exp(x + y).expand() == exp(x)*exp(y)
assert exp(x + y + z).expand() == exp(x)*exp(y)*exp(z)
@_both_exp_pow
def test_as_numer_denom():
n = symbols('n', negative=True)
assert exp(x).as_numer_denom() == (exp(x), 1)
assert exp(-x).as_numer_denom() == (1, exp(x))
assert exp(-2*x).as_numer_denom() == (1, exp(2*x))
assert exp(-2).as_numer_denom() == (1, exp(2))
assert exp(n).as_numer_denom() == (1, exp(-n))
assert exp(-n).as_numer_denom() == (exp(-n), 1)
assert exp(-I*x).as_numer_denom() == (1, exp(I*x))
assert exp(-I*n).as_numer_denom() == (1, exp(I*n))
assert exp(-n).as_numer_denom() == (exp(-n), 1)
# Check noncommutativity
a = symbols('a', commutative=False)
assert exp(-a).as_numer_denom() == (exp(-a), 1)
@_both_exp_pow
def test_polar():
x, y = symbols('x y', polar=True)
assert abs(exp_polar(I*4)) == 1
assert abs(exp_polar(0)) == 1
assert abs(exp_polar(2 + 3*I)) == exp(2)
assert exp_polar(I*10).n() == exp_polar(I*10)
assert log(exp_polar(z)) == z
assert log(x*y).expand() == log(x) + log(y)
assert log(x**z).expand() == z*log(x)
assert exp_polar(3).exp == 3
# Compare exp(1.0*pi*I).
assert (exp_polar(1.0*pi*I).n(n=5)).as_real_imag()[1] >= 0
assert exp_polar(0).is_rational is True # issue 8008
def test_exp_summation():
w = symbols("w")
m, n, i, j = symbols("m n i j")
expr = exp(Sum(w*i, (i, 0, n), (j, 0, m)))
assert expr.expand() == Product(exp(w*i), (i, 0, n), (j, 0, m))
def test_log_product():
from sympy.abc import n, m
i, j = symbols('i,j', positive=True, integer=True)
x, y = symbols('x,y', positive=True)
z = symbols('z', real=True)
w = symbols('w')
expr = log(Product(x**i, (i, 1, n)))
assert simplify(expr) == expr
assert expr.expand() == Sum(i*log(x), (i, 1, n))
expr = log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))
assert simplify(expr) == expr
assert expr.expand() == Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m))
expr = log(Product(-2, (n, 0, 4)))
assert simplify(expr) == expr
assert expr.expand() == expr
assert expr.expand(force=True) == Sum(log(-2), (n, 0, 4))
expr = log(Product(exp(z*i), (i, 0, n)))
assert expr.expand() == Sum(z*i, (i, 0, n))
expr = log(Product(exp(w*i), (i, 0, n)))
assert expr.expand() == expr
assert expr.expand(force=True) == Sum(w*i, (i, 0, n))
expr = log(Product(i**2*abs(j), (i, 1, n), (j, 1, m)))
assert expr.expand() == Sum(2*log(i) + log(j), (i, 1, n), (j, 1, m))
@XFAIL
def test_log_product_simplify_to_sum():
from sympy.abc import n, m
i, j = symbols('i,j', positive=True, integer=True)
x, y = symbols('x,y', positive=True)
assert simplify(log(Product(x**i, (i, 1, n)))) == Sum(i*log(x), (i, 1, n))
assert simplify(log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))) == \
Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m))
def test_issue_8866():
assert simplify(log(x, 10, evaluate=False)) == simplify(log(x, 10))
assert expand_log(log(x, 10, evaluate=False)) == expand_log(log(x, 10))
y = Symbol('y', positive=True)
l1 = log(exp(y), exp(10))
b1 = log(exp(y), exp(5))
l2 = log(exp(y), exp(10), evaluate=False)
b2 = log(exp(y), exp(5), evaluate=False)
assert simplify(log(l1, b1)) == simplify(log(l2, b2))
assert expand_log(log(l1, b1)) == expand_log(log(l2, b2))
def test_log_expand_factor():
assert (log(18)/log(3) - 2).expand(factor=True) == log(2)/log(3)
assert (log(12)/log(2)).expand(factor=True) == log(3)/log(2) + 2
assert (log(15)/log(3)).expand(factor=True) == 1 + log(5)/log(3)
assert (log(2)/(-log(12) + log(24))).expand(factor=True) == 1
assert expand_log(log(12), factor=True) == log(3) + 2*log(2)
assert expand_log(log(21)/log(7), factor=False) == log(3)/log(7) + 1
assert expand_log(log(45)/log(5) + log(20), factor=False) == \
1 + 2*log(3)/log(5) + log(20)
assert expand_log(log(45)/log(5) + log(26), factor=True) == \
log(2) + log(13) + (log(5) + 2*log(3))/log(5)
def test_issue_9116():
n = Symbol('n', positive=True, integer=True)
assert log(n).is_nonnegative is True
def test_issue_18473():
assert exp(x*log(cos(1/x))).as_leading_term(x) == S.NaN
assert exp(x*log(tan(1/x))).as_leading_term(x) == S.NaN
assert log(cos(1/x)).as_leading_term(x) == S.NaN
assert log(tan(1/x)).as_leading_term(x) == S.NaN
assert log(cos(1/x) + 2).as_leading_term(x) == AccumBounds(0, log(3))
assert exp(x*log(cos(1/x) + 2)).as_leading_term(x) == 1
assert log(cos(1/x) - 2).as_leading_term(x) == S.NaN
assert exp(x*log(cos(1/x) - 2)).as_leading_term(x) == S.NaN
assert log(cos(1/x) + 1).as_leading_term(x) == AccumBounds(-oo, log(2))
assert exp(x*log(cos(1/x) + 1)).as_leading_term(x) == AccumBounds(0, 1)
assert log(sin(1/x)**2).as_leading_term(x) == AccumBounds(-oo, 0)
assert exp(x*log(sin(1/x)**2)).as_leading_term(x) == AccumBounds(0, 1)
assert log(tan(1/x)**2).as_leading_term(x) == AccumBounds(-oo, oo)
assert exp(2*x*(log(tan(1/x)**2))).as_leading_term(x) == AccumBounds(0, oo)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,662 @@
from sympy.calculus.accumulationbounds import AccumBounds
from sympy.core.numbers import (E, Float, I, Rational, nan, oo, pi, zoo)
from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.integers import (ceiling, floor, frac)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import sin, cos, tan
from sympy.polys.rootoftools import RootOf, CRootOf
from sympy import Integers
from sympy.sets.sets import Interval
from sympy.sets.fancysets import ImageSet
from sympy.core.function import Lambda
from sympy.core.expr import unchanged
from sympy.testing.pytest import XFAIL, raises
x = Symbol('x')
i = Symbol('i', imaginary=True)
y = Symbol('y', real=True)
k, n = symbols('k,n', integer=True)
def test_floor():
assert floor(nan) is nan
assert floor(oo) is oo
assert floor(-oo) is -oo
assert floor(zoo) is zoo
assert floor(0) == 0
assert floor(1) == 1
assert floor(-1) == -1
assert floor(E) == 2
assert floor(-E) == -3
assert floor(2*E) == 5
assert floor(-2*E) == -6
assert floor(pi) == 3
assert floor(-pi) == -4
assert floor(S.Half) == 0
assert floor(Rational(-1, 2)) == -1
assert floor(Rational(7, 3)) == 2
assert floor(Rational(-7, 3)) == -3
assert floor(-Rational(7, 3)) == -3
assert floor(Float(17.0)) == 17
assert floor(-Float(17.0)) == -17
assert floor(Float(7.69)) == 7
assert floor(-Float(7.69)) == -8
assert floor(I) == I
assert floor(-I) == -I
e = floor(i)
assert e.func is floor and e.args[0] == i
assert floor(oo*I) == oo*I
assert floor(-oo*I) == -oo*I
assert floor(exp(I*pi/4)*oo) == exp(I*pi/4)*oo
assert floor(2*I) == 2*I
assert floor(-2*I) == -2*I
assert floor(I/2) == 0
assert floor(-I/2) == -I
assert floor(E + 17) == 19
assert floor(pi + 2) == 5
assert floor(E + pi) == 5
assert floor(I + pi) == 3 + I
assert floor(floor(pi)) == 3
assert floor(floor(y)) == floor(y)
assert floor(floor(x)) == floor(x)
assert unchanged(floor, x)
assert unchanged(floor, 2*x)
assert unchanged(floor, k*x)
assert floor(k) == k
assert floor(2*k) == 2*k
assert floor(k*n) == k*n
assert unchanged(floor, k/2)
assert unchanged(floor, x + y)
assert floor(x + 3) == floor(x) + 3
assert floor(x + k) == floor(x) + k
assert floor(y + 3) == floor(y) + 3
assert floor(y + k) == floor(y) + k
assert floor(3 + I*y + pi) == 6 + floor(y)*I
assert floor(k + n) == k + n
assert unchanged(floor, x*I)
assert floor(k*I) == k*I
assert floor(Rational(23, 10) - E*I) == 2 - 3*I
assert floor(sin(1)) == 0
assert floor(sin(-1)) == -1
assert floor(exp(2)) == 7
assert floor(log(8)/log(2)) != 2
assert int(floor(log(8)/log(2)).evalf(chop=True)) == 3
assert floor(factorial(50)/exp(1)) == \
11188719610782480504630258070757734324011354208865721592720336800
assert (floor(y) < y) == False
assert (floor(y) <= y) == True
assert (floor(y) > y) == False
assert (floor(y) >= y) == False
assert (floor(x) <= x).is_Relational # x could be non-real
assert (floor(x) > x).is_Relational
assert (floor(x) <= y).is_Relational # arg is not same as rhs
assert (floor(x) > y).is_Relational
assert (floor(y) <= oo) == True
assert (floor(y) < oo) == True
assert (floor(y) >= -oo) == True
assert (floor(y) > -oo) == True
assert floor(y).rewrite(frac) == y - frac(y)
assert floor(y).rewrite(ceiling) == -ceiling(-y)
assert floor(y).rewrite(frac).subs(y, -pi) == floor(-pi)
assert floor(y).rewrite(frac).subs(y, E) == floor(E)
assert floor(y).rewrite(ceiling).subs(y, E) == -ceiling(-E)
assert floor(y).rewrite(ceiling).subs(y, -pi) == -ceiling(pi)
assert Eq(floor(y), y - frac(y))
assert Eq(floor(y), -ceiling(-y))
neg = Symbol('neg', negative=True)
nn = Symbol('nn', nonnegative=True)
pos = Symbol('pos', positive=True)
np = Symbol('np', nonpositive=True)
assert (floor(neg) < 0) == True
assert (floor(neg) <= 0) == True
assert (floor(neg) > 0) == False
assert (floor(neg) >= 0) == False
assert (floor(neg) <= -1) == True
assert (floor(neg) >= -3) == (neg >= -3)
assert (floor(neg) < 5) == (neg < 5)
assert (floor(nn) < 0) == False
assert (floor(nn) >= 0) == True
assert (floor(pos) < 0) == False
assert (floor(pos) <= 0) == (pos < 1)
assert (floor(pos) > 0) == (pos >= 1)
assert (floor(pos) >= 0) == True
assert (floor(pos) >= 3) == (pos >= 3)
assert (floor(np) <= 0) == True
assert (floor(np) > 0) == False
assert floor(neg).is_negative == True
assert floor(neg).is_nonnegative == False
assert floor(nn).is_negative == False
assert floor(nn).is_nonnegative == True
assert floor(pos).is_negative == False
assert floor(pos).is_nonnegative == True
assert floor(np).is_negative is None
assert floor(np).is_nonnegative is None
assert (floor(7, evaluate=False) >= 7) == True
assert (floor(7, evaluate=False) > 7) == False
assert (floor(7, evaluate=False) <= 7) == True
assert (floor(7, evaluate=False) < 7) == False
assert (floor(7, evaluate=False) >= 6) == True
assert (floor(7, evaluate=False) > 6) == True
assert (floor(7, evaluate=False) <= 6) == False
assert (floor(7, evaluate=False) < 6) == False
assert (floor(7, evaluate=False) >= 8) == False
assert (floor(7, evaluate=False) > 8) == False
assert (floor(7, evaluate=False) <= 8) == True
assert (floor(7, evaluate=False) < 8) == True
assert (floor(x) <= 5.5) == Le(floor(x), 5.5, evaluate=False)
assert (floor(x) >= -3.2) == Ge(floor(x), -3.2, evaluate=False)
assert (floor(x) < 2.9) == Lt(floor(x), 2.9, evaluate=False)
assert (floor(x) > -1.7) == Gt(floor(x), -1.7, evaluate=False)
assert (floor(y) <= 5.5) == (y < 6)
assert (floor(y) >= -3.2) == (y >= -3)
assert (floor(y) < 2.9) == (y < 3)
assert (floor(y) > -1.7) == (y >= -1)
assert (floor(y) <= n) == (y < n + 1)
assert (floor(y) >= n) == (y >= n)
assert (floor(y) < n) == (y < n)
assert (floor(y) > n) == (y >= n + 1)
assert floor(RootOf(x**3 - 27*x, 2)) == 5
def test_ceiling():
assert ceiling(nan) is nan
assert ceiling(oo) is oo
assert ceiling(-oo) is -oo
assert ceiling(zoo) is zoo
assert ceiling(0) == 0
assert ceiling(1) == 1
assert ceiling(-1) == -1
assert ceiling(E) == 3
assert ceiling(-E) == -2
assert ceiling(2*E) == 6
assert ceiling(-2*E) == -5
assert ceiling(pi) == 4
assert ceiling(-pi) == -3
assert ceiling(S.Half) == 1
assert ceiling(Rational(-1, 2)) == 0
assert ceiling(Rational(7, 3)) == 3
assert ceiling(-Rational(7, 3)) == -2
assert ceiling(Float(17.0)) == 17
assert ceiling(-Float(17.0)) == -17
assert ceiling(Float(7.69)) == 8
assert ceiling(-Float(7.69)) == -7
assert ceiling(I) == I
assert ceiling(-I) == -I
e = ceiling(i)
assert e.func is ceiling and e.args[0] == i
assert ceiling(oo*I) == oo*I
assert ceiling(-oo*I) == -oo*I
assert ceiling(exp(I*pi/4)*oo) == exp(I*pi/4)*oo
assert ceiling(2*I) == 2*I
assert ceiling(-2*I) == -2*I
assert ceiling(I/2) == I
assert ceiling(-I/2) == 0
assert ceiling(E + 17) == 20
assert ceiling(pi + 2) == 6
assert ceiling(E + pi) == 6
assert ceiling(I + pi) == I + 4
assert ceiling(ceiling(pi)) == 4
assert ceiling(ceiling(y)) == ceiling(y)
assert ceiling(ceiling(x)) == ceiling(x)
assert unchanged(ceiling, x)
assert unchanged(ceiling, 2*x)
assert unchanged(ceiling, k*x)
assert ceiling(k) == k
assert ceiling(2*k) == 2*k
assert ceiling(k*n) == k*n
assert unchanged(ceiling, k/2)
assert unchanged(ceiling, x + y)
assert ceiling(x + 3) == ceiling(x) + 3
assert ceiling(x + 3.0) == ceiling(x) + 3
assert ceiling(x + 3.0*I) == ceiling(x) + 3*I
assert ceiling(x + k) == ceiling(x) + k
assert ceiling(y + 3) == ceiling(y) + 3
assert ceiling(y + k) == ceiling(y) + k
assert ceiling(3 + pi + y*I) == 7 + ceiling(y)*I
assert ceiling(k + n) == k + n
assert unchanged(ceiling, x*I)
assert ceiling(k*I) == k*I
assert ceiling(Rational(23, 10) - E*I) == 3 - 2*I
assert ceiling(sin(1)) == 1
assert ceiling(sin(-1)) == 0
assert ceiling(exp(2)) == 8
assert ceiling(-log(8)/log(2)) != -2
assert int(ceiling(-log(8)/log(2)).evalf(chop=True)) == -3
assert ceiling(factorial(50)/exp(1)) == \
11188719610782480504630258070757734324011354208865721592720336801
assert (ceiling(y) >= y) == True
assert (ceiling(y) > y) == False
assert (ceiling(y) < y) == False
assert (ceiling(y) <= y) == False
assert (ceiling(x) >= x).is_Relational # x could be non-real
assert (ceiling(x) < x).is_Relational
assert (ceiling(x) >= y).is_Relational # arg is not same as rhs
assert (ceiling(x) < y).is_Relational
assert (ceiling(y) >= -oo) == True
assert (ceiling(y) > -oo) == True
assert (ceiling(y) <= oo) == True
assert (ceiling(y) < oo) == True
assert ceiling(y).rewrite(floor) == -floor(-y)
assert ceiling(y).rewrite(frac) == y + frac(-y)
assert ceiling(y).rewrite(floor).subs(y, -pi) == -floor(pi)
assert ceiling(y).rewrite(floor).subs(y, E) == -floor(-E)
assert ceiling(y).rewrite(frac).subs(y, pi) == ceiling(pi)
assert ceiling(y).rewrite(frac).subs(y, -E) == ceiling(-E)
assert Eq(ceiling(y), y + frac(-y))
assert Eq(ceiling(y), -floor(-y))
neg = Symbol('neg', negative=True)
nn = Symbol('nn', nonnegative=True)
pos = Symbol('pos', positive=True)
np = Symbol('np', nonpositive=True)
assert (ceiling(neg) <= 0) == True
assert (ceiling(neg) < 0) == (neg <= -1)
assert (ceiling(neg) > 0) == False
assert (ceiling(neg) >= 0) == (neg > -1)
assert (ceiling(neg) > -3) == (neg > -3)
assert (ceiling(neg) <= 10) == (neg <= 10)
assert (ceiling(nn) < 0) == False
assert (ceiling(nn) >= 0) == True
assert (ceiling(pos) < 0) == False
assert (ceiling(pos) <= 0) == False
assert (ceiling(pos) > 0) == True
assert (ceiling(pos) >= 0) == True
assert (ceiling(pos) >= 1) == True
assert (ceiling(pos) > 5) == (pos > 5)
assert (ceiling(np) <= 0) == True
assert (ceiling(np) > 0) == False
assert ceiling(neg).is_positive == False
assert ceiling(neg).is_nonpositive == True
assert ceiling(nn).is_positive is None
assert ceiling(nn).is_nonpositive is None
assert ceiling(pos).is_positive == True
assert ceiling(pos).is_nonpositive == False
assert ceiling(np).is_positive == False
assert ceiling(np).is_nonpositive == True
assert (ceiling(7, evaluate=False) >= 7) == True
assert (ceiling(7, evaluate=False) > 7) == False
assert (ceiling(7, evaluate=False) <= 7) == True
assert (ceiling(7, evaluate=False) < 7) == False
assert (ceiling(7, evaluate=False) >= 6) == True
assert (ceiling(7, evaluate=False) > 6) == True
assert (ceiling(7, evaluate=False) <= 6) == False
assert (ceiling(7, evaluate=False) < 6) == False
assert (ceiling(7, evaluate=False) >= 8) == False
assert (ceiling(7, evaluate=False) > 8) == False
assert (ceiling(7, evaluate=False) <= 8) == True
assert (ceiling(7, evaluate=False) < 8) == True
assert (ceiling(x) <= 5.5) == Le(ceiling(x), 5.5, evaluate=False)
assert (ceiling(x) >= -3.2) == Ge(ceiling(x), -3.2, evaluate=False)
assert (ceiling(x) < 2.9) == Lt(ceiling(x), 2.9, evaluate=False)
assert (ceiling(x) > -1.7) == Gt(ceiling(x), -1.7, evaluate=False)
assert (ceiling(y) <= 5.5) == (y <= 5)
assert (ceiling(y) >= -3.2) == (y > -4)
assert (ceiling(y) < 2.9) == (y <= 2)
assert (ceiling(y) > -1.7) == (y > -2)
assert (ceiling(y) <= n) == (y <= n)
assert (ceiling(y) >= n) == (y > n - 1)
assert (ceiling(y) < n) == (y <= n - 1)
assert (ceiling(y) > n) == (y > n)
assert ceiling(RootOf(x**3 - 27*x, 2)) == 6
s = ImageSet(Lambda(n, n + (CRootOf(x**5 - x**2 + 1, 0))), Integers)
f = CRootOf(x**5 - x**2 + 1, 0)
s = ImageSet(Lambda(n, n + f), Integers)
assert s.intersect(Interval(-10, 10)) == {i + f for i in range(-9, 11)}
def test_frac():
assert isinstance(frac(x), frac)
assert frac(oo) == AccumBounds(0, 1)
assert frac(-oo) == AccumBounds(0, 1)
assert frac(zoo) is nan
assert frac(n) == 0
assert frac(nan) is nan
assert frac(Rational(4, 3)) == Rational(1, 3)
assert frac(-Rational(4, 3)) == Rational(2, 3)
assert frac(Rational(-4, 3)) == Rational(2, 3)
r = Symbol('r', real=True)
assert frac(I*r) == I*frac(r)
assert frac(1 + I*r) == I*frac(r)
assert frac(0.5 + I*r) == 0.5 + I*frac(r)
assert frac(n + I*r) == I*frac(r)
assert frac(n + I*k) == 0
assert unchanged(frac, x + I*x)
assert frac(x + I*n) == frac(x)
assert frac(x).rewrite(floor) == x - floor(x)
assert frac(x).rewrite(ceiling) == x + ceiling(-x)
assert frac(y).rewrite(floor).subs(y, pi) == frac(pi)
assert frac(y).rewrite(floor).subs(y, -E) == frac(-E)
assert frac(y).rewrite(ceiling).subs(y, -pi) == frac(-pi)
assert frac(y).rewrite(ceiling).subs(y, E) == frac(E)
assert Eq(frac(y), y - floor(y))
assert Eq(frac(y), y + ceiling(-y))
r = Symbol('r', real=True)
p_i = Symbol('p_i', integer=True, positive=True)
n_i = Symbol('p_i', integer=True, negative=True)
np_i = Symbol('np_i', integer=True, nonpositive=True)
nn_i = Symbol('nn_i', integer=True, nonnegative=True)
p_r = Symbol('p_r', positive=True)
n_r = Symbol('n_r', negative=True)
np_r = Symbol('np_r', real=True, nonpositive=True)
nn_r = Symbol('nn_r', real=True, nonnegative=True)
# Real frac argument, integer rhs
assert frac(r) <= p_i
assert not frac(r) <= n_i
assert (frac(r) <= np_i).has(Le)
assert (frac(r) <= nn_i).has(Le)
assert frac(r) < p_i
assert not frac(r) < n_i
assert not frac(r) < np_i
assert (frac(r) < nn_i).has(Lt)
assert not frac(r) >= p_i
assert frac(r) >= n_i
assert frac(r) >= np_i
assert (frac(r) >= nn_i).has(Ge)
assert not frac(r) > p_i
assert frac(r) > n_i
assert (frac(r) > np_i).has(Gt)
assert (frac(r) > nn_i).has(Gt)
assert not Eq(frac(r), p_i)
assert not Eq(frac(r), n_i)
assert Eq(frac(r), np_i).has(Eq)
assert Eq(frac(r), nn_i).has(Eq)
assert Ne(frac(r), p_i)
assert Ne(frac(r), n_i)
assert Ne(frac(r), np_i).has(Ne)
assert Ne(frac(r), nn_i).has(Ne)
# Real frac argument, real rhs
assert (frac(r) <= p_r).has(Le)
assert not frac(r) <= n_r
assert (frac(r) <= np_r).has(Le)
assert (frac(r) <= nn_r).has(Le)
assert (frac(r) < p_r).has(Lt)
assert not frac(r) < n_r
assert not frac(r) < np_r
assert (frac(r) < nn_r).has(Lt)
assert (frac(r) >= p_r).has(Ge)
assert frac(r) >= n_r
assert frac(r) >= np_r
assert (frac(r) >= nn_r).has(Ge)
assert (frac(r) > p_r).has(Gt)
assert frac(r) > n_r
assert (frac(r) > np_r).has(Gt)
assert (frac(r) > nn_r).has(Gt)
assert not Eq(frac(r), n_r)
assert Eq(frac(r), p_r).has(Eq)
assert Eq(frac(r), np_r).has(Eq)
assert Eq(frac(r), nn_r).has(Eq)
assert Ne(frac(r), p_r).has(Ne)
assert Ne(frac(r), n_r)
assert Ne(frac(r), np_r).has(Ne)
assert Ne(frac(r), nn_r).has(Ne)
# Real frac argument, +/- oo rhs
assert frac(r) < oo
assert frac(r) <= oo
assert not frac(r) > oo
assert not frac(r) >= oo
assert not frac(r) < -oo
assert not frac(r) <= -oo
assert frac(r) > -oo
assert frac(r) >= -oo
assert frac(r) < 1
assert frac(r) <= 1
assert not frac(r) > 1
assert not frac(r) >= 1
assert not frac(r) < 0
assert (frac(r) <= 0).has(Le)
assert (frac(r) > 0).has(Gt)
assert frac(r) >= 0
# Some test for numbers
assert frac(r) <= sqrt(2)
assert (frac(r) <= sqrt(3) - sqrt(2)).has(Le)
assert not frac(r) <= sqrt(2) - sqrt(3)
assert not frac(r) >= sqrt(2)
assert (frac(r) >= sqrt(3) - sqrt(2)).has(Ge)
assert frac(r) >= sqrt(2) - sqrt(3)
assert not Eq(frac(r), sqrt(2))
assert Eq(frac(r), sqrt(3) - sqrt(2)).has(Eq)
assert not Eq(frac(r), sqrt(2) - sqrt(3))
assert Ne(frac(r), sqrt(2))
assert Ne(frac(r), sqrt(3) - sqrt(2)).has(Ne)
assert Ne(frac(r), sqrt(2) - sqrt(3))
assert frac(p_i, evaluate=False).is_zero
assert frac(p_i, evaluate=False).is_finite
assert frac(p_i, evaluate=False).is_integer
assert frac(p_i, evaluate=False).is_real
assert frac(r).is_finite
assert frac(r).is_real
assert frac(r).is_zero is None
assert frac(r).is_integer is None
assert frac(oo).is_finite
assert frac(oo).is_real
def test_series():
x, y = symbols('x,y')
assert floor(x).nseries(x, y, 100) == floor(y)
assert ceiling(x).nseries(x, y, 100) == ceiling(y)
assert floor(x).nseries(x, pi, 100) == 3
assert ceiling(x).nseries(x, pi, 100) == 4
assert floor(x).nseries(x, 0, 100) == 0
assert ceiling(x).nseries(x, 0, 100) == 1
assert floor(-x).nseries(x, 0, 100) == -1
assert ceiling(-x).nseries(x, 0, 100) == 0
def test_issue_14355():
# This test checks the leading term and series for the floor and ceil
# function when arg0 evaluates to S.NaN.
assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -2
assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == -1
assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == -1
assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 0
assert floor(sin(x)/x).as_leading_term(x, cdir = 1) == 0
assert floor(sin(x)/x).as_leading_term(x, cdir = -1) == 0
assert floor(-tan(x)/x).as_leading_term(x, cdir = 1) == -2
assert floor(-tan(x)/x).as_leading_term(x, cdir = -1) == -2
assert floor(sin(x)/x/3).as_leading_term(x, cdir = 1) == 0
assert floor(sin(x)/x/3).as_leading_term(x, cdir = -1) == 0
assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -1
assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == 0
assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == 0
assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 1
assert ceiling(sin(x)/x).as_leading_term(x, cdir = 1) == 1
assert ceiling(sin(x)/x).as_leading_term(x, cdir = -1) == 1
assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = 1) == 1
assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = -1) == 1
# test for series
assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -2
assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == -1
assert ceiling(sin(x)/x).series(x, 0, 100, cdir = 1) == 1
assert ceiling(sin(x)/x).series(x, 0, 100, cdir = -1) == 1
assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -1
assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == 0
def test_frac_leading_term():
assert frac(x).as_leading_term(x) == x
assert frac(x).as_leading_term(x, cdir = 1) == x
assert frac(x).as_leading_term(x, cdir = -1) == 1
assert frac(x + S.Half).as_leading_term(x, cdir = 1) == S.Half
assert frac(x + S.Half).as_leading_term(x, cdir = -1) == S.Half
assert frac(-2*x + 1).as_leading_term(x, cdir = 1) == S.One
assert frac(-2*x + 1).as_leading_term(x, cdir = -1) == -2*x
assert frac(sin(x) + 5).as_leading_term(x, cdir = 1) == x
assert frac(sin(x) + 5).as_leading_term(x, cdir = -1) == S.One
assert frac(sin(x**2) + 5).as_leading_term(x, cdir = 1) == x**2
assert frac(sin(x**2) + 5).as_leading_term(x, cdir = -1) == x**2
@XFAIL
def test_issue_4149():
assert floor(3 + pi*I + y*I) == 3 + floor(pi + y)*I
assert floor(3*I + pi*I + y*I) == floor(3 + pi + y)*I
assert floor(3 + E + pi*I + y*I) == 5 + floor(pi + y)*I
def test_issue_21651():
k = Symbol('k', positive=True, integer=True)
exp = 2*2**(-k)
assert isinstance(floor(exp), floor)
def test_issue_11207():
assert floor(floor(x)) == floor(x)
assert floor(ceiling(x)) == ceiling(x)
assert ceiling(floor(x)) == floor(x)
assert ceiling(ceiling(x)) == ceiling(x)
def test_nested_floor_ceiling():
assert floor(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y)
assert ceiling(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y)
assert floor(ceiling(-floor(x**Rational(7, 2)/y))) == -floor(x**Rational(7, 2)/y)
assert -ceiling(-ceiling(floor(x)/y)) == ceiling(floor(x)/y)
def test_issue_18689():
assert floor(floor(floor(x)) + 3) == floor(x) + 3
assert ceiling(ceiling(ceiling(x)) + 1) == ceiling(x) + 1
assert ceiling(ceiling(floor(x)) + 3) == floor(x) + 3
def test_issue_18421():
assert floor(float(0)) is S.Zero
assert ceiling(float(0)) is S.Zero
def test_issue_25230():
a = Symbol('a', real = True)
b = Symbol('b', positive = True)
c = Symbol('c', negative = True)
raises(NotImplementedError, lambda: floor(x/a).as_leading_term(x, cdir = 1))
raises(NotImplementedError, lambda: ceiling(x/a).as_leading_term(x, cdir = 1))
assert floor(x/b).as_leading_term(x, cdir = 1) == 0
assert floor(x/b).as_leading_term(x, cdir = -1) == -1
assert floor(x/c).as_leading_term(x, cdir = 1) == -1
assert floor(x/c).as_leading_term(x, cdir = -1) == 0
assert ceiling(x/b).as_leading_term(x, cdir = 1) == 1
assert ceiling(x/b).as_leading_term(x, cdir = -1) == 0
assert ceiling(x/c).as_leading_term(x, cdir = 1) == 0
assert ceiling(x/c).as_leading_term(x, cdir = -1) == 1

View File

@ -0,0 +1,72 @@
# This test file tests the SymPy function interface, that people use to create
# their own new functions. It should be as easy as possible.
from sympy.core.function import Function
from sympy.core.sympify import sympify
from sympy.functions.elementary.hyperbolic import tanh
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.series.limits import limit
from sympy.abc import x
def test_function_series1():
"""Create our new "sin" function."""
class my_function(Function):
def fdiff(self, argindex=1):
return cos(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(0)
#Test that the taylor series is correct
assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10)
assert limit(my_function(x)/x, x, 0) == 1
def test_function_series2():
"""Create our new "cos" function."""
class my_function2(Function):
def fdiff(self, argindex=1):
return -sin(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(1)
#Test that the taylor series is correct
assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10)
def test_function_series3():
"""
Test our easy "tanh" function.
This test tests two things:
* that the Function interface works as expected and it's easy to use
* that the general algorithm for the series expansion works even when the
derivative is defined recursively in terms of the original function,
since tanh(x).diff(x) == 1-tanh(x)**2
"""
class mytanh(Function):
def fdiff(self, argindex=1):
return 1 - mytanh(self.args[0])**2
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(0)
e = tanh(x)
f = mytanh(x)
assert e.series(x, 0, 6) == f.series(x, 0, 6)

View File

@ -0,0 +1,504 @@
import itertools as it
from sympy.core.expr import unchanged
from sympy.core.function import Function
from sympy.core.numbers import I, oo, Rational
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.external import import_module
from sympy.functions.elementary.exponential import log
from sympy.functions.elementary.integers import floor, ceiling
from sympy.functions.elementary.miscellaneous import (sqrt, cbrt, root, Min,
Max, real_root, Rem)
from sympy.functions.elementary.trigonometric import cos, sin
from sympy.functions.special.delta_functions import Heaviside
from sympy.utilities.lambdify import lambdify
from sympy.testing.pytest import raises, skip, ignore_warnings
def test_Min():
from sympy.abc import x, y, z
n = Symbol('n', negative=True)
n_ = Symbol('n_', negative=True)
nn = Symbol('nn', nonnegative=True)
nn_ = Symbol('nn_', nonnegative=True)
p = Symbol('p', positive=True)
p_ = Symbol('p_', positive=True)
np = Symbol('np', nonpositive=True)
np_ = Symbol('np_', nonpositive=True)
r = Symbol('r', real=True)
assert Min(5, 4) == 4
assert Min(-oo, -oo) is -oo
assert Min(-oo, n) is -oo
assert Min(n, -oo) is -oo
assert Min(-oo, np) is -oo
assert Min(np, -oo) is -oo
assert Min(-oo, 0) is -oo
assert Min(0, -oo) is -oo
assert Min(-oo, nn) is -oo
assert Min(nn, -oo) is -oo
assert Min(-oo, p) is -oo
assert Min(p, -oo) is -oo
assert Min(-oo, oo) is -oo
assert Min(oo, -oo) is -oo
assert Min(n, n) == n
assert unchanged(Min, n, np)
assert Min(np, n) == Min(n, np)
assert Min(n, 0) == n
assert Min(0, n) == n
assert Min(n, nn) == n
assert Min(nn, n) == n
assert Min(n, p) == n
assert Min(p, n) == n
assert Min(n, oo) == n
assert Min(oo, n) == n
assert Min(np, np) == np
assert Min(np, 0) == np
assert Min(0, np) == np
assert Min(np, nn) == np
assert Min(nn, np) == np
assert Min(np, p) == np
assert Min(p, np) == np
assert Min(np, oo) == np
assert Min(oo, np) == np
assert Min(0, 0) == 0
assert Min(0, nn) == 0
assert Min(nn, 0) == 0
assert Min(0, p) == 0
assert Min(p, 0) == 0
assert Min(0, oo) == 0
assert Min(oo, 0) == 0
assert Min(nn, nn) == nn
assert unchanged(Min, nn, p)
assert Min(p, nn) == Min(nn, p)
assert Min(nn, oo) == nn
assert Min(oo, nn) == nn
assert Min(p, p) == p
assert Min(p, oo) == p
assert Min(oo, p) == p
assert Min(oo, oo) is oo
assert Min(n, n_).func is Min
assert Min(nn, nn_).func is Min
assert Min(np, np_).func is Min
assert Min(p, p_).func is Min
# lists
assert Min() is S.Infinity
assert Min(x) == x
assert Min(x, y) == Min(y, x)
assert Min(x, y, z) == Min(z, y, x)
assert Min(x, Min(y, z)) == Min(z, y, x)
assert Min(x, Max(y, -oo)) == Min(x, y)
assert Min(p, oo, n, p, p, p_) == n
assert Min(p_, n_, p) == n_
assert Min(n, oo, -7, p, p, 2) == Min(n, -7)
assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_)
assert Min(0, x, 1, y) == Min(0, x, y)
assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100)
assert unchanged(Min, sin(x), cos(x))
assert Min(sin(x), cos(x)) == Min(cos(x), sin(x))
assert Min(cos(x), sin(x)).subs(x, 1) == cos(1)
assert Min(cos(x), sin(x)).subs(x, S.Half) == sin(S.Half)
raises(ValueError, lambda: Min(cos(x), sin(x)).subs(x, I))
raises(ValueError, lambda: Min(I))
raises(ValueError, lambda: Min(I, x))
raises(ValueError, lambda: Min(S.ComplexInfinity, x))
assert Min(1, x).diff(x) == Heaviside(1 - x)
assert Min(x, 1).diff(x) == Heaviside(1 - x)
assert Min(0, -x, 1 - 2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \
- 2*Heaviside(2*x + Min(0, -x) - 1)
# issue 7619
f = Function('f')
assert Min(1, 2*Min(f(1), 2)) # doesn't fail
# issue 7233
e = Min(0, x)
assert e.n().args == (0, x)
# issue 8643
m = Min(n, p_, n_, r)
assert m.is_positive is False
assert m.is_nonnegative is False
assert m.is_negative is True
m = Min(p, p_)
assert m.is_positive is True
assert m.is_nonnegative is True
assert m.is_negative is False
m = Min(p, nn_, p_)
assert m.is_positive is None
assert m.is_nonnegative is True
assert m.is_negative is False
m = Min(nn, p, r)
assert m.is_positive is None
assert m.is_nonnegative is None
assert m.is_negative is None
def test_Max():
from sympy.abc import x, y, z
n = Symbol('n', negative=True)
n_ = Symbol('n_', negative=True)
nn = Symbol('nn', nonnegative=True)
p = Symbol('p', positive=True)
p_ = Symbol('p_', positive=True)
r = Symbol('r', real=True)
assert Max(5, 4) == 5
# lists
assert Max() is S.NegativeInfinity
assert Max(x) == x
assert Max(x, y) == Max(y, x)
assert Max(x, y, z) == Max(z, y, x)
assert Max(x, Max(y, z)) == Max(z, y, x)
assert Max(x, Min(y, oo)) == Max(x, y)
assert Max(n, -oo, n_, p, 2) == Max(p, 2)
assert Max(n, -oo, n_, p) == p
assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p)
assert Max(0, x, 1, y) == Max(1, x, y)
assert Max(r, r + 1, r - 1) == 1 + r
assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000)
assert Max(cos(x), sin(x)) == Max(sin(x), cos(x))
assert Max(cos(x), sin(x)).subs(x, 1) == sin(1)
assert Max(cos(x), sin(x)).subs(x, S.Half) == cos(S.Half)
raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I))
raises(ValueError, lambda: Max(I))
raises(ValueError, lambda: Max(I, x))
raises(ValueError, lambda: Max(S.ComplexInfinity, 1))
assert Max(n, -oo, n_, p, 2) == Max(p, 2)
assert Max(n, -oo, n_, p, 1000) == Max(p, 1000)
assert Max(1, x).diff(x) == Heaviside(x - 1)
assert Max(x, 1).diff(x) == Heaviside(x - 1)
assert Max(x**2, 1 + x, 1).diff(x) == \
2*x*Heaviside(x**2 - Max(1, x + 1)) \
+ Heaviside(x - Max(1, x**2) + 1)
e = Max(0, x)
assert e.n().args == (0, x)
# issue 8643
m = Max(p, p_, n, r)
assert m.is_positive is True
assert m.is_nonnegative is True
assert m.is_negative is False
m = Max(n, n_)
assert m.is_positive is False
assert m.is_nonnegative is False
assert m.is_negative is True
m = Max(n, n_, r)
assert m.is_positive is None
assert m.is_nonnegative is None
assert m.is_negative is None
m = Max(n, nn, r)
assert m.is_positive is None
assert m.is_nonnegative is True
assert m.is_negative is False
def test_minmax_assumptions():
r = Symbol('r', real=True)
a = Symbol('a', real=True, algebraic=True)
t = Symbol('t', real=True, transcendental=True)
q = Symbol('q', rational=True)
p = Symbol('p', irrational=True)
n = Symbol('n', rational=True, integer=False)
i = Symbol('i', integer=True)
o = Symbol('o', odd=True)
e = Symbol('e', even=True)
k = Symbol('k', prime=True)
reals = [r, a, t, q, p, n, i, o, e, k]
for ext in (Max, Min):
for x, y in it.product(reals, repeat=2):
# Must be real
assert ext(x, y).is_real
# Algebraic?
if x.is_algebraic and y.is_algebraic:
assert ext(x, y).is_algebraic
elif x.is_transcendental and y.is_transcendental:
assert ext(x, y).is_transcendental
else:
assert ext(x, y).is_algebraic is None
# Rational?
if x.is_rational and y.is_rational:
assert ext(x, y).is_rational
elif x.is_irrational and y.is_irrational:
assert ext(x, y).is_irrational
else:
assert ext(x, y).is_rational is None
# Integer?
if x.is_integer and y.is_integer:
assert ext(x, y).is_integer
elif x.is_noninteger and y.is_noninteger:
assert ext(x, y).is_noninteger
else:
assert ext(x, y).is_integer is None
# Odd?
if x.is_odd and y.is_odd:
assert ext(x, y).is_odd
elif x.is_odd is False and y.is_odd is False:
assert ext(x, y).is_odd is False
else:
assert ext(x, y).is_odd is None
# Even?
if x.is_even and y.is_even:
assert ext(x, y).is_even
elif x.is_even is False and y.is_even is False:
assert ext(x, y).is_even is False
else:
assert ext(x, y).is_even is None
# Prime?
if x.is_prime and y.is_prime:
assert ext(x, y).is_prime
elif x.is_prime is False and y.is_prime is False:
assert ext(x, y).is_prime is False
else:
assert ext(x, y).is_prime is None
def test_issue_8413():
x = Symbol('x', real=True)
# we can't evaluate in general because non-reals are not
# comparable: Min(floor(3.2 + I), 3.2 + I) -> ValueError
assert Min(floor(x), x) == floor(x)
assert Min(ceiling(x), x) == x
assert Max(floor(x), x) == x
assert Max(ceiling(x), x) == ceiling(x)
def test_root():
from sympy.abc import x
n = Symbol('n', integer=True)
k = Symbol('k', integer=True)
assert root(2, 2) == sqrt(2)
assert root(2, 1) == 2
assert root(2, 3) == 2**Rational(1, 3)
assert root(2, 3) == cbrt(2)
assert root(2, -5) == 2**Rational(4, 5)/2
assert root(-2, 1) == -2
assert root(-2, 2) == sqrt(2)*I
assert root(-2, 1) == -2
assert root(x, 2) == sqrt(x)
assert root(x, 1) == x
assert root(x, 3) == x**Rational(1, 3)
assert root(x, 3) == cbrt(x)
assert root(x, -5) == x**Rational(-1, 5)
assert root(x, n) == x**(1/n)
assert root(x, -n) == x**(-1/n)
assert root(x, n, k) == (-1)**(2*k/n)*x**(1/n)
def test_real_root():
assert real_root(-8, 3) == -2
assert real_root(-16, 4) == root(-16, 4)
r = root(-7, 4)
assert real_root(r) == r
r1 = root(-1, 3)
r2 = r1**2
r3 = root(-1, 4)
assert real_root(r1 + r2 + r3) == -1 + r2 + r3
assert real_root(root(-2, 3)) == -root(2, 3)
assert real_root(-8., 3) == -2.0
x = Symbol('x')
n = Symbol('n')
g = real_root(x, n)
assert g.subs({"x": -8, "n": 3}) == -2
assert g.subs({"x": 8, "n": 3}) == 2
# give principle root if there is no real root -- if this is not desired
# then maybe a Root class is needed to raise an error instead
assert g.subs({"x": I, "n": 3}) == cbrt(I)
assert g.subs({"x": -8, "n": 2}) == sqrt(-8)
assert g.subs({"x": I, "n": 2}) == sqrt(I)
def test_issue_11463():
numpy = import_module('numpy')
if not numpy:
skip("numpy not installed.")
x = Symbol('x')
f = lambdify(x, real_root((log(x/(x-2))), 3), 'numpy')
# numpy.select evaluates all options before considering conditions,
# so it raises a warning about root of negative number which does
# not affect the outcome. This warning is suppressed here
with ignore_warnings(RuntimeWarning):
assert f(numpy.array(-1)) < -1
def test_rewrite_MaxMin_as_Heaviside():
from sympy.abc import x
assert Max(0, x).rewrite(Heaviside) == x*Heaviside(x)
assert Max(3, x).rewrite(Heaviside) == x*Heaviside(x - 3) + \
3*Heaviside(-x + 3)
assert Max(0, x+2, 2*x).rewrite(Heaviside) == \
2*x*Heaviside(2*x)*Heaviside(x - 2) + \
(x + 2)*Heaviside(-x + 2)*Heaviside(x + 2)
assert Min(0, x).rewrite(Heaviside) == x*Heaviside(-x)
assert Min(3, x).rewrite(Heaviside) == x*Heaviside(-x + 3) + \
3*Heaviside(x - 3)
assert Min(x, -x, -2).rewrite(Heaviside) == \
x*Heaviside(-2*x)*Heaviside(-x - 2) - \
x*Heaviside(2*x)*Heaviside(x - 2) \
- 2*Heaviside(-x + 2)*Heaviside(x + 2)
def test_rewrite_MaxMin_as_Piecewise():
from sympy.core.symbol import symbols
from sympy.functions.elementary.piecewise import Piecewise
x, y, z, a, b = symbols('x y z a b', real=True)
vx, vy, va = symbols('vx vy va')
assert Max(a, b).rewrite(Piecewise) == Piecewise((a, a >= b), (b, True))
assert Max(x, y, z).rewrite(Piecewise) == Piecewise((x, (x >= y) & (x >= z)), (y, y >= z), (z, True))
assert Max(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a >= b) & (a >= x) & (a >= y)),
(b, (b >= x) & (b >= y)), (x, x >= y), (y, True))
assert Min(a, b).rewrite(Piecewise) == Piecewise((a, a <= b), (b, True))
assert Min(x, y, z).rewrite(Piecewise) == Piecewise((x, (x <= y) & (x <= z)), (y, y <= z), (z, True))
assert Min(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a <= b) & (a <= x) & (a <= y)),
(b, (b <= x) & (b <= y)), (x, x <= y), (y, True))
# Piecewise rewriting of Min/Max does also takes place for not explicitly real arguments
assert Max(vx, vy).rewrite(Piecewise) == Piecewise((vx, vx >= vy), (vy, True))
assert Min(va, vx, vy).rewrite(Piecewise) == Piecewise((va, (va <= vx) & (va <= vy)), (vx, vx <= vy), (vy, True))
def test_issue_11099():
from sympy.abc import x, y
# some fixed value tests
fixed_test_data = {x: -2, y: 3}
assert Min(x, y).evalf(subs=fixed_test_data) == \
Min(x, y).subs(fixed_test_data).evalf()
assert Max(x, y).evalf(subs=fixed_test_data) == \
Max(x, y).subs(fixed_test_data).evalf()
# randomly generate some test data
from sympy.core.random import randint
for i in range(20):
random_test_data = {x: randint(-100, 100), y: randint(-100, 100)}
assert Min(x, y).evalf(subs=random_test_data) == \
Min(x, y).subs(random_test_data).evalf()
assert Max(x, y).evalf(subs=random_test_data) == \
Max(x, y).subs(random_test_data).evalf()
def test_issue_12638():
from sympy.abc import a, b, c
assert Min(a, b, c, Max(a, b)) == Min(a, b, c)
assert Min(a, b, Max(a, b, c)) == Min(a, b)
assert Min(a, b, Max(a, c)) == Min(a, b)
def test_issue_21399():
from sympy.abc import a, b, c
assert Max(Min(a, b), Min(a, b, c)) == Min(a, b)
def test_instantiation_evaluation():
from sympy.abc import v, w, x, y, z
assert Min(1, Max(2, x)) == 1
assert Max(3, Min(2, x)) == 3
assert Min(Max(x, y), Max(x, z)) == Max(x, Min(y, z))
assert set(Min(Max(w, x), Max(y, z)).args) == {
Max(w, x), Max(y, z)}
assert Min(Max(x, y), Max(x, z), w) == Min(
w, Max(x, Min(y, z)))
A, B = Min, Max
for i in range(2):
assert A(x, B(x, y)) == x
assert A(x, B(y, A(x, w, z))) == A(x, B(y, A(w, z)))
A, B = B, A
assert Min(w, Max(x, y), Max(v, x, z)) == Min(
w, Max(x, Min(y, Max(v, z))))
def test_rewrite_as_Abs():
from itertools import permutations
from sympy.functions.elementary.complexes import Abs
from sympy.abc import x, y, z, w
def test(e):
free = e.free_symbols
a = e.rewrite(Abs)
assert not a.has(Min, Max)
for i in permutations(range(len(free))):
reps = dict(zip(free, i))
assert a.xreplace(reps) == e.xreplace(reps)
test(Min(x, y))
test(Max(x, y))
test(Min(x, y, z))
test(Min(Max(w, x), Max(y, z)))
def test_issue_14000():
assert isinstance(sqrt(4, evaluate=False), Pow) == True
assert isinstance(cbrt(3.5, evaluate=False), Pow) == True
assert isinstance(root(16, 4, evaluate=False), Pow) == True
assert sqrt(4, evaluate=False) == Pow(4, S.Half, evaluate=False)
assert cbrt(3.5, evaluate=False) == Pow(3.5, Rational(1, 3), evaluate=False)
assert root(4, 2, evaluate=False) == Pow(4, S.Half, evaluate=False)
assert root(16, 4, 2, evaluate=False).has(Pow) == True
assert real_root(-8, 3, evaluate=False).has(Pow) == True
def test_issue_6899():
from sympy.core.function import Lambda
x = Symbol('x')
eqn = Lambda(x, x)
assert eqn.func(*eqn.args) == eqn
def test_Rem():
from sympy.abc import x, y
assert Rem(5, 3) == 2
assert Rem(-5, 3) == -2
assert Rem(5, -3) == 2
assert Rem(-5, -3) == -2
assert Rem(x**3, y) == Rem(x**3, y)
assert Rem(Rem(-5, 3) + 3, 3) == 1
def test_minmax_no_evaluate():
from sympy import evaluate
p = Symbol('p', positive=True)
assert Max(1, 3) == 3
assert Max(1, 3).args == ()
assert Max(0, p) == p
assert Max(0, p).args == ()
assert Min(0, p) == 0
assert Min(0, p).args == ()
assert Max(1, 3, evaluate=False) != 3
assert Max(1, 3, evaluate=False).args == (1, 3)
assert Max(0, p, evaluate=False) != p
assert Max(0, p, evaluate=False).args == (0, p)
assert Min(0, p, evaluate=False) != 0
assert Min(0, p, evaluate=False).args == (0, p)
with evaluate(False):
assert Max(1, 3) != 3
assert Max(1, 3).args == (1, 3)
assert Max(0, p) != p
assert Max(0, p).args == (0, p)
assert Min(0, p) != 0
assert Min(0, p).args == (0, p)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff