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

1from typing import Tuple as tTuple 

2 

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 

14 

15############################################################################### 

16######################### REAL and IMAGINARY PARTS ############################ 

17############################################################################### 

18 

19 

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. 

27 

28 Examples 

29 ======== 

30 

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 

43 

44 Parameters 

45 ========== 

46 

47 arg : Expr 

48 Real or complex expression. 

49 

50 Returns 

51 ======= 

52 

53 expr : Expr 

54 Real part of expression. 

55 

56 See Also 

57 ======== 

58 

59 im 

60 """ 

61 

62 args: tTuple[Expr] 

63 

64 is_extended_real = True 

65 unbranched = True # implicitly works on the projection to C 

66 _singularities = True # non-holomorphic 

67 

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: 

83 

84 included, reverted, excluded = [], [], [] 

85 args = Add.make_args(arg) 

86 for term in args: 

87 coeff = term.as_coefficient(I) 

88 

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) 

103 

104 if len(args) != len(included): 

105 a, b, c = (Add(*xs) for xs in [included, reverted, excluded]) 

106 

107 return cls(a) - im(b) + c 

108 

109 def as_real_imag(self, deep=True, **hints): 

110 """ 

111 Returns the real number with a zero imaginary part. 

112 

113 """ 

114 return (self, S.Zero) 

115 

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)) 

122 

123 def _eval_rewrite_as_im(self, arg, **kwargs): 

124 return self.args[0] - I*im(self.args[0]) 

125 

126 def _eval_is_algebraic(self): 

127 return self.args[0].is_algebraic 

128 

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]) 

132 

133 def _eval_is_finite(self): 

134 if self.args[0].is_finite: 

135 return True 

136 

137 def _eval_is_complex(self): 

138 if self.args[0].is_finite: 

139 return True 

140 

141 

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. 

149 

150 Examples 

151 ======== 

152 

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 

165 

166 Parameters 

167 ========== 

168 

169 arg : Expr 

170 Real or complex expression. 

171 

172 Returns 

173 ======= 

174 

175 expr : Expr 

176 Imaginary part of expression. 

177 

178 See Also 

179 ======== 

180 

181 re 

182 """ 

183 

184 args: tTuple[Expr] 

185 

186 is_extended_real = True 

187 unbranched = True # implicitly works on the projection to C 

188 _singularities = True # non-holomorphic 

189 

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) 

209 

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) 

224 

225 if len(args) != len(included): 

226 a, b, c = (Add(*xs) for xs in [included, reverted, excluded]) 

227 

228 return cls(a) + re(b) + c 

229 

230 def as_real_imag(self, deep=True, **hints): 

231 """ 

232 Return the imaginary part with a zero real part. 

233 

234 """ 

235 return (self, S.Zero) 

236 

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)) 

243 

244 def _eval_rewrite_as_re(self, arg, **kwargs): 

245 return -I*(self.args[0] - re(self.args[0])) 

246 

247 def _eval_is_algebraic(self): 

248 return self.args[0].is_algebraic 

249 

250 def _eval_is_zero(self): 

251 return self.args[0].is_extended_real 

252 

253 def _eval_is_finite(self): 

254 if self.args[0].is_finite: 

255 return True 

256 

257 def _eval_is_complex(self): 

258 if self.args[0].is_finite: 

259 return True 

260 

261############################################################################### 

262############### SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ################ 

263############################################################################### 

264 

265class sign(Function): 

266 """ 

267 Returns the complex sign of an expression: 

268 

269 Explanation 

270 =========== 

271 

272 If the expression is real the sign will be: 

273 

274 * $1$ if expression is positive 

275 * $0$ if expression is equal to zero 

276 * $-1$ if expression is negative 

277 

278 If the expression is imaginary the sign will be: 

279 

280 * $I$ if im(expression) is positive 

281 * $-I$ if im(expression) is negative 

282 

283 Otherwise an unevaluated expression will be returned. When evaluated, the 

284 result (in general) will be ``cos(arg(expr)) + I*sin(arg(expr))``. 

285 

286 Examples 

287 ======== 

288 

289 >>> from sympy import sign, I 

290 

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 

301 

302 Parameters 

303 ========== 

304 

305 arg : Expr 

306 Real or imaginary expression. 

307 

308 Returns 

309 ======= 

310 

311 expr : Expr 

312 Complex sign of expression. 

313 

314 See Also 

315 ======== 

316 

317 Abs, conjugate 

318 """ 

