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