switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# Stub __init__.py for sympy.functions.elementary
|
||||
+261
@@ -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
|
||||
}
|
||||
+11
@@ -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
@@ -0,0 +1,710 @@
|
||||
from __future__ import annotations
|
||||
|
||||
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 DefinedFunction
|
||||
from sympy.core.logic import fuzzy_or, fuzzy_and
|
||||
from sympy.core.numbers import Integer, int_valued
|
||||
from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq, is_le, is_lt
|
||||
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(DefinedFunction):
|
||||
"""Abstract base class for rounding functions."""
|
||||
|
||||
args: tuple[Expr]
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
if (v := cls._eval_number(arg)) is not None:
|
||||
return v
|
||||
if (v := cls._eval_const_number(arg)) 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()
|
||||
if 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]
|
||||
|
||||
@classmethod
|
||||
def _eval_const_number(cls, arg):
|
||||
if arg.is_real:
|
||||
if arg.is_zero:
|
||||
return S.Zero
|
||||
if arg.is_positive:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# 0 <= num/den < 1 -> 0
|
||||
if is_lt(num, den):
|
||||
return S.Zero
|
||||
# 1 <= num/den < 2 -> 1
|
||||
if fuzzy_and([is_le(den, num), is_lt(num, 2*den)]):
|
||||
return S.One
|
||||
if arg.is_negative:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# -1 <= num/den < 0 -> -1
|
||||
if is_le(-den, num):
|
||||
return S.NegativeOne
|
||||
# -2 <= num/den < -1 -> -2
|
||||
if fuzzy_and([is_le(-2*den, num), is_lt(num, -den)]):
|
||||
return Integer(-2)
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
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 and other.is_noninteger:
|
||||
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 and other.is_noninteger:
|
||||
return S.true
|
||||
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()
|
||||
if 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]
|
||||
|
||||
@classmethod
|
||||
def _eval_const_number(cls, arg):
|
||||
if arg.is_real:
|
||||
if arg.is_zero:
|
||||
return S.Zero
|
||||
if arg.is_positive:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# 0 < num/den <= 1 -> 1
|
||||
if is_le(num, den):
|
||||
return S.One
|
||||
# 1 < num/den <= 2 -> 2
|
||||
if fuzzy_and([is_lt(den, num), is_le(num, 2*den)]):
|
||||
return Integer(2)
|
||||
if arg.is_negative:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# -1 < num/den <= 0 -> 0
|
||||
if is_lt(-den, num):
|
||||
return S.Zero
|
||||
# -2 < num/den <= -1 -> -1
|
||||
if fuzzy_and([is_lt(-2*den, num), is_le(num, -den)]):
|
||||
return S.NegativeOne
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
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 and other.is_noninteger:
|
||||
return S.true
|
||||
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 and other.is_noninteger:
|
||||
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(DefinedFunction):
|
||||
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, cdir):
|
||||
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
|
||||
@@ -0,0 +1,915 @@
|
||||
from sympy.core import 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, DefinedFunction)
|
||||
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 = super().fdiff(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(DefinedFunction):
|
||||
"""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
+1030
File diff suppressed because it is too large
Load Diff
+810
@@ -0,0 +1,810 @@
|
||||
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():
|
||||
x = Symbol('x', commutative=False)
|
||||
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) + 2*sqrt(3)*I*x**2/(3*sqrt(3) + 6) + 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(-log(2)/2) == -log(2)
|
||||
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 - 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)
|
||||
+1553
File diff suppressed because it is too large
Load Diff
+688
@@ -0,0 +1,688 @@
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
from sympy.core.numbers import (E, Float, I, Rational, Integer, 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, asin
|
||||
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)
|
||||
b = Symbol('b', real=True, noninteger=True)
|
||||
m = Symbol('m', positive=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(I*log(asin(5)/abs(asin(5)))) == 0
|
||||
assert floor(-I*log(asin(7)/abs(asin(7)))) == -2
|
||||
|
||||
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(1/(m+1)) == S.Zero
|
||||
assert floor((m+2)/(m+1)) == S.One
|
||||
assert floor(-1/(m+1)) == S.NegativeOne
|
||||
assert floor((m+2)/(-m-1)) == Integer(-2)
|
||||
|
||||
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).is_Relational
|
||||
assert (floor(y) <= y) == True
|
||||
assert (floor(y) > y) == False
|
||||
assert (floor(y) >= y).is_Relational
|
||||
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(b) < b) == True
|
||||
assert (floor(b) <= b) == True
|
||||
assert (floor(b) > b) == False
|
||||
assert (floor(b) >= b) == False
|
||||
|
||||
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(I*log(asin(5)/abs(asin(5)))) == 1
|
||||
assert ceiling(-I*log(asin(7)/abs(asin(7)))) == -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(1/(m+1)) == S.One
|
||||
assert ceiling((m+2)/(m+1)) == Integer(2)
|
||||
assert ceiling(-1/(m+1)) == S.Zero
|
||||
assert ceiling((m+2)/(-m-1)) == S.NegativeOne
|
||||
|
||||
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).is_Relational
|
||||
assert (ceiling(y) < y) == False
|
||||
assert (ceiling(y) <= y).is_Relational
|
||||
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(b) < b) == False
|
||||
assert (ceiling(b) <= b) == False
|
||||
assert (ceiling(b) > b) == True
|
||||
assert (ceiling(b) >= b) == 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
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# This test file tests the SymPy function interface, that people use to create
|
||||
# their own new functions. It should be as easy as possible.
|
||||
#
|
||||
# We test that it works with both Function and DefinedFunction. New code should
|
||||
# use DefinedFunction because it has better type inference. Old code still
|
||||
# using Function should continue to work though.
|
||||
from sympy.core.function import Function, DefinedFunction
|
||||
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."""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class my_function(F):
|
||||
|
||||
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."""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class my_function2(F):
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class mytanh(F):
|
||||
|
||||
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)
|
||||
+504
@@ -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)
|
||||
+1639
File diff suppressed because it is too large
Load Diff
+2236
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user