319 

320 is_complex = True 

321 _singularities = True 

322 

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 

328 

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 

378 

379 def _eval_Abs(self): 

380 if fuzzy_not(self.args[0].is_zero): 

381 return S.One 

382 

383 def _eval_conjugate(self): 

384 return sign(conjugate(self.args[0])) 

385 

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]) 

395 

396 def _eval_is_nonnegative(self): 

397 if self.args[0].is_nonnegative: 

398 return True 

399 

400 def _eval_is_nonpositive(self): 

401 if self.args[0].is_nonpositive: 

402 return True 

403 

404 def _eval_is_imaginary(self): 

405 return self.args[0].is_imaginary 

406 

407 def _eval_is_integer(self): 

408 return self.args[0].is_extended_real 

409 

410 def _eval_is_zero(self): 

411 return self.args[0].is_zero 

412 

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 

420 

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 

429 

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)) 

433 

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 

438 

439 def _eval_rewrite_as_Abs(self, arg, **kwargs): 

440 return Piecewise((0, Eq(arg, 0)), (arg / Abs(arg), True)) 

441 

442 def _eval_simplify(self, **kwargs): 

443 return self.func(factor_terms(self.args[0])) # XXX include doit? 

444 

445 

446class Abs(Function): 

447 """ 

448 Return the absolute value of the argument. 

449 

450 Explanation 

451 =========== 

452 

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()``. 

456 

457 Examples 

458 ======== 

459 

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 

474 

475 Note that the Python built-in will return either an Expr or int depending on 

476 the argument:: 

477 

478 >>> type(abs(-1)) 

479 <... 'int'> 

480 >>> type(abs(S.NegativeOne)) 

481 <class 'sympy.core.numbers.One'> 

482 

483 Abs will always return a SymPy object. 

484 

485 Parameters 

486 ========== 

487 

488 arg : Expr 

489 Real or complex expression. 

490 

491 Returns 

492 ======= 

493 

494 expr : Expr 

495 Absolute value returned can be an expression or integer depending on 

496 input arg. 

497 

498 See Also 

499 ======== 

500 

501 sign, conjugate 

502 """ 

503 

504 args: tTuple[Expr] 

505 

506 is_extended_real = True 

507 is_extended_negative = False 

508 is_extended_nonnegative = True 

509 unbranched = True 

510 _singularities = True # non-holomorphic 

511 

512 def fdiff(self, argindex=1): 

513 """ 

514 Get the first derivative of the argument to Abs(). 

515 

516 """ 

517 if argindex == 1: 

518 return sign(self.args[0]) 

519 else: 

520 raise ArgumentIndexError(self, argindex) 

521 

522 @classmethod 

523 def eval(cls, arg): 

524 from sympy.simplify.simplify import signsimp 

525 

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)) 

532 

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) 

538 

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 

563 

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)) 

618 

619 def _eval_is_real(self): 

620 if self.args[0].is_finite: 

621 return True 

622 

623 def _eval_is_integer(self): 

624 if self.args[0].is_extended_real: 

625 return self.args[0].is_integer 

626 

627 def _eval_is_extended_nonzero(self): 

628 return fuzzy_not(self._args[0].is_zero) 

629 

630 def _eval_is_zero(self): 

631 return self._args[0].is_zero 

632 

633 def _eval_is_extended_positive(self): 

634 return fuzzy_not(self._args[0].is_zero) 

635 

636 def _eval_is_rational(self): 

637 if self.args[0].is_extended_real: 

638 return self.args[0].is_rational 

639 

640 def _eval_is_even(self): 

641 if self.args[0].is_extended_real: 

642 return self.args[0].is_even 

643 

