Coverage for /usr/lib/python3/dist-packages/sympy/functions/elementary/complexes.py: 23%
689 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from typing import Tuple as tTuple
3from sympy.core import S, Add, Mul, sympify, Symbol, Dummy, Basic
4from sympy.core.expr import Expr
5from sympy.core.exprtools import factor_terms
6from sympy.core.function import (Function, Derivative, ArgumentIndexError,
7 AppliedUndef, expand_mul)
8from sympy.core.logic import fuzzy_not, fuzzy_or
9from sympy.core.numbers import pi, I, oo
10from sympy.core.power import Pow
11from sympy.core.relational import Eq
12from sympy.functions.elementary.miscellaneous import sqrt
13from sympy.functions.elementary.piecewise import Piecewise
15###############################################################################
16######################### REAL and IMAGINARY PARTS ############################
17###############################################################################
20class re(Function):
21 """
22 Returns real part of expression. This function performs only
23 elementary analysis and so it will fail to decompose properly
24 more complicated expressions. If completely simplified result
25 is needed then use ``Basic.as_real_imag()`` or perform complex
26 expansion on instance of this function.
28 Examples
29 ========
31 >>> from sympy import re, im, I, E, symbols
32 >>> x, y = symbols('x y', real=True)
33 >>> re(2*E)
34 2*E
35 >>> re(2*I + 17)
36 17
37 >>> re(2*I)
38 0
39 >>> re(im(x) + x*I + 2)
40 2
41 >>> re(5 + I + 2)
42 7
44 Parameters
45 ==========
47 arg : Expr
48 Real or complex expression.
50 Returns
51 =======
53 expr : Expr
54 Real part of expression.
56 See Also
57 ========
59 im
60 """
62 args: tTuple[Expr]
64 is_extended_real = True
65 unbranched = True # implicitly works on the projection to C
66 _singularities = True # non-holomorphic
68 @classmethod
69 def eval(cls, arg):
70 if arg is S.NaN:
71 return S.NaN
72 elif arg is S.ComplexInfinity:
73 return S.NaN
74 elif arg.is_extended_real:
75 return arg
76 elif arg.is_imaginary or (I*arg).is_extended_real:
77 return S.Zero
78 elif arg.is_Matrix:
79 return arg.as_real_imag()[0]
80 elif arg.is_Function and isinstance(arg, conjugate):
81 return re(arg.args[0])
82 else:
84 included, reverted, excluded = [], [], []
85 args = Add.make_args(arg)
86 for term in args:
87 coeff = term.as_coefficient(I)
89 if coeff is not None:
90 if not coeff.is_extended_real:
91 reverted.append(coeff)
92 elif not term.has(I) and term.is_extended_real:
93 excluded.append(term)
94 else:
95 # Try to do some advanced expansion. If
96 # impossible, don't try to do re(arg) again
97 # (because this is what we are trying to do now).
98 real_imag = term.as_real_imag(ignore=arg)
99 if real_imag:
100 excluded.append(real_imag[0])
101 else:
102 included.append(term)
104 if len(args) != len(included):
105 a, b, c = (Add(*xs) for xs in [included, reverted, excluded])
107 return cls(a) - im(b) + c
109 def as_real_imag(self, deep=True, **hints):
110 """
111 Returns the real number with a zero imaginary part.
113 """
114 return (self, S.Zero)
116 def _eval_derivative(self, x):
117 if x.is_extended_real or self.args[0].is_extended_real:
118 return re(Derivative(self.args[0], x, evaluate=True))
119 if x.is_imaginary or self.args[0].is_imaginary:
120 return -I \
121 * im(Derivative(self.args[0], x, evaluate=True))
123 def _eval_rewrite_as_im(self, arg, **kwargs):
124 return self.args[0] - I*im(self.args[0])
126 def _eval_is_algebraic(self):
127 return self.args[0].is_algebraic
129 def _eval_is_zero(self):
130 # is_imaginary implies nonzero
131 return fuzzy_or([self.args[0].is_imaginary, self.args[0].is_zero])
133 def _eval_is_finite(self):
134 if self.args[0].is_finite:
135 return True
137 def _eval_is_complex(self):
138 if self.args[0].is_finite:
139 return True
142class im(Function):
143 """
144 Returns imaginary part of expression. This function performs only
145 elementary analysis and so it will fail to decompose properly more
146 complicated expressions. If completely simplified result is needed then
147 use ``Basic.as_real_imag()`` or perform complex expansion on instance of
148 this function.
150 Examples
151 ========
153 >>> from sympy import re, im, E, I
154 >>> from sympy.abc import x, y
155 >>> im(2*E)
156 0
157 >>> im(2*I + 17)
158 2
159 >>> im(x*I)
160 re(x)
161 >>> im(re(x) + y)
162 im(y)
163 >>> im(2 + 3*I)
164 3
166 Parameters
167 ==========
169 arg : Expr
170 Real or complex expression.
172 Returns
173 =======
175 expr : Expr
176 Imaginary part of expression.
178 See Also
179 ========
181 re
182 """
184 args: tTuple[Expr]
186 is_extended_real = True
187 unbranched = True # implicitly works on the projection to C
188 _singularities = True # non-holomorphic
190 @classmethod
191 def eval(cls, arg):
192 if arg is S.NaN:
193 return S.NaN
194 elif arg is S.ComplexInfinity:
195 return S.NaN
196 elif arg.is_extended_real:
197 return S.Zero
198 elif arg.is_imaginary or (I*arg).is_extended_real:
199 return -I * arg
200 elif arg.is_Matrix:
201 return arg.as_real_imag()[1]
202 elif arg.is_Function and isinstance(arg, conjugate):
203 return -im(arg.args[0])
204 else:
205 included, reverted, excluded = [], [], []
206 args = Add.make_args(arg)
207 for term in args:
208 coeff = term.as_coefficient(I)
210 if coeff is not None:
211 if not coeff.is_extended_real:
212 reverted.append(coeff)
213 else:
214 excluded.append(coeff)
215 elif term.has(I) or not term.is_extended_real:
216 # Try to do some advanced expansion. If
217 # impossible, don't try to do im(arg) again
218 # (because this is what we are trying to do now).
219 real_imag = term.as_real_imag(ignore=arg)
220 if real_imag:
221 excluded.append(real_imag[1])
222 else:
223 included.append(term)
225 if len(args) != len(included):
226 a, b, c = (Add(*xs) for xs in [included, reverted, excluded])
228 return cls(a) + re(b) + c
230 def as_real_imag(self, deep=True, **hints):
231 """
232 Return the imaginary part with a zero real part.
234 """
235 return (self, S.Zero)
237 def _eval_derivative(self, x):
238 if x.is_extended_real or self.args[0].is_extended_real:
239 return im(Derivative(self.args[0], x, evaluate=True))
240 if x.is_imaginary or self.args[0].is_imaginary:
241 return -I \
242 * re(Derivative(self.args[0], x, evaluate=True))
244 def _eval_rewrite_as_re(self, arg, **kwargs):
245 return -I*(self.args[0] - re(self.args[0]))
247 def _eval_is_algebraic(self):
248 return self.args[0].is_algebraic
250 def _eval_is_zero(self):
251 return self.args[0].is_extended_real
253 def _eval_is_finite(self):
254 if self.args[0].is_finite:
255 return True
257 def _eval_is_complex(self):
258 if self.args[0].is_finite:
259 return True
261###############################################################################
262############### SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ################
263###############################################################################
265class sign(Function):
266 """
267 Returns the complex sign of an expression:
269 Explanation
270 ===========
272 If the expression is real the sign will be:
274 * $1$ if expression is positive
275 * $0$ if expression is equal to zero
276 * $-1$ if expression is negative
278 If the expression is imaginary the sign will be:
280 * $I$ if im(expression) is positive
281 * $-I$ if im(expression) is negative
283 Otherwise an unevaluated expression will be returned. When evaluated, the
284 result (in general) will be ``cos(arg(expr)) + I*sin(arg(expr))``.
286 Examples
287 ========
289 >>> from sympy import sign, I
291 >>> sign(-1)
292 -1
293 >>> sign(0)
294 0
295 >>> sign(-3*I)
296 -I
297 >>> sign(1 + I)
298 sign(1 + I)
299 >>> _.evalf()
300 0.707106781186548 + 0.707106781186548*I
302 Parameters
303 ==========
305 arg : Expr
306 Real or imaginary expression.
308 Returns
309 =======
311 expr : Expr
312 Complex sign of expression.
314 See Also
315 ========
317 Abs, conjugate
318 """
320 is_complex = True
321 _singularities = True
323 def doit(self, **hints):
324 s = super().doit()
325 if s == self and self.args[0].is_zero is False:
326 return self.args[0] / Abs(self.args[0])
327 return s
329 @classmethod
330 def eval(cls, arg):
331 # handle what we can
332 if arg.is_Mul:
333 c, args = arg.as_coeff_mul()
334 unk = []
335 s = sign(c)
336 for a in args:
337 if a.is_extended_negative:
338 s = -s
339 elif a.is_extended_positive:
340 pass
341 else:
342 if a.is_imaginary:
343 ai = im(a)
344 if ai.is_comparable: # i.e. a = I*real
345 s *= I
346 if ai.is_extended_negative:
347 # can't use sign(ai) here since ai might not be
348 # a Number
349 s = -s
350 else:
351 unk.append(a)
352 else:
353 unk.append(a)
354 if c is S.One and len(unk) == len(args):
355 return None
356 return s * cls(arg._new_rawargs(*unk))
357 if arg is S.NaN:
358 return S.NaN
359 if arg.is_zero: # it may be an Expr that is zero
360 return S.Zero
361 if arg.is_extended_positive:
362 return S.One
363 if arg.is_extended_negative:
364 return S.NegativeOne
365 if arg.is_Function:
366 if isinstance(arg, sign):
367 return arg
368 if arg.is_imaginary:
369 if arg.is_Pow and arg.exp is S.Half:
370 # we catch this because non-trivial sqrt args are not expanded
371 # e.g. sqrt(1-sqrt(2)) --x--> to I*sqrt(sqrt(2) - 1)
372 return I
373 arg2 = -I * arg
374 if arg2.is_extended_positive:
375 return I
376 if arg2.is_extended_negative:
377 return -I
379 def _eval_Abs(self):
380 if fuzzy_not(self.args[0].is_zero):
381 return S.One
383 def _eval_conjugate(self):
384 return sign(conjugate(self.args[0]))
386 def _eval_derivative(self, x):
387 if self.args[0].is_extended_real:
388 from sympy.functions.special.delta_functions import DiracDelta
389 return 2 * Derivative(self.args[0], x, evaluate=True) \
390 * DiracDelta(self.args[0])
391 elif self.args[0].is_imaginary:
392 from sympy.functions.special.delta_functions import DiracDelta
393 return 2 * Derivative(self.args[0], x, evaluate=True) \
394 * DiracDelta(-I * self.args[0])
396 def _eval_is_nonnegative(self):
397 if self.args[0].is_nonnegative:
398 return True
400 def _eval_is_nonpositive(self):
401 if self.args[0].is_nonpositive:
402 return True
404 def _eval_is_imaginary(self):
405 return self.args[0].is_imaginary
407 def _eval_is_integer(self):
408 return self.args[0].is_extended_real
410 def _eval_is_zero(self):
411 return self.args[0].is_zero
413 def _eval_power(self, other):
414 if (
415 fuzzy_not(self.args[0].is_zero) and
416 other.is_integer and
417 other.is_even
418 ):
419 return S.One
421 def _eval_nseries(self, x, n, logx, cdir=0):
422 arg0 = self.args[0]
423 x0 = arg0.subs(x, 0)
424 if x0 != 0:
425 return self.func(x0)
426 if cdir != 0:
427 cdir = arg0.dir(x, cdir)
428 return -S.One if re(cdir) < 0 else S.One
430 def _eval_rewrite_as_Piecewise(self, arg, **kwargs):
431 if arg.is_extended_real:
432 return Piecewise((1, arg > 0), (-1, arg < 0), (0, True))
434 def _eval_rewrite_as_Heaviside(self, arg, **kwargs):
435 from sympy.functions.special.delta_functions import Heaviside
436 if arg.is_extended_real:
437 return Heaviside(arg) * 2 - 1
439 def _eval_rewrite_as_Abs(self, arg, **kwargs):
440 return Piecewise((0, Eq(arg, 0)), (arg / Abs(arg), True))
442 def _eval_simplify(self, **kwargs):
443 return self.func(factor_terms(self.args[0])) # XXX include doit?
446class Abs(Function):
447 """
448 Return the absolute value of the argument.
450 Explanation
451 ===========
453 This is an extension of the built-in function ``abs()`` to accept symbolic
454 values. If you pass a SymPy expression to the built-in ``abs()``, it will
455 pass it automatically to ``Abs()``.
457 Examples
458 ========
460 >>> from sympy import Abs, Symbol, S, I
461 >>> Abs(-1)
462 1
463 >>> x = Symbol('x', real=True)
464 >>> Abs(-x)
465 Abs(x)
466 >>> Abs(x**2)
467 x**2
468 >>> abs(-x) # The Python built-in
469 Abs(x)
470 >>> Abs(3*x + 2*I)
471 sqrt(9*x**2 + 4)
472 >>> Abs(8*I)
473 8
475 Note that the Python built-in will return either an Expr or int depending on
476 the argument::
478 >>> type(abs(-1))
479 <... 'int'>
480 >>> type(abs(S.NegativeOne))
481 <class 'sympy.core.numbers.One'>
483 Abs will always return a SymPy object.
485 Parameters
486 ==========
488 arg : Expr
489 Real or complex expression.
491 Returns
492 =======
494 expr : Expr
495 Absolute value returned can be an expression or integer depending on
496 input arg.
498 See Also
499 ========
501 sign, conjugate
502 """
504 args: tTuple[Expr]
506 is_extended_real = True
507 is_extended_negative = False
508 is_extended_nonnegative = True
509 unbranched = True
510 _singularities = True # non-holomorphic
512 def fdiff(self, argindex=1):
513 """
514 Get the first derivative of the argument to Abs().
516 """
517 if argindex == 1:
518 return sign(self.args[0])
519 else:
520 raise ArgumentIndexError(self, argindex)
522 @classmethod
523 def eval(cls, arg):
524 from sympy.simplify.simplify import signsimp
526 if hasattr(arg, '_eval_Abs'):
527 obj = arg._eval_Abs()
528 if obj is not None:
529 return obj
530 if not isinstance(arg, Expr):
531 raise TypeError("Bad argument type for Abs(): %s" % type(arg))
533 # handle what we can
534 arg = signsimp(arg, evaluate=False)
535 n, d = arg.as_numer_denom()
536 if d.free_symbols and not n.free_symbols:
537 return cls(n)/cls(d)
539 if arg.is_Mul:
540 known = []
541 unk = []
542 for t in arg.args:
543 if t.is_Pow and t.exp.is_integer and t.exp.is_negative:
544 bnew = cls(t.base)
545 if isinstance(bnew, cls):
546 unk.append(t)
547 else:
548 known.append(Pow(bnew, t.exp))
549 else:
550 tnew = cls(t)
551 if isinstance(tnew, cls):
552 unk.append(t)
553 else:
554 known.append(tnew)
555 known = Mul(*known)
556 unk = cls(Mul(*unk), evaluate=False) if unk else S.One
557 return known*unk
558 if arg is S.NaN:
559 return S.NaN
560 if arg is S.ComplexInfinity:
561 return oo
562 from sympy.functions.elementary.exponential import exp, log
564 if arg.is_Pow:
565 base, exponent = arg.as_base_exp()
566 if base.is_extended_real:
567 if exponent.is_integer:
568 if exponent.is_even:
569 return arg
570 if base is S.NegativeOne:
571 return S.One
572 return Abs(base)**exponent
573 if base.is_extended_nonnegative:
574 return base**re(exponent)
575 if base.is_extended_negative:
576 return (-base)**re(exponent)*exp(-pi*im(exponent))
577 return
578 elif not base.has(Symbol): # complex base
579 # express base**exponent as exp(exponent*log(base))
580 a, b = log(base).as_real_imag()
581 z = a + I*b
582 return exp(re(exponent*z))
583 if isinstance(arg, exp):
584 return exp(re(arg.args[0]))
585 if isinstance(arg, AppliedUndef):
586 if arg.is_positive:
587 return arg
588 elif arg.is_negative:
589 return -arg
590 return
591 if arg.is_Add and arg.has(oo, S.NegativeInfinity):
592 if any(a.is_infinite for a in arg.as_real_imag()):
593 return oo
594 if arg.is_zero:
595 return S.Zero
596 if arg.is_extended_nonnegative:
597 return arg
598 if arg.is_extended_nonpositive:
599 return -arg
600 if arg.is_imaginary:
601 arg2 = -I * arg
602 if arg2.is_extended_nonnegative:
603 return arg2
604 if arg.is_extended_real:
605 return
606 # reject result if all new conjugates are just wrappers around
607 # an expression that was already in the arg
608 conj = signsimp(arg.conjugate(), evaluate=False)
609 new_conj = conj.atoms(conjugate) - arg.atoms(conjugate)
610 if new_conj and all(arg.has(i.args[0]) for i in new_conj):
611 return
612 if arg != conj and arg != -conj:
613 ignore = arg.atoms(Abs)
614 abs_free_arg = arg.xreplace({i: Dummy(real=True) for i in ignore})
615 unk = [a for a in abs_free_arg.free_symbols if a.is_extended_real is None]
616 if not unk or not all(conj.has(conjugate(u)) for u in unk):
617 return sqrt(expand_mul(arg*conj))
619 def _eval_is_real(self):
620 if self.args[0].is_finite:
621 return True
623 def _eval_is_integer(self):
624 if self.args[0].is_extended_real:
625 return self.args[0].is_integer
627 def _eval_is_extended_nonzero(self):
628 return fuzzy_not(self._args[0].is_zero)
630 def _eval_is_zero(self):
631 return self._args[0].is_zero
633 def _eval_is_extended_positive(self):
634 return fuzzy_not(self._args[0].is_zero)
636 def _eval_is_rational(self):
637 if self.args[0].is_extended_real:
638 return self.args[0].is_rational
640 def _eval_is_even(self):
641 if self.args[0].is_extended_real:
642 return self.args[0].is_even
644 def _eval_is_odd(self):
645 if self.args[0].is_extended_real:
646 return self.args[0].is_odd
648 def _eval_is_algebraic(self):
649 return self.args[0].is_algebraic
651 def _eval_power(self, exponent):
652 if self.args[0].is_extended_real and exponent.is_integer:
653 if exponent.is_even:
654 return self.args[0]**exponent
655 elif exponent is not S.NegativeOne and exponent.is_Integer:
656 return self.args[0]**(exponent - 1)*self
657 return
659 def _eval_nseries(self, x, n, logx, cdir=0):
660 from sympy.functions.elementary.exponential import log
661 direction = self.args[0].leadterm(x)[0]
662 if direction.has(log(x)):
663 direction = direction.subs(log(x), logx)
664 s = self.args[0]._eval_nseries(x, n=n, logx=logx)
665 return (sign(direction)*s).expand()
667 def _eval_derivative(self, x):
668 if self.args[0].is_extended_real or self.args[0].is_imaginary:
669 return Derivative(self.args[0], x, evaluate=True) \
670 * sign(conjugate(self.args[0]))
671 rv = (re(self.args[0]) * Derivative(re(self.args[0]), x,
672 evaluate=True) + im(self.args[0]) * Derivative(im(self.args[0]),
673 x, evaluate=True)) / Abs(self.args[0])
674 return rv.rewrite(sign)
676 def _eval_rewrite_as_Heaviside(self, arg, **kwargs):
677 # Note this only holds for real arg (since Heaviside is not defined
678 # for complex arguments).
679 from sympy.functions.special.delta_functions import Heaviside
680 if arg.is_extended_real:
681 return arg*(Heaviside(arg) - Heaviside(-arg))
683 def _eval_rewrite_as_Piecewise(self, arg, **kwargs):
684 if arg.is_extended_real:
685 return Piecewise((arg, arg >= 0), (-arg, True))
686 elif arg.is_imaginary:
687 return Piecewise((I*arg, I*arg >= 0), (-I*arg, True))
689 def _eval_rewrite_as_sign(self, arg, **kwargs):
690 return arg/sign(arg)
692 def _eval_rewrite_as_conjugate(self, arg, **kwargs):
693 return sqrt(arg*conjugate(arg))
696class arg(Function):
697 r"""
698 Returns the argument (in radians) of a complex number. The argument is
699 evaluated in consistent convention with ``atan2`` where the branch-cut is
700 taken along the negative real axis and ``arg(z)`` is in the interval
701 $(-\pi,\pi]$. For a positive number, the argument is always 0; the
702 argument of a negative number is $\pi$; and the argument of 0
703 is undefined and returns ``nan``. So the ``arg`` function will never nest
704 greater than 3 levels since at the 4th application, the result must be
705 nan; for a real number, nan is returned on the 3rd application.
707 Examples
708 ========
710 >>> from sympy import arg, I, sqrt, Dummy
711 >>> from sympy.abc import x
712 >>> arg(2.0)
713 0
714 >>> arg(I)
715 pi/2
716 >>> arg(sqrt(2) + I*sqrt(2))
717 pi/4
718 >>> arg(sqrt(3)/2 + I/2)
719 pi/6
720 >>> arg(4 + 3*I)
721 atan(3/4)
722 >>> arg(0.8 + 0.6*I)
723 0.643501108793284
724 >>> arg(arg(arg(arg(x))))
725 nan
726 >>> real = Dummy(real=True)
727 >>> arg(arg(arg(real)))
728 nan
730 Parameters
731 ==========
733 arg : Expr
734 Real or complex expression.
736 Returns
737 =======
739 value : Expr
740 Returns arc tangent of arg measured in radians.
742 """
744 is_extended_real = True
745 is_real = True
746 is_finite = True
747 _singularities = True # non-holomorphic
749 @classmethod
750 def eval(cls, arg):
751 a = arg
752 for i in range(3):
753 if isinstance(a, cls):
754 a = a.args[0]
755 else:
756 if i == 2 and a.is_extended_real:
757 return S.NaN
758 break
759 else:
760 return S.NaN
761 from sympy.functions.elementary.exponential import exp_polar
762 if isinstance(arg, exp_polar):
763 return periodic_argument(arg, oo)
764 if not arg.is_Atom:
765 c, arg_ = factor_terms(arg).as_coeff_Mul()
766 if arg_.is_Mul:
767 arg_ = Mul(*[a if (sign(a) not in (-1, 1)) else
768 sign(a) for a in arg_.args])
769 arg_ = sign(c)*arg_
770 else:
771 arg_ = arg
772 if any(i.is_extended_positive is None for i in arg_.atoms(AppliedUndef)):
773 return
774 from sympy.functions.elementary.trigonometric import atan2
775 x, y = arg_.as_real_imag()
776 rv = atan2(y, x)
777 if rv.is_number:
778 return rv
779 if arg_ != arg:
780 return cls(arg_, evaluate=False)
782 def _eval_derivative(self, t):
783 x, y = self.args[0].as_real_imag()
784 return (x * Derivative(y, t, evaluate=True) - y *
785 Derivative(x, t, evaluate=True)) / (x**2 + y**2)
787 def _eval_rewrite_as_atan2(self, arg, **kwargs):
788 from sympy.functions.elementary.trigonometric import atan2
789 x, y = self.args[0].as_real_imag()
790 return atan2(y, x)
793class conjugate(Function):
794 """
795 Returns the *complex conjugate* [1]_ of an argument.
796 In mathematics, the complex conjugate of a complex number
797 is given by changing the sign of the imaginary part.
799 Thus, the conjugate of the complex number
800 :math:`a + ib` (where $a$ and $b$ are real numbers) is :math:`a - ib`
802 Examples
803 ========
805 >>> from sympy import conjugate, I
806 >>> conjugate(2)
807 2
808 >>> conjugate(I)
809 -I
810 >>> conjugate(3 + 2*I)
811 3 - 2*I
812 >>> conjugate(5 - I)
813 5 + I
815 Parameters
816 ==========
818 arg : Expr
819 Real or complex expression.
821 Returns
822 =======
824 arg : Expr
825 Complex conjugate of arg as real, imaginary or mixed expression.
827 See Also
828 ========
830 sign, Abs
832 References
833 ==========
835 .. [1] https://en.wikipedia.org/wiki/Complex_conjugation
836 """
837 _singularities = True # non-holomorphic
839 @classmethod
840 def eval(cls, arg):
841 obj = arg._eval_conjugate()
842 if obj is not None:
843 return obj
845 def inverse(self):
846 return conjugate
848 def _eval_Abs(self):
849 return Abs(self.args[0], evaluate=True)
851 def _eval_adjoint(self):
852 return transpose(self.args[0])
854 def _eval_conjugate(self):
855 return self.args[0]
857 def _eval_derivative(self, x):
858 if x.is_real:
859 return conjugate(Derivative(self.args[0], x, evaluate=True))
860 elif x.is_imaginary:
861 return -conjugate(Derivative(self.args[0], x, evaluate=True))
863 def _eval_transpose(self):
864 return adjoint(self.args[0])
866 def _eval_is_algebraic(self):
867 return self.args[0].is_algebraic
870class transpose(Function):
871 """
872 Linear map transposition.
874 Examples
875 ========
877 >>> from sympy import transpose, Matrix, MatrixSymbol
878 >>> A = MatrixSymbol('A', 25, 9)
879 >>> transpose(A)
880 A.T
881 >>> B = MatrixSymbol('B', 9, 22)
882 >>> transpose(B)
883 B.T
884 >>> transpose(A*B)
885 B.T*A.T
886 >>> M = Matrix([[4, 5], [2, 1], [90, 12]])
887 >>> M
888 Matrix([
889 [ 4, 5],
890 [ 2, 1],
891 [90, 12]])
892 >>> transpose(M)
893 Matrix([
894 [4, 2, 90],
895 [5, 1, 12]])
897 Parameters
898 ==========
900 arg : Matrix
901 Matrix or matrix expression to take the transpose of.
903 Returns
904 =======
906 value : Matrix
907 Transpose of arg.
909 """
911 @classmethod
912 def eval(cls, arg):
913 obj = arg._eval_transpose()
914 if obj is not None:
915 return obj
917 def _eval_adjoint(self):
918 return conjugate(self.args[0])
920 def _eval_conjugate(self):
921 return adjoint(self.args[0])
923 def _eval_transpose(self):
924 return self.args[0]
927class adjoint(Function):
928 """
929 Conjugate transpose or Hermite conjugation.
931 Examples
932 ========
934 >>> from sympy import adjoint, MatrixSymbol
935 >>> A = MatrixSymbol('A', 10, 5)
936 >>> adjoint(A)
937 Adjoint(A)
939 Parameters
940 ==========
942 arg : Matrix
943 Matrix or matrix expression to take the adjoint of.
945 Returns
946 =======
948 value : Matrix
949 Represents the conjugate transpose or Hermite
950 conjugation of arg.
952 """
954 @classmethod
955 def eval(cls, arg):
956 obj = arg._eval_adjoint()
957 if obj is not None:
958 return obj
959 obj = arg._eval_transpose()
960 if obj is not None:
961 return conjugate(obj)
963 def _eval_adjoint(self):
964 return self.args[0]
966 def _eval_conjugate(self):
967 return transpose(self.args[0])
969 def _eval_transpose(self):
970 return conjugate(self.args[0])
972 def _latex(self, printer, exp=None, *args):
973 arg = printer._print(self.args[0])
974 tex = r'%s^{\dagger}' % arg
975 if exp:
976 tex = r'\left(%s\right)^{%s}' % (tex, exp)
977 return tex
979 def _pretty(self, printer, *args):
980 from sympy.printing.pretty.stringpict import prettyForm
981 pform = printer._print(self.args[0], *args)
982 if printer._use_unicode:
983 pform = pform**prettyForm('\N{DAGGER}')
984 else:
985 pform = pform**prettyForm('+')
986 return pform
988###############################################################################
989############### HANDLING OF POLAR NUMBERS #####################################
990###############################################################################
993class polar_lift(Function):
994 """
995 Lift argument to the Riemann surface of the logarithm, using the
996 standard branch.
998 Examples
999 ========
1001 >>> from sympy import Symbol, polar_lift, I
1002 >>> p = Symbol('p', polar=True)
1003 >>> x = Symbol('x')
1004 >>> polar_lift(4)
1005 4*exp_polar(0)
1006 >>> polar_lift(-4)
1007 4*exp_polar(I*pi)
1008 >>> polar_lift(-I)
1009 exp_polar(-I*pi/2)
1010 >>> polar_lift(I + 2)
1011 polar_lift(2 + I)
1013 >>> polar_lift(4*x)
1014 4*polar_lift(x)
1015 >>> polar_lift(4*p)
1016 4*p
1018 Parameters
1019 ==========
1021 arg : Expr
1022 Real or complex expression.
1024 See Also
1025 ========
1027 sympy.functions.elementary.exponential.exp_polar
1028 periodic_argument
1029 """
1031 is_polar = True
1032 is_comparable = False # Cannot be evalf'd.
1034 @classmethod
1035 def eval(cls, arg):
1036 from sympy.functions.elementary.complexes import arg as argument
1037 if arg.is_number:
1038 ar = argument(arg)
1039 # In general we want to affirm that something is known,
1040 # e.g. `not ar.has(argument) and not ar.has(atan)`
1041 # but for now we will just be more restrictive and
1042 # see that it has evaluated to one of the known values.
1043 if ar in (0, pi/2, -pi/2, pi):
1044 from sympy.functions.elementary.exponential import exp_polar
1045 return exp_polar(I*ar)*abs(arg)
1047 if arg.is_Mul:
1048 args = arg.args
1049 else:
1050 args = [arg]
1051 included = []
1052 excluded = []
1053 positive = []
1054 for arg in args:
1055 if arg.is_polar:
1056 included += [arg]
1057 elif arg.is_positive:
1058 positive += [arg]
1059 else:
1060 excluded += [arg]
1061 if len(excluded) < len(args):
1062 if excluded:
1063 return Mul(*(included + positive))*polar_lift(Mul(*excluded))
1064 elif included:
1065 return Mul(*(included + positive))
1066 else:
1067 from sympy.functions.elementary.exponential import exp_polar
1068 return Mul(*positive)*exp_polar(0)
1070 def _eval_evalf(self, prec):
1071 """ Careful! any evalf of polar numbers is flaky """
1072 return self.args[0]._eval_evalf(prec)
1074 def _eval_Abs(self):
1075 return Abs(self.args[0], evaluate=True)
1078class periodic_argument(Function):
1079 r"""
1080 Represent the argument on a quotient of the Riemann surface of the
1081 logarithm. That is, given a period $P$, always return a value in
1082 $(-P/2, P/2]$, by using $\exp(PI) = 1$.
1084 Examples
1085 ========
1087 >>> from sympy import exp_polar, periodic_argument
1088 >>> from sympy import I, pi
1089 >>> periodic_argument(exp_polar(10*I*pi), 2*pi)
1090 0
1091 >>> periodic_argument(exp_polar(5*I*pi), 4*pi)
1092 pi
1093 >>> from sympy import exp_polar, periodic_argument
1094 >>> from sympy import I, pi
1095 >>> periodic_argument(exp_polar(5*I*pi), 2*pi)
1096 pi
1097 >>> periodic_argument(exp_polar(5*I*pi), 3*pi)
1098 -pi
1099 >>> periodic_argument(exp_polar(5*I*pi), pi)
1100 0
1102 Parameters
1103 ==========
1105 ar : Expr
1106 A polar number.
1108 period : Expr
1109 The period $P$.
1111 See Also
1112 ========
1114 sympy.functions.elementary.exponential.exp_polar
1115 polar_lift : Lift argument to the Riemann surface of the logarithm
1116 principal_branch
1117 """
1119 @classmethod
1120 def _getunbranched(cls, ar):
1121 from sympy.functions.elementary.exponential import exp_polar, log
1122 if ar.is_Mul:
1123 args = ar.args
1124 else:
1125 args = [ar]
1126 unbranched = 0
1127 for a in args:
1128 if not a.is_polar:
1129 unbranched += arg(a)
1130 elif isinstance(a, exp_polar):
1131 unbranched += a.exp.as_real_imag()[1]
1132 elif a.is_Pow:
1133 re, im = a.exp.as_real_imag()
1134 unbranched += re*unbranched_argument(
1135 a.base) + im*log(abs(a.base))
1136 elif isinstance(a, polar_lift):
1137 unbranched += arg(a.args[0])
1138 else:
1139 return None
1140 return unbranched
1142 @classmethod
1143 def eval(cls, ar, period):
1144 # Our strategy is to evaluate the argument on the Riemann surface of the
1145 # logarithm, and then reduce.
1146 # NOTE evidently this means it is a rather bad idea to use this with
1147 # period != 2*pi and non-polar numbers.
1148 if not period.is_extended_positive:
1149 return None
1150 if period == oo and isinstance(ar, principal_branch):
1151 return periodic_argument(*ar.args)
1152 if isinstance(ar, polar_lift) and period >= 2*pi:
1153 return periodic_argument(ar.args[0], period)
1154 if ar.is_Mul:
1155 newargs = [x for x in ar.args if not x.is_positive]
1156 if len(newargs) != len(ar.args):
1157 return periodic_argument(Mul(*newargs), period)
1158 unbranched = cls._getunbranched(ar)
1159 if unbranched is None:
1160 return None
1161 from sympy.functions.elementary.trigonometric import atan, atan2
1162 if unbranched.has(periodic_argument, atan2, atan):
1163 return None
1164 if period == oo:
1165 return unbranched
1166 if period != oo:
1167 from sympy.functions.elementary.integers import ceiling
1168 n = ceiling(unbranched/period - S.Half)*period
1169 if not n.has(ceiling):
1170 return unbranched - n
1172 def _eval_evalf(self, prec):
1173 z, period = self.args
1174 if period == oo:
1175 unbranched = periodic_argument._getunbranched(z)
1176 if unbranched is None:
1177 return self
1178 return unbranched._eval_evalf(prec)
1179 ub = periodic_argument(z, oo)._eval_evalf(prec)
1180 from sympy.functions.elementary.integers import ceiling
1181 return (ub - ceiling(ub/period - S.Half)*period)._eval_evalf(prec)
1184def unbranched_argument(arg):
1185 '''
1186 Returns periodic argument of arg with period as infinity.
1188 Examples
1189 ========
1191 >>> from sympy import exp_polar, unbranched_argument
1192 >>> from sympy import I, pi
1193 >>> unbranched_argument(exp_polar(15*I*pi))
1194 15*pi
1195 >>> unbranched_argument(exp_polar(7*I*pi))
1196 7*pi
1198 See also
1199 ========
1201 periodic_argument
1202 '''
1203 return periodic_argument(arg, oo)
1206class principal_branch(Function):
1207 """
1208 Represent a polar number reduced to its principal branch on a quotient
1209 of the Riemann surface of the logarithm.
1211 Explanation
1212 ===========
1214 This is a function of two arguments. The first argument is a polar
1215 number `z`, and the second one a positive real number or infinity, `p`.
1216 The result is ``z mod exp_polar(I*p)``.
1218 Examples
1219 ========
1221 >>> from sympy import exp_polar, principal_branch, oo, I, pi
1222 >>> from sympy.abc import z
1223 >>> principal_branch(z, oo)
1224 z
1225 >>> principal_branch(exp_polar(2*pi*I)*3, 2*pi)
1226 3*exp_polar(0)
1227 >>> principal_branch(exp_polar(2*pi*I)*3*z, 2*pi)
1228 3*principal_branch(z, 2*pi)
1230 Parameters
1231 ==========
1233 x : Expr
1234 A polar number.
1236 period : Expr
1237 Positive real number or infinity.
1239 See Also
1240 ========
1242 sympy.functions.elementary.exponential.exp_polar
1243 polar_lift : Lift argument to the Riemann surface of the logarithm
1244 periodic_argument
1245 """
1247 is_polar = True
1248 is_comparable = False # cannot always be evalf'd
1250 @classmethod
1251 def eval(self, x, period):
1252 from sympy.functions.elementary.exponential import exp_polar
1253 if isinstance(x, polar_lift):
1254 return principal_branch(x.args[0], period)
1255 if period == oo:
1256 return x
1257 ub = periodic_argument(x, oo)
1258 barg = periodic_argument(x, period)
1259 if ub != barg and not ub.has(periodic_argument) \
1260 and not barg.has(periodic_argument):
1261 pl = polar_lift(x)
1263 def mr(expr):
1264 if not isinstance(expr, Symbol):
1265 return polar_lift(expr)
1266 return expr
1267 pl = pl.replace(polar_lift, mr)
1268 # Recompute unbranched argument
1269 ub = periodic_argument(pl, oo)
1270 if not pl.has(polar_lift):
1271 if ub != barg:
1272 res = exp_polar(I*(barg - ub))*pl
1273 else:
1274 res = pl
1275 if not res.is_polar and not res.has(exp_polar):
1276 res *= exp_polar(0)
1277 return res
1279 if not x.free_symbols:
1280 c, m = x, ()
1281 else:
1282 c, m = x.as_coeff_mul(*x.free_symbols)
1283 others = []
1284 for y in m:
1285 if y.is_positive:
1286 c *= y
1287 else:
1288 others += [y]
1289 m = tuple(others)
1290 arg = periodic_argument(c, period)
1291 if arg.has(periodic_argument):
1292 return None
1293 if arg.is_number and (unbranched_argument(c) != arg or
1294 (arg == 0 and m != () and c != 1)):
1295 if arg == 0:
1296 return abs(c)*principal_branch(Mul(*m), period)
1297 return principal_branch(exp_polar(I*arg)*Mul(*m), period)*abs(c)
1298 if arg.is_number and ((abs(arg) < period/2) == True or arg == period/2) \
1299 and m == ():
1300 return exp_polar(arg*I)*abs(c)
1302 def _eval_evalf(self, prec):
1303 z, period = self.args
1304 p = periodic_argument(z, period)._eval_evalf(prec)
1305 if abs(p) > pi or p == -pi:
1306 return self # Cannot evalf for this argument.
1307 from sympy.functions.elementary.exponential import exp
1308 return (abs(z)*exp(I*p))._eval_evalf(prec)
1311def _polarify(eq, lift, pause=False):
1312 from sympy.integrals.integrals import Integral
1313 if eq.is_polar:
1314 return eq
1315 if eq.is_number and not pause:
1316 return polar_lift(eq)
1317 if isinstance(eq, Symbol) and not pause and lift:
1318 return polar_lift(eq)
1319 elif eq.is_Atom:
1320 return eq
1321 elif eq.is_Add:
1322 r = eq.func(*[_polarify(arg, lift, pause=True) for arg in eq.args])
1323 if lift:
1324 return polar_lift(r)
1325 return r
1326 elif eq.is_Pow and eq.base == S.Exp1:
1327 return eq.func(S.Exp1, _polarify(eq.exp, lift, pause=False))
1328 elif eq.is_Function:
1329 return eq.func(*[_polarify(arg, lift, pause=False) for arg in eq.args])
1330 elif isinstance(eq, Integral):
1331 # Don't lift the integration variable
1332 func = _polarify(eq.function, lift, pause=pause)
1333 limits = []
1334 for limit in eq.args[1:]:
1335 var = _polarify(limit[0], lift=False, pause=pause)
1336 rest = _polarify(limit[1:], lift=lift, pause=pause)
1337 limits.append((var,) + rest)
1338 return Integral(*((func,) + tuple(limits)))
1339 else:
1340 return eq.func(*[_polarify(arg, lift, pause=pause)
1341 if isinstance(arg, Expr) else arg for arg in eq.args])
1344def polarify(eq, subs=True, lift=False):
1345 """
1346 Turn all numbers in eq into their polar equivalents (under the standard
1347 choice of argument).
1349 Note that no attempt is made to guess a formal convention of adding
1350 polar numbers, expressions like $1 + x$ will generally not be altered.
1352 Note also that this function does not promote ``exp(x)`` to ``exp_polar(x)``.
1354 If ``subs`` is ``True``, all symbols which are not already polar will be
1355 substituted for polar dummies; in this case the function behaves much
1356 like :func:`~.posify`.
1358 If ``lift`` is ``True``, both addition statements and non-polar symbols are
1359 changed to their ``polar_lift()``ed versions.
1360 Note that ``lift=True`` implies ``subs=False``.
1362 Examples
1363 ========
1365 >>> from sympy import polarify, sin, I
1366 >>> from sympy.abc import x, y
1367 >>> expr = (-x)**y
1368 >>> expr.expand()
1369 (-x)**y
1370 >>> polarify(expr)
1371 ((_x*exp_polar(I*pi))**_y, {_x: x, _y: y})
1372 >>> polarify(expr)[0].expand()
1373 _x**_y*exp_polar(_y*I*pi)
1374 >>> polarify(x, lift=True)
1375 polar_lift(x)
1376 >>> polarify(x*(1+y), lift=True)
1377 polar_lift(x)*polar_lift(y + 1)
1379 Adds are treated carefully:
1381 >>> polarify(1 + sin((1 + I)*x))
1382 (sin(_x*polar_lift(1 + I)) + 1, {_x: x})
1383 """
1384 if lift:
1385 subs = False
1386 eq = _polarify(sympify(eq), lift)
1387 if not subs:
1388 return eq
1389 reps = {s: Dummy(s.name, polar=True) for s in eq.free_symbols}
1390 eq = eq.subs(reps)
1391 return eq, {r: s for s, r in reps.items()}
1394def _unpolarify(eq, exponents_only, pause=False):
1395 if not isinstance(eq, Basic) or eq.is_Atom:
1396 return eq
1398 if not pause:
1399 from sympy.functions.elementary.exponential import exp, exp_polar
1400 if isinstance(eq, exp_polar):
1401 return exp(_unpolarify(eq.exp, exponents_only))
1402 if isinstance(eq, principal_branch) and eq.args[1] == 2*pi:
1403 return _unpolarify(eq.args[0], exponents_only)
1404 if (
1405 eq.is_Add or eq.is_Mul or eq.is_Boolean or
1406 eq.is_Relational and (
1407 eq.rel_op in ('==', '!=') and 0 in eq.args or
1408 eq.rel_op not in ('==', '!='))
1409 ):
1410 return eq.func(*[_unpolarify(x, exponents_only) for x in eq.args])
1411 if isinstance(eq, polar_lift):
1412 return _unpolarify(eq.args[0], exponents_only)
1414 if eq.is_Pow:
1415 expo = _unpolarify(eq.exp, exponents_only)
1416 base = _unpolarify(eq.base, exponents_only,
1417 not (expo.is_integer and not pause))
1418 return base**expo
1420 if eq.is_Function and getattr(eq.func, 'unbranched', False):
1421 return eq.func(*[_unpolarify(x, exponents_only, exponents_only)
1422 for x in eq.args])
1424 return eq.func(*[_unpolarify(x, exponents_only, True) for x in eq.args])
1427def unpolarify(eq, subs=None, exponents_only=False):
1428 """
1429 If `p` denotes the projection from the Riemann surface of the logarithm to
1430 the complex line, return a simplified version `eq'` of `eq` such that
1431 `p(eq') = p(eq)`.
1432 Also apply the substitution subs in the end. (This is a convenience, since
1433 ``unpolarify``, in a certain sense, undoes :func:`polarify`.)
1435 Examples
1436 ========
1438 >>> from sympy import unpolarify, polar_lift, sin, I
1439 >>> unpolarify(polar_lift(I + 2))
1440 2 + I
1441 >>> unpolarify(sin(polar_lift(I + 7)))
1442 sin(7 + I)
1443 """
1444 if isinstance(eq, bool):
1445 return eq
1447 eq = sympify(eq)
1448 if subs is not None:
1449 return unpolarify(eq.subs(subs))
1450 changed = True
1451 pause = False
1452 if exponents_only:
1453 pause = True
1454 while changed:
1455 changed = False
1456 res = _unpolarify(eq, exponents_only, pause)
1457 if res != eq:
1458 changed = True
1459 eq = res
1460 if isinstance(res, bool):
1461 return res
1462 # Finally, replacing Exp(0) by 1 is always correct.
1463 # So is polar_lift(0) -> 0.
1464 from sympy.functions.elementary.exponential import exp_polar
1465 return res.subs({exp_polar(0): 1, polar_lift(0): 0})