diff --git a/sympy/core/assumptions.py b/sympy/core/assumptions.py index 8e82a24f3c31..3d71d15749b4 100644 --- a/sympy/core/assumptions.py +++ b/sympy/core/assumptions.py @@ -165,14 +165,14 @@ 'integer -> rational', 'rational -> real', 'rational -> algebraic', - 'algebraic -> complex & finite', - 'transcendental == complex & !algebraic & finite', + 'algebraic -> complex', + 'transcendental == complex & !algebraic', 'real -> hermitian', - 'imaginary -> complex & finite', + 'imaginary -> complex', 'imaginary -> antihermitian', 'extended_real -> commutative', 'complex -> commutative', - 'complex -> infinite | finite', + 'complex -> finite', 'odd == integer & !even', 'even == integer & !odd', diff --git a/sympy/core/expr.py b/sympy/core/expr.py index 5a12227e2677..7ccdac7557a9 100644 --- a/sympy/core/expr.py +++ b/sympy/core/expr.py @@ -1066,7 +1066,7 @@ def conjugate(self): def _eval_transpose(self): from sympy.functions.elementary.complexes import conjugate - if self.is_complex: + if (self.is_complex or self.is_infinite): return self elif self.is_hermitian: return conjugate(self) diff --git a/sympy/core/mul.py b/sympy/core/mul.py index da2a8b18e760..c74ddace5525 100644 --- a/sympy/core/mul.py +++ b/sympy/core/mul.py @@ -1196,8 +1196,17 @@ def _eval_is_algebraic_expr(self, syms): _eval_is_commutative = lambda self: _fuzzy_group( a.is_commutative for a in self.args) - _eval_is_complex = lambda self: _fuzzy_group( - (a.is_complex for a in self.args), quick_exit=True) + + def _eval_is_complex(self): + comp = _fuzzy_group((a.is_complex for a in self.args)) + if comp is False: + if any(a.is_infinite for a in self.args): + if any(a.is_zero for a in self.args): + return S.NaN.is_infinite + if any(a.is_zero is None for a in self.args): + return None + return False + return comp def _eval_is_finite(self): if all(a.is_finite for a in self.args): @@ -1270,7 +1279,7 @@ def _eval_real_imag(self, real): t_not_re_im = None for t in self.args: - if t.is_complex is False and t.is_extended_real is False: + if (t.is_complex or t.is_infinite) is False and t.is_extended_real is False: return False elif t.is_imaginary: # I real = not real diff --git a/sympy/core/numbers.py b/sympy/core/numbers.py index 98069502ad23..c9c9a96f3cdc 100644 --- a/sympy/core/numbers.py +++ b/sympy/core/numbers.py @@ -3345,7 +3345,7 @@ class ComplexInfinity(with_metaclass(Singleton, AtomicExpr)): is_infinite = True is_number = True is_prime = False - is_complex = True + is_complex = False is_extended_real = False __slots__ = [] diff --git a/sympy/core/power.py b/sympy/core/power.py index 4a0d08c0a6e3..151a6cabd9b2 100644 --- a/sympy/core/power.py +++ b/sympy/core/power.py @@ -597,7 +597,8 @@ def _eval_is_extended_real(self): return i.is_integer def _eval_is_complex(self): - if all(a.is_complex for a in self.args): + + if all(a.is_complex for a in self.args) and self._eval_is_finite(): return True def _eval_is_imaginary(self): @@ -849,7 +850,7 @@ def _eval_conjugate(self): def _eval_transpose(self): from sympy.functions.elementary.complexes import transpose - i, p = self.exp.is_integer, self.base.is_complex + i, p = self.exp.is_integer, (self.base.is_complex or self.base.is_infinite) if p: return self.base**self.exp if i: diff --git a/sympy/core/tests/test_arit.py b/sympy/core/tests/test_arit.py index c6b3c71df0c7..f4459e7b84b0 100644 --- a/sympy/core/tests/test_arit.py +++ b/sympy/core/tests/test_arit.py @@ -1295,7 +1295,7 @@ def test_Mul_is_imaginary_real(): assert (r*i1*i2).is_real is True # Github's issue 5874: - nr = Symbol('nr', real=False, complex=True, finite=True) # e.g. I or 1 + I + nr = Symbol('nr', real=False, complex=True) # e.g. I or 1 + I a = Symbol('a', real=True, nonzero=True) b = Symbol('b', real=True) assert (i1*nr).is_real is None @@ -1898,38 +1898,38 @@ def test_mul_coeff(): def test_mul_zero_detection(): - nz = Dummy(real=True, zero=False, finite=True) - r = Dummy(real=True) - c = Dummy(real=False, complex=True, finite=True) - c2 = Dummy(real=False, complex=True, finite=True) - i = Dummy(imaginary=True, finite=True) + nz = Dummy(real=True, zero=False) + r = Dummy(extended_real=True) + c = Dummy(real=False, complex=True) + c2 = Dummy(real=False, complex=True) + i = Dummy(imaginary=True) e = nz*r*c assert e.is_imaginary is None - assert e.is_real is None + assert e.is_extended_real is None e = nz*c assert e.is_imaginary is None - assert e.is_real is False + assert e.is_extended_real is False e = nz*i*c assert e.is_imaginary is False - assert e.is_real is None + assert e.is_extended_real is None # check for more than one complex; it is important to use # uniquely named Symbols to ensure that two factors appear # e.g. if the symbols have the same name they just become # a single factor, a power. e = nz*i*c*c2 assert e.is_imaginary is None - assert e.is_real is None + assert e.is_extended_real is None - # _eval_is_real and _eval_is_zero both employ trapping of the + # _eval_is_extended_real and _eval_is_zero both employ trapping of the # zero value so args should be tested in both directions and # TO AVOID GETTING THE CACHED RESULT, Dummy MUST BE USED # real is unknown def test(z, b, e): if z.is_zero and b.is_finite: - assert e.is_real and e.is_zero + assert e.is_extended_real and e.is_zero else: - assert e.is_real is None + assert e.is_extended_real is None if b.is_finite: if z.is_zero: assert e.is_zero @@ -1974,11 +1974,11 @@ def test_Mul_with_zero_infinite(): inf = Dummy(finite=False) e = Mul(zer, inf, evaluate=False) - assert e.is_positive is None + assert e.is_extended_positive is None assert e.is_hermitian is None e = Mul(inf, zer, evaluate=False) - assert e.is_positive is None + assert e.is_extended_positive is None assert e.is_hermitian is None def test_Mul_does_not_cancel_infinities(): diff --git a/sympy/core/tests/test_assumptions.py b/sympy/core/tests/test_assumptions.py index b5f587399a6b..9b400e148bf7 100644 --- a/sympy/core/tests/test_assumptions.py +++ b/sympy/core/tests/test_assumptions.py @@ -164,7 +164,7 @@ def test_neg_infinity(): def test_zoo(): zoo = S.ComplexInfinity - assert zoo.is_complex + assert zoo.is_complex is False assert zoo.is_real is False assert zoo.is_prime is False @@ -1132,10 +1132,13 @@ def test_issue_16313(): assert (-x).is_positive is False def test_issue_16579(): - # complex -> finite | infinite - # with work on PR 16603 it may be changed in future to complex -> finite - x = Symbol('x', complex=True, finite=False) - y = Symbol('x', real=True, infinite=False) - - assert x.is_infinite - assert y.is_finite + # extended_real -> finite | infinite + x = Symbol('x', extended_real=True, infinite=False) + y = Symbol('y', extended_real=True, finite=False) + assert x.is_finite + assert y.is_infinite + + # With PR 16978, complex now implies finite + c = Symbol('c', complex=True) + assert c.is_finite + raises(InconsistentAssumptions, lambda: Dummy(complex=True, finite=False)) diff --git a/sympy/functions/elementary/complexes.py b/sympy/functions/elementary/complexes.py index b91aa60d7ea5..9d9aca940f51 100644 --- a/sympy/functions/elementary/complexes.py +++ b/sympy/functions/elementary/complexes.py @@ -284,7 +284,6 @@ class sign(Function): Abs, conjugate """ - is_finite = True is_complex = True def doit(self, **hints): diff --git a/sympy/functions/elementary/exponential.py b/sympy/functions/elementary/exponential.py index 3fdee4fe9755..4094ccd084cf 100644 --- a/sympy/functions/elementary/exponential.py +++ b/sympy/functions/elementary/exponential.py @@ -81,9 +81,9 @@ def _eval_conjugate(self): def _eval_is_finite(self): arg = self.args[0] if arg.is_infinite: - if arg.is_negative: + if arg.is_extended_negative: return True - if arg.is_positive: + if arg.is_extended_positive: return False if arg.is_finite: return True diff --git a/sympy/functions/elementary/tests/test_complexes.py b/sympy/functions/elementary/tests/test_complexes.py index 00876965708f..2092a3bdd5f9 100644 --- a/sympy/functions/elementary/tests/test_complexes.py +++ b/sympy/functions/elementary/tests/test_complexes.py @@ -524,10 +524,10 @@ def test_Abs_properties(): assert Abs(f).is_extended_nonnegative is True z = Symbol('z', complex=True, zero=False) - assert Abs(z).is_real is None + assert Abs(z).is_real is True # since complex implies finite assert Abs(z).is_extended_real is True assert Abs(z).is_rational is None - assert Abs(z).is_positive is None + assert Abs(z).is_positive is True assert Abs(z).is_extended_positive is True assert Abs(z).is_zero is False diff --git a/sympy/functions/elementary/trigonometric.py b/sympy/functions/elementary/trigonometric.py index b7a0ad11cb40..72e41b35e01f 100644 --- a/sympy/functions/elementary/trigonometric.py +++ b/sympy/functions/elementary/trigonometric.py @@ -476,6 +476,11 @@ def _eval_is_finite(self): if arg.is_extended_real: return True + def _eval_is_complex(self): + if self.args[0].is_extended_real \ + or self.args[0].is_complex: + return True + class cos(TrigonometricFunction): """ @@ -904,6 +909,11 @@ def _eval_is_finite(self): if arg.is_extended_real: return True + def _eval_is_complex(self): + if self.args[0].is_extended_real \ + or self.args[0].is_complex: + return True + class tan(TrigonometricFunction): """ @@ -1209,6 +1219,7 @@ def _eval_as_leading_term(self, x): return self.func(arg) def _eval_is_extended_real(self): + # FIXME: currently tan(pi/2) return zoo return self.args[0].is_extended_real def _eval_is_real(self): @@ -1219,9 +1230,18 @@ def _eval_is_real(self): def _eval_is_finite(self): arg = self.args[0] + if arg.is_real and (arg / pi - S.Half).is_integer is False: + return True + if arg.is_imaginary: return True + def _eval_is_complex(self): + arg = self.args[0] + + if arg.is_real and (arg / pi - S.Half).is_integer is False: + return True + class cot(TrigonometricFunction): """ @@ -1505,9 +1525,21 @@ def _eval_expand_trig(self, **hints): def _eval_is_finite(self): arg = self.args[0] + if arg.is_real and (arg/pi).is_integer is False: + return True if arg.is_imaginary: return True + def _eval_is_real(self): + arg = self.args[0] + if arg.is_real and (arg/pi).is_integer is False: + return True + + def _eval_is_complex(self): + arg = self.args[0] + if arg.is_real and (arg / pi).is_integer is False: + return True + def _eval_subs(self, old, new): arg = self.args[0] argnew = arg.subs(old, new) @@ -1700,6 +1732,12 @@ def fdiff(self, argindex=1): else: raise ArgumentIndexError(self, argindex) + def _eval_is_complex(self): + arg = self.args[0] + + if arg.is_real and (arg / pi - S.Half).is_integer is False: + return True + @staticmethod @cacheit def taylor_term(n, x, *previous_terms): @@ -1781,6 +1819,11 @@ def fdiff(self, argindex=1): else: raise ArgumentIndexError(self, argindex) + def _eval_is_complex(self): + arg = self.args[0] + if arg.is_real and (arg / pi).is_integer is False: + return True + @staticmethod @cacheit def taylor_term(n, x, *previous_terms): diff --git a/sympy/functions/special/tests/test_zeta_functions.py b/sympy/functions/special/tests/test_zeta_functions.py index 9709e4f37dfe..a81113f4ff36 100644 --- a/sympy/functions/special/tests/test_zeta_functions.py +++ b/sympy/functions/special/tests/test_zeta_functions.py @@ -217,8 +217,8 @@ def test_stieltjes_evalf(): def test_issue_10475(): - a = Symbol('a', real=True) - b = Symbol('b', positive=True) + a = Symbol('a', extended_real=True) + b = Symbol('b', extended_positive=True) s = Symbol('s', zero=False) assert zeta(2 + I).is_finite diff --git a/sympy/physics/wigner.py b/sympy/physics/wigner.py index 4c41075c4a67..a157d9e47eca 100644 --- a/sympy/physics/wigner.py +++ b/sympy/physics/wigner.py @@ -196,7 +196,7 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3): _Factlist[int(j_1 + j_2 + j_3 + 1)] ressqrt = sqrt(argsqrt) - if ressqrt.is_complex: + if ressqrt.is_complex or ressqrt.is_infinite: ressqrt = ressqrt.as_real_imag()[0] imin = max(-j_3 + j_1 + m_2, -j_3 + j_2 - m_1, 0) diff --git a/sympy/printing/fcode.py b/sympy/printing/fcode.py index 4648ba8da8e7..dc2e596cf2d3 100644 --- a/sympy/printing/fcode.py +++ b/sympy/printing/fcode.py @@ -204,7 +204,7 @@ def _print_sign(self, expr): arg, = expr.args if arg.is_integer: new_expr = merge(0, isign(1, arg), Eq(arg, 0)) - elif arg.is_complex: + elif (arg.is_complex or arg.is_infinite): new_expr = merge(cmplx(literal_dp(0), literal_dp(0)), arg/Abs(arg), Eq(Abs(arg), literal_dp(0))) else: new_expr = merge(literal_dp(0), dsign(literal_dp(1), arg), Eq(arg, literal_dp(0))) diff --git a/sympy/stats/crv.py b/sympy/stats/crv.py index b4fce9fd1b12..9647eef44c40 100644 --- a/sympy/stats/crv.py +++ b/sympy/stats/crv.py @@ -410,6 +410,7 @@ def compute_quantile(self, expr, **kwargs): "Quantile not well defined on multivariate expressions") d = self.compute_cdf(expr, **kwargs) + x = Dummy('x', real=True) p = Dummy('p', positive=True) diff --git a/sympy/stats/tests/test_continuous_rv.py b/sympy/stats/tests/test_continuous_rv.py index 6c2225de3d99..16121ce5f3b6 100644 --- a/sympy/stats/tests/test_continuous_rv.py +++ b/sympy/stats/tests/test_continuous_rv.py @@ -28,7 +28,6 @@ x, y, z = map(Symbol, 'xyz') - def test_single_normal(): mu = Symbol('mu', real=True) sigma = Symbol('sigma', positive=True)