644 def _eval_is_odd(self): 

645 if self.args[0].is_extended_real: 

646 return self.args[0].is_odd 

647 

648 def _eval_is_algebraic(self): 

649 return self.args[0].is_algebraic 

650 

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 

658 

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() 

666 

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) 

675 

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)) 

682 

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)) 

688 

689 def _eval_rewrite_as_sign(self, arg, **kwargs): 

690 return arg/sign(arg) 

691 

692 def _eval_rewrite_as_conjugate(self, arg, **kwargs): 

693 return sqrt(arg*conjugate(arg)) 

694 

695 

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. 

706 

707 Examples 

708 ======== 

709 

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 

729 

730 Parameters 

731 ========== 

732 

733 arg : Expr 

734 Real or complex expression. 

735 

736 Returns 

737 ======= 

738 

739 value : Expr 

740 Returns arc tangent of arg measured in radians. 

741 

742 """ 

743 

744 is_extended_real = True 

745 is_real = True 

746 is_finite = True 

747 _singularities = True # non-holomorphic 

748 

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) 

781 

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) 

786 

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) 

791 

792 

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. 

798 

799 Thus, the conjugate of the complex number 

800 :math:`a + ib` (where $a$ and $b$ are real numbers) is :math:`a - ib` 

801 

802 Examples 

803 ======== 

804 

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 

814 

815 Parameters 

816 ========== 

817 

818 arg : Expr 

819 Real or complex expression. 

820 

821 Returns 

822 ======= 

823 

824 arg : Expr 

825 Complex conjugate of arg as real, imaginary or mixed expression. 

826 

827 See Also 

828 ======== 

829 

830 sign, Abs 

831 

832 References 

833 ========== 

834 

835 .. [1] https://en.wikipedia.org/wiki/Complex_conjugation 

836 """ 

837 _singularities = True # non-holomorphic 

838 

839 @classmethod 

840 def eval(cls, arg): 

841 obj = arg._eval_conjugate() 

842 if obj is not None: 

843 return obj 

844 

845 def inverse(self): 

846 return conjugate 

847 

848 def _eval_Abs(self): 

849 return Abs(self.args[0], evaluate=True) 

850 

851 def _eval_adjoint(self): 

852 return transpose(self.args[0]) 

853 

854 def _eval_conjugate(self): 

855 return self.args[0] 

856 

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)) 

862 

863 def _eval_transpose(self): 

864 return adjoint(self.args[0]) 

865 

866 def _eval_is_algebraic(self): 

867 return self.args[0].is_algebraic 

868 

869 

870class transpose(Function): 

871 """ 

872 Linear map transposition. 

873 

874 Examples 

875 ======== 

876 

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]]) 

896 

897 Parameters 

898 ========== 

899 

900 arg : Matrix 

901 Matrix or matrix expression to take the transpose of. 

902 

903 Returns 

904 ======= 

905 

906 value : Matrix 

907 Transpose of arg. 

908 

909 """ 

910 

911 @classmethod 

912 def eval(cls, arg): 

913 obj = arg._eval_transpose() 

914 if obj is not None: 

915 return obj 

916 

917 def _eval_adjoint(self): 

918 return conjugate(self.args[0]) 

919 

920 def _eval_conjugate(self): 

921 return adjoint(self.args[0]) 

922 

923 def _eval_transpose(self): 

924 return self.args[0] 

925 

926 

927class adjoint(Function): 

928 """ 

929 Conjugate transpose or Hermite conjugation. 

930 

931 Examples 

932 ======== 

933 

934 >>> from sympy import adjoint, MatrixSymbol 

935 >>> A = MatrixSymbol('A', 10, 5) 

936 >>> adjoint(A) 

937 Adjoint(A) 

938 

939 Parameters 

940 ========== 

941 

942 arg : Matrix 

943 Matrix or matrix expression to take the adjoint of. 

944 

945 Returns 

946 ======= 

947 

948 value : Matrix 

949 Represents the conjugate transpose or Hermite 

950 conjugation of arg. 

951 

952 """ 

953 

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) 

962 

963 def _eval_adjoint(self): 

964 return self.args[0] 

965 

966 def _eval_conjugate(self): 

967 return transpose(self.args[0]) 

968 

969 def _eval_transpose(self): 

970 return conjugate(self.args[0]) 

971 

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 

978 

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 

987 

988############################################################################### 

989############### HANDLING OF POLAR NUMBERS ##################################### 

990############################################################################### 

991 

992 

993class polar_lift(Function): 

994 """ 

995 Lift argument to the Riemann surface of the logarithm, using the 

996 standard branch. 

997 

998 Examples 

999 ======== 

1000 

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) 

1012 

1013 >>> polar_lift(4*x) 

1014 4*polar_lift(x) 

1015 >>> polar_lift(4*p) 

1016 4*p 

1017 

1018 Parameters 

1019 ========== 

1020 

1021 arg : Expr 

1022 Real or complex expression. 

1023 

1024 See Also 

1025 ======== 

1026 

1027 sympy.functions.elementary.exponential.exp_polar 

1028 periodic_argument 

1029 """ 

1030 

1031 is_polar = True 

1032 is_comparable = False # Cannot be evalf'd. 

1033 

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) 

1046 

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) 

1069 

1070 def _eval_evalf(self, prec): 

1071 """ Careful! any evalf of polar numbers is flaky """ 

1072 return self.args[0]._eval_evalf(prec) 

1073 

1074 def _eval_Abs(self): 

1075 return Abs(self.args[0], evaluate=True) 

1076 

1077 

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$. 

1083 

1084 Examples 

1085 ======== 

1086 

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 

1101 

1102 Parameters 

1103 ========== 

1104 

1105 ar : Expr 

1106 A polar number. 

1107 

1108 period : Expr 

1109 The period $P$. 

1110 

1111 See Also 

1112 ======== 

1113 

1114 sympy.functions.elementary.exponential.exp_polar 

1115 polar_lift : Lift argument to the Riemann surface of the logarithm 

1116 principal_branch 

1117 """ 

1118 

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 

1141 

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 

1171 

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) 

1182 

1183 

1184def unbranched_argument(arg): 

1185 ''' 

1186 Returns periodic argument of arg with period as infinity. 

1187 

1188 Examples 

1189 ======== 

1190 

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 

1197 

1198 See also 

1199 ======== 

1200 

1201 periodic_argument 

1202 ''' 

1203 return periodic_argument(arg, oo) 

1204 

1205 

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. 

1210 

1211 Explanation 

1212 =========== 

1213 

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)``. 

1217 

1218 Examples 

1219 ======== 

1220 

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) 

1229 

1230 Parameters 

1231 ========== 

1232 

1233 x : Expr 

1234 A polar number. 

1235 

1236 period : Expr 

1237 Positive real number or infinity. 

1238 

1239 See Also 

1240 ======== 

1241 

1242 sympy.functions.elementary.exponential.exp_polar 

1243 polar_lift : Lift argument to the Riemann surface of the logarithm 

1244 periodic_argument 

1245 """ 

1246 

1247 is_polar = True 

1248 is_comparable = False # cannot always be evalf'd 

1249 

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) 

1262 

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 

1278 

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) 

1301 

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) 

1309 

1310 

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]) 

1342 

1343 

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). 

1348 

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. 

1351 

1352 Note also that this function does not promote ``exp(x)`` to ``exp_polar(x)``. 

1353 

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`. 

1357 

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``. 

1361 

1362 Examples 

1363 ======== 

1364 

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) 

1378 

1379 Adds are treated carefully: 

1380 

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()} 

1392 

1393 

1394def _unpolarify(eq, exponents_only, pause=False): 

1395 if not isinstance(eq, Basic) or eq.is_Atom: 

1396 return eq 

1397 

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) 

1413 

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 

1419 

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]) 

1423 

1424 return eq.func(*[_unpolarify(x, exponents_only, True) for x in eq.args]) 

1425 

1426 

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`.) 

1434 

1435 Examples 

1436 ======== 

1437 

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 

1446 

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})