Coverage for /usr/lib/python3/dist-packages/sympy/functions/elementary/trigonometric.py: 17%

2101 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1from typing import Tuple as tTuple, Union as tUnion 

2from sympy.core.add import Add 

3from sympy.core.cache import cacheit 

4from sympy.core.expr import Expr 

5from sympy.core.function import Function, ArgumentIndexError, PoleError, expand_mul 

6from sympy.core.logic import fuzzy_not, fuzzy_or, FuzzyBool, fuzzy_and 

7from sympy.core.mod import Mod 

8from sympy.core.numbers import Rational, pi, Integer, Float, equal_valued 

9from sympy.core.relational import Ne, Eq 

10from sympy.core.singleton import S 

11from sympy.core.symbol import Symbol, Dummy 

12from sympy.core.sympify import sympify 

13from sympy.functions.combinatorial.factorials import factorial, RisingFactorial 

14from sympy.functions.combinatorial.numbers import bernoulli, euler 

15from sympy.functions.elementary.complexes import arg as arg_f, im, re 

16from sympy.functions.elementary.exponential import log, exp 

17from sympy.functions.elementary.integers import floor 

18from sympy.functions.elementary.miscellaneous import sqrt, Min, Max 

19from sympy.functions.elementary.piecewise import Piecewise 

20from sympy.functions.elementary._trigonometric_special import ( 

21 cos_table, ipartfrac, fermat_coords) 

22from sympy.logic.boolalg import And 

23from sympy.ntheory import factorint 

24from sympy.polys.specialpolys import symmetric_poly 

25from sympy.utilities.iterables import numbered_symbols 

26 

27 

28############################################################################### 

29########################## UTILITIES ########################################## 

30############################################################################### 

31 

32 

33def _imaginary_unit_as_coefficient(arg): 

34 """ Helper to extract symbolic coefficient for imaginary unit """ 

35 if isinstance(arg, Float): 

36 return None 

37 else: 

38 return arg.as_coefficient(S.ImaginaryUnit) 

39 

40############################################################################### 

41########################## TRIGONOMETRIC FUNCTIONS ############################ 

42############################################################################### 

43 

44 

45class TrigonometricFunction(Function): 

46 """Base class for trigonometric functions. """ 

47 

48 unbranched = True 

49 _singularities = (S.ComplexInfinity,) 

50 

51 def _eval_is_rational(self): 

52 s = self.func(*self.args) 

53 if s.func == self.func: 

54 if s.args[0].is_rational and fuzzy_not(s.args[0].is_zero): 

55 return False 

56 else: 

57 return s.is_rational 

58 

59 def _eval_is_algebraic(self): 

60 s = self.func(*self.args) 

61 if s.func == self.func: 

62 if fuzzy_not(self.args[0].is_zero) and self.args[0].is_algebraic: 

63 return False 

64 pi_coeff = _pi_coeff(self.args[0]) 

65 if pi_coeff is not None and pi_coeff.is_rational: 

66 return True 

67 else: 

68 return s.is_algebraic 

69 

70 def _eval_expand_complex(self, deep=True, **hints): 

71 re_part, im_part = self.as_real_imag(deep=deep, **hints) 

72 return re_part + im_part*S.ImaginaryUnit 

73 

74 def _as_real_imag(self, deep=True, **hints): 

75 if self.args[0].is_extended_real: 

76 if deep: 

77 hints['complex'] = False 

78 return (self.args[0].expand(deep, **hints), S.Zero) 

79 else: 

80 return (self.args[0], S.Zero) 

81 if deep: 

82 re, im = self.args[0].expand(deep, **hints).as_real_imag() 

83 else: 

84 re, im = self.args[0].as_real_imag() 

85 return (re, im) 

86 

87 def _period(self, general_period, symbol=None): 

88 f = expand_mul(self.args[0]) 

89 if symbol is None: 

90 symbol = tuple(f.free_symbols)[0] 

91 

92 if not f.has(symbol): 

93 return S.Zero 

94 

95 if f == symbol: 

96 return general_period 

97 

98 if symbol in f.free_symbols: 

99 if f.is_Mul: 

100 g, h = f.as_independent(symbol) 

101 if h == symbol: 

102 return general_period/abs(g) 

103 

104 if f.is_Add: 

105 a, h = f.as_independent(symbol) 

106 g, h = h.as_independent(symbol, as_Add=False) 

107 if h == symbol: 

108 return general_period/abs(g) 

109 

110 raise NotImplementedError("Use the periodicity function instead.") 

111 

112 

113@cacheit 

114def _table2(): 

115 # If nested sqrt's are worse than un-evaluation 

116 # you can require q to be in (1, 2, 3, 4, 6, 12) 

117 # q <= 12, q=15, q=20, q=24, q=30, q=40, q=60, q=120 return 

118 # expressions with 2 or fewer sqrt nestings. 

119 return { 

120 12: (3, 4), 

121 20: (4, 5), 

122 30: (5, 6), 

123 15: (6, 10), 

124 24: (6, 8), 

125 40: (8, 10), 

126 60: (20, 30), 

127 120: (40, 60) 

128 } 

129 

130 

131def _peeloff_pi(arg): 

132 r""" 

133 Split ARG into two parts, a "rest" and a multiple of $\pi$. 

134 This assumes ARG to be an Add. 

135 The multiple of $\pi$ returned in the second position is always a Rational. 

136 

137 Examples 

138 ======== 

139 

140 >>> from sympy.functions.elementary.trigonometric import _peeloff_pi 

141 >>> from sympy import pi 

142 >>> from sympy.abc import x, y 

143 >>> _peeloff_pi(x + pi/2) 

144 (x, 1/2) 

145 >>> _peeloff_pi(x + 2*pi/3 + pi*y) 

146 (x + pi*y + pi/6, 1/2) 

147 

148 """ 

149 pi_coeff = S.Zero 

150 rest_terms = [] 

151 for a in Add.make_args(arg): 

152 K = a.coeff(pi) 

153 if K and K.is_rational: 

154 pi_coeff += K 

155 else: 

156 rest_terms.append(a) 

157 

158 if pi_coeff is S.Zero: 

159 return arg, S.Zero 

160 

161 m1 = (pi_coeff % S.Half) 

162 m2 = pi_coeff - m1 

163 if m2.is_integer or ((2*m2).is_integer and m2.is_even is False): 

164 return Add(*(rest_terms + [m1*pi])), m2 

165 return arg, S.Zero 

166 

167 

168def _pi_coeff(arg: Expr, cycles: int = 1) -> tUnion[Expr, None]: 

169 r""" 

170 When arg is a Number times $\pi$ (e.g. $3\pi/2$) then return the Number 

171 normalized to be in the range $[0, 2]$, else `None`. 

172 

173 When an even multiple of $\pi$ is encountered, if it is multiplying 

174 something with known parity then the multiple is returned as 0 otherwise 

175 as 2. 

176 

177 Examples 

178 ======== 

179 

180 >>> from sympy.functions.elementary.trigonometric import _pi_coeff 

181 >>> from sympy import pi, Dummy 

182 >>> from sympy.abc import x 

183 >>> _pi_coeff(3*x*pi) 

184 3*x 

185 >>> _pi_coeff(11*pi/7) 

186 11/7 

187 >>> _pi_coeff(-11*pi/7) 

188 3/7 

189 >>> _pi_coeff(4*pi) 

190 0 

191 >>> _pi_coeff(5*pi) 

192 1 

193 >>> _pi_coeff(5.0*pi) 

194 1 

195 >>> _pi_coeff(5.5*pi) 

196 3/2 

197 >>> _pi_coeff(2 + pi) 

198 

199 >>> _pi_coeff(2*Dummy(integer=True)*pi) 

200 2 

201 >>> _pi_coeff(2*Dummy(even=True)*pi) 

202 0 

203 

204 """ 

205 if arg is pi: 

206 return S.One 

207 elif not arg: 

208 return S.Zero 

209 elif arg.is_Mul: 

210 cx = arg.coeff(pi) 

211 if cx: 

212 c, x = cx.as_coeff_Mul() # pi is not included as coeff 

213 if c.is_Float: 

214 # recast exact binary fractions to Rationals 

215 f = abs(c) % 1 

216 if f != 0: 

217 p = -int(round(log(f, 2).evalf())) 

218 m = 2**p 

219 cm = c*m 

220 i = int(cm) 

221 if equal_valued(i, cm): 

222 c = Rational(i, m) 

223 cx = c*x 

224 else: 

225 c = Rational(int(c)) 

226 cx = c*x 

227 if x.is_integer: 

228 c2 = c % 2 

229 if c2 == 1: 

230 return x 

231 elif not c2: 

232 if x.is_even is not None: # known parity 

233 return S.Zero 

234 return Integer(2) 

235 else: 

236 return c2*x 

237 return cx 

238 elif arg.is_zero: 

239 return S.Zero 

240 return None 

241 

242 

243class sin(TrigonometricFunction): 

244 r""" 

245 The sine function. 

246 

247 Returns the sine of x (measured in radians). 

248 

249 Explanation 

250 =========== 

251 

252 This function will evaluate automatically in the 

253 case $x/\pi$ is some rational number [4]_. For example, 

254 if $x$ is a multiple of $\pi$, $\pi/2$, $\pi/3$, $\pi/4$, and $\pi/6$. 

255 

256 Examples 

257 ======== 

258 

259 >>> from sympy import sin, pi 

260 >>> from sympy.abc import x 

261 >>> sin(x**2).diff(x) 

262 2*x*cos(x**2) 

263 >>> sin(1).diff(x) 

264 0 

265 >>> sin(pi) 

266 0 

267 >>> sin(pi/2) 

268 1 

269 >>> sin(pi/6) 

270 1/2 

271 >>> sin(pi/12) 

272 -sqrt(2)/4 + sqrt(6)/4 

273 

274 

275 See Also 

276 ======== 

277 

278 csc, cos, sec, tan, cot 

279 asin, acsc, acos, asec, atan, acot, atan2 

280 

281 References 

282 ========== 

283 

284 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

285 .. [2] https://dlmf.nist.gov/4.14 

286 .. [3] https://functions.wolfram.com/ElementaryFunctions/Sin 

287 .. [4] https://mathworld.wolfram.com/TrigonometryAngles.html 

288 

289 """ 

290 

291 def period(self, symbol=None): 

292 return self._period(2*pi, symbol) 

293 

294 def fdiff(self, argindex=1): 

295 if argindex == 1: 

296 return cos(self.args[0]) 

297 else: 

298 raise ArgumentIndexError(self, argindex) 

299 

300 @classmethod 

301 def eval(cls, arg): 

302 from sympy.calculus.accumulationbounds import AccumBounds 

303 from sympy.sets.setexpr import SetExpr 

304 if arg.is_Number: 

305 if arg is S.NaN: 

306 return S.NaN 

307 elif arg.is_zero: 

308 return S.Zero 

309 elif arg in (S.Infinity, S.NegativeInfinity): 

310 return AccumBounds(-1, 1) 

311 

312 if arg is S.ComplexInfinity: 

313 return S.NaN 

314 

315 if isinstance(arg, AccumBounds): 

316 from sympy.sets.sets import FiniteSet 

317 min, max = arg.min, arg.max 

318 d = floor(min/(2*pi)) 

319 if min is not S.NegativeInfinity: 

320 min = min - d*2*pi 

321 if max is not S.Infinity: 

322 max = max - d*2*pi 

323 if AccumBounds(min, max).intersection(FiniteSet(pi/2, pi*Rational(5, 2))) \ 

324 is not S.EmptySet and \ 

325 AccumBounds(min, max).intersection(FiniteSet(pi*Rational(3, 2), 

326 pi*Rational(7, 2))) is not S.EmptySet: 

327 return AccumBounds(-1, 1) 

328 elif AccumBounds(min, max).intersection(FiniteSet(pi/2, pi*Rational(5, 2))) \ 

329 is not S.EmptySet: 

330 return AccumBounds(Min(sin(min), sin(max)), 1) 

331 elif AccumBounds(min, max).intersection(FiniteSet(pi*Rational(3, 2), pi*Rational(8, 2))) \ 

332 is not S.EmptySet: 

333 return AccumBounds(-1, Max(sin(min), sin(max))) 

334 else: 

335 return AccumBounds(Min(sin(min), sin(max)), 

336 Max(sin(min), sin(max))) 

337 elif isinstance(arg, SetExpr): 

338 return arg._eval_func(cls) 

339 

340 if arg.could_extract_minus_sign(): 

341 return -cls(-arg) 

342 

343 i_coeff = _imaginary_unit_as_coefficient(arg) 

344 if i_coeff is not None: 

345 from sympy.functions.elementary.hyperbolic import sinh 

346 return S.ImaginaryUnit*sinh(i_coeff) 

347 

348 pi_coeff = _pi_coeff(arg) 

349 if pi_coeff is not None: 

350 if pi_coeff.is_integer: 

351 return S.Zero 

352 

353 if (2*pi_coeff).is_integer: 

354 # is_even-case handled above as then pi_coeff.is_integer, 

355 # so check if known to be not even 

356 if pi_coeff.is_even is False: 

357 return S.NegativeOne**(pi_coeff - S.Half) 

358 

359 if not pi_coeff.is_Rational: 

360 narg = pi_coeff*pi 

361 if narg != arg: 

362 return cls(narg) 

363 return None 

364 

365 # https://github.com/sympy/sympy/issues/6048 

366 # transform a sine to a cosine, to avoid redundant code 

367 if pi_coeff.is_Rational: 

368 x = pi_coeff % 2 

369 if x > 1: 

370 return -cls((x % 1)*pi) 

371 if 2*x > 1: 

372 return cls((1 - x)*pi) 

373 narg = ((pi_coeff + Rational(3, 2)) % 2)*pi 

374 result = cos(narg) 

375 if not isinstance(result, cos): 

376 return result 

377 if pi_coeff*pi != arg: 

378 return cls(pi_coeff*pi) 

379 return None 

380 

381 if arg.is_Add: 

382 x, m = _peeloff_pi(arg) 

383 if m: 

384 m = m*pi 

385 return sin(m)*cos(x) + cos(m)*sin(x) 

386 

387 if arg.is_zero: 

388 return S.Zero 

389 

390 if isinstance(arg, asin): 

391 return arg.args[0] 

392 

393 if isinstance(arg, atan): 

394 x = arg.args[0] 

395 return x/sqrt(1 + x**2) 

396 

397 if isinstance(arg, atan2): 

398 y, x = arg.args 

399 return y/sqrt(x**2 + y**2) 

400 

401 if isinstance(arg, acos): 

402 x = arg.args[0] 

403 return sqrt(1 - x**2) 

404 

405 if isinstance(arg, acot): 

406 x = arg.args[0] 

407 return 1/(sqrt(1 + 1/x**2)*x) 

408 

409 if isinstance(arg, acsc): 

410 x = arg.args[0] 

411 return 1/x 

412 

413 if isinstance(arg, asec): 

414 x = arg.args[0] 

415 return sqrt(1 - 1/x**2) 

416 

417 @staticmethod 

418 @cacheit 

419 def taylor_term(n, x, *previous_terms): 

420 if n < 0 or n % 2 == 0: 

421 return S.Zero 

422 else: 

423 x = sympify(x) 

424 

425 if len(previous_terms) > 2: 

426 p = previous_terms[-2] 

427 return -p*x**2/(n*(n - 1)) 

428 else: 

429 return S.NegativeOne**(n//2)*x**n/factorial(n) 

430 

431 def _eval_nseries(self, x, n, logx, cdir=0): 

432 arg = self.args[0] 

433 if logx is not None: 

434 arg = arg.subs(log(x), logx) 

435 if arg.subs(x, 0).has(S.NaN, S.ComplexInfinity): 

436 raise PoleError("Cannot expand %s around 0" % (self)) 

437 return Function._eval_nseries(self, x, n=n, logx=logx, cdir=cdir) 

438 

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

440 from sympy.functions.elementary.hyperbolic import HyperbolicFunction 

441 I = S.ImaginaryUnit 

442 if isinstance(arg, (TrigonometricFunction, HyperbolicFunction)): 

443 arg = arg.func(arg.args[0]).rewrite(exp) 

444 return (exp(arg*I) - exp(-arg*I))/(2*I) 

445 

446 def _eval_rewrite_as_Pow(self, arg, **kwargs): 

447 if isinstance(arg, log): 

448 I = S.ImaginaryUnit 

449 x = arg.args[0] 

450 return I*x**-I/2 - I*x**I /2 

451 

452 def _eval_rewrite_as_cos(self, arg, **kwargs): 

453 return cos(arg - pi/2, evaluate=False) 

454 

455 def _eval_rewrite_as_tan(self, arg, **kwargs): 

456 tan_half = tan(S.Half*arg) 

457 return 2*tan_half/(1 + tan_half**2) 

458 

459 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

460 return sin(arg)*cos(arg)/cos(arg) 

461 

462 def _eval_rewrite_as_cot(self, arg, **kwargs): 

463 cot_half = cot(S.Half*arg) 

464 return Piecewise((0, And(Eq(im(arg), 0), Eq(Mod(arg, pi), 0))), 

465 (2*cot_half/(1 + cot_half**2), True)) 

466 

467 def _eval_rewrite_as_pow(self, arg, **kwargs): 

468 return self.rewrite(cos).rewrite(pow) 

469 

470 def _eval_rewrite_as_sqrt(self, arg, **kwargs): 

471 return self.rewrite(cos).rewrite(sqrt) 

472 

473 def _eval_rewrite_as_csc(self, arg, **kwargs): 

474 return 1/csc(arg) 

475 

476 def _eval_rewrite_as_sec(self, arg, **kwargs): 

477 return 1/sec(arg - pi/2, evaluate=False) 

478 

479 def _eval_rewrite_as_sinc(self, arg, **kwargs): 

480 return arg*sinc(arg) 

481 

482 def _eval_conjugate(self): 

483 return self.func(self.args[0].conjugate()) 

484 

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

486 from sympy.functions.elementary.hyperbolic import cosh, sinh 

487 re, im = self._as_real_imag(deep=deep, **hints) 

488 return (sin(re)*cosh(im), cos(re)*sinh(im)) 

489 

490 def _eval_expand_trig(self, **hints): 

491 from sympy.functions.special.polynomials import chebyshevt, chebyshevu 

492 arg = self.args[0] 

493 x = None 

494 if arg.is_Add: # TODO, implement more if deep stuff here 

495 # TODO: Do this more efficiently for more than two terms 

496 x, y = arg.as_two_terms() 

497 sx = sin(x, evaluate=False)._eval_expand_trig() 

498 sy = sin(y, evaluate=False)._eval_expand_trig() 

499 cx = cos(x, evaluate=False)._eval_expand_trig() 

500 cy = cos(y, evaluate=False)._eval_expand_trig() 

501 return sx*cy + sy*cx 

502 elif arg.is_Mul: 

503 n, x = arg.as_coeff_Mul(rational=True) 

504 if n.is_Integer: # n will be positive because of .eval 

505 # canonicalization 

506 

507 # See https://mathworld.wolfram.com/Multiple-AngleFormulas.html 

508 if n.is_odd: 

509 return S.NegativeOne**((n - 1)/2)*chebyshevt(n, sin(x)) 

510 else: 

511 return expand_mul(S.NegativeOne**(n/2 - 1)*cos(x)* 

512 chebyshevu(n - 1, sin(x)), deep=False) 

513 pi_coeff = _pi_coeff(arg) 

514 if pi_coeff is not None: 

515 if pi_coeff.is_Rational: 

516 return self.rewrite(sqrt) 

517 return sin(arg) 

518 

519 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

520 from sympy.calculus.accumulationbounds import AccumBounds 

521 arg = self.args[0] 

522 x0 = arg.subs(x, 0).cancel() 

523 n = x0/pi 

524 if n.is_integer: 

525 lt = (arg - n*pi).as_leading_term(x) 

526 return (S.NegativeOne**n)*lt 

527 if x0 is S.ComplexInfinity: 

528 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

529 if x0 in [S.Infinity, S.NegativeInfinity]: 

530 return AccumBounds(-1, 1) 

531 return self.func(x0) if x0.is_finite else self 

532 

533 def _eval_is_extended_real(self): 

534 if self.args[0].is_extended_real: 

535 return True 

536 

537 def _eval_is_finite(self): 

538 arg = self.args[0] 

539 if arg.is_extended_real: 

540 return True 

541 

542 def _eval_is_zero(self): 

543 rest, pi_mult = _peeloff_pi(self.args[0]) 

544 if rest.is_zero: 

545 return pi_mult.is_integer 

546 

547 def _eval_is_complex(self): 

548 if self.args[0].is_extended_real \ 

549 or self.args[0].is_complex: 

550 return True 

551 

552 

553class cos(TrigonometricFunction): 

554 """ 

555 The cosine function. 

556 

557 Returns the cosine of x (measured in radians). 

558 

559 Explanation 

560 =========== 

561 

562 See :func:`sin` for notes about automatic evaluation. 

563 

564 Examples 

565 ======== 

566 

567 >>> from sympy import cos, pi 

568 >>> from sympy.abc import x 

569 >>> cos(x**2).diff(x) 

570 -2*x*sin(x**2) 

571 >>> cos(1).diff(x) 

572 0 

573 >>> cos(pi) 

574 -1 

575 >>> cos(pi/2) 

576 0 

577 >>> cos(2*pi/3) 

578 -1/2 

579 >>> cos(pi/12) 

580 sqrt(2)/4 + sqrt(6)/4 

581 

582 See Also 

583 ======== 

584 

585 sin, csc, sec, tan, cot 

586 asin, acsc, acos, asec, atan, acot, atan2 

587 

588 References 

589 ========== 

590 

591 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

592 .. [2] https://dlmf.nist.gov/4.14 

593 .. [3] https://functions.wolfram.com/ElementaryFunctions/Cos 

594 

595 """ 

596 

597 def period(self, symbol=None): 

598 return self._period(2*pi, symbol) 

599 

600 def fdiff(self, argindex=1): 

601 if argindex == 1: 

602 return -sin(self.args[0]) 

603 else: 

604 raise ArgumentIndexError(self, argindex) 

605 

606 @classmethod 

607 def eval(cls, arg): 

608 from sympy.functions.special.polynomials import chebyshevt 

609 from sympy.calculus.accumulationbounds import AccumBounds 

610 from sympy.sets.setexpr import SetExpr 

611 if arg.is_Number: 

612 if arg is S.NaN: 

613 return S.NaN 

614 elif arg.is_zero: 

615 return S.One 

616 elif arg in (S.Infinity, S.NegativeInfinity): 

617 # In this case it is better to return AccumBounds(-1, 1) 

618 # rather than returning S.NaN, since AccumBounds(-1, 1) 

619 # preserves the information that sin(oo) is between 

620 # -1 and 1, where S.NaN does not do that. 

621 return AccumBounds(-1, 1) 

622 

623 if arg is S.ComplexInfinity: 

624 return S.NaN 

625 

626 if isinstance(arg, AccumBounds): 

627 return sin(arg + pi/2) 

628 elif isinstance(arg, SetExpr): 

629 return arg._eval_func(cls) 

630 

631 if arg.is_extended_real and arg.is_finite is False: 

632 return AccumBounds(-1, 1) 

633 

634 if arg.could_extract_minus_sign(): 

635 return cls(-arg) 

636 

637 i_coeff = _imaginary_unit_as_coefficient(arg) 

638 if i_coeff is not None: 

639 from sympy.functions.elementary.hyperbolic import cosh 

640 return cosh(i_coeff) 

641 

642 pi_coeff = _pi_coeff(arg) 

643 if pi_coeff is not None: 

644 if pi_coeff.is_integer: 

645 return (S.NegativeOne)**pi_coeff 

646 

647 if (2*pi_coeff).is_integer: 

648 # is_even-case handled above as then pi_coeff.is_integer, 

649 # so check if known to be not even 

650 if pi_coeff.is_even is False: 

651 return S.Zero 

652 

653 if not pi_coeff.is_Rational: 

654 narg = pi_coeff*pi 

655 if narg != arg: 

656 return cls(narg) 

657 return None 

658 

659 # cosine formula ##################### 

660 # https://github.com/sympy/sympy/issues/6048 

661 # explicit calculations are performed for 

662 # cos(k pi/n) for n = 8,10,12,15,20,24,30,40,60,120 

663 # Some other exact values like cos(k pi/240) can be 

664 # calculated using a partial-fraction decomposition 

665 # by calling cos( X ).rewrite(sqrt) 

666 if pi_coeff.is_Rational: 

667 q = pi_coeff.q 

668 p = pi_coeff.p % (2*q) 

669 if p > q: 

670 narg = (pi_coeff - 1)*pi 

671 return -cls(narg) 

672 if 2*p > q: 

673 narg = (1 - pi_coeff)*pi 

674 return -cls(narg) 

675 

676 # If nested sqrt's are worse than un-evaluation 

677 # you can require q to be in (1, 2, 3, 4, 6, 12) 

678 # q <= 12, q=15, q=20, q=24, q=30, q=40, q=60, q=120 return 

679 # expressions with 2 or fewer sqrt nestings. 

680 table2 = _table2() 

681 if q in table2: 

682 a, b = table2[q] 

683 a, b = p*pi/a, p*pi/b 

684 nvala, nvalb = cls(a), cls(b) 

685 if None in (nvala, nvalb): 

686 return None 

687 return nvala*nvalb + cls(pi/2 - a)*cls(pi/2 - b) 

688 

689 if q > 12: 

690 return None 

691 

692 cst_table_some = { 

693 3: S.Half, 

694 5: (sqrt(5) + 1) / 4, 

695 } 

696 if q in cst_table_some: 

697 cts = cst_table_some[pi_coeff.q] 

698 return chebyshevt(pi_coeff.p, cts).expand() 

699 

700 if 0 == q % 2: 

701 narg = (pi_coeff*2)*pi 

702 nval = cls(narg) 

703 if None == nval: 

704 return None 

705 x = (2*pi_coeff + 1)/2 

706 sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) 

707 return sign_cos*sqrt( (1 + nval)/2 ) 

708 return None 

709 

710 if arg.is_Add: 

711 x, m = _peeloff_pi(arg) 

712 if m: 

713 m = m*pi 

714 return cos(m)*cos(x) - sin(m)*sin(x) 

715 

716 if arg.is_zero: 

717 return S.One 

718 

719 if isinstance(arg, acos): 

720 return arg.args[0] 

721 

722 if isinstance(arg, atan): 

723 x = arg.args[0] 

724 return 1/sqrt(1 + x**2) 

725 

726 if isinstance(arg, atan2): 

727 y, x = arg.args 

728 return x/sqrt(x**2 + y**2) 

729 

730 if isinstance(arg, asin): 

731 x = arg.args[0] 

732 return sqrt(1 - x ** 2) 

733 

734 if isinstance(arg, acot): 

735 x = arg.args[0] 

736 return 1/sqrt(1 + 1/x**2) 

737 

738 if isinstance(arg, acsc): 

739 x = arg.args[0] 

740 return sqrt(1 - 1/x**2) 

741 

742 if isinstance(arg, asec): 

743 x = arg.args[0] 

744 return 1/x 

745 

746 @staticmethod 

747 @cacheit 

748 def taylor_term(n, x, *previous_terms): 

749 if n < 0 or n % 2 == 1: 

750 return S.Zero 

751 else: 

752 x = sympify(x) 

753 

754 if len(previous_terms) > 2: 

755 p = previous_terms[-2] 

756 return -p*x**2/(n*(n - 1)) 

757 else: 

758 return S.NegativeOne**(n//2)*x**n/factorial(n) 

759 

760 def _eval_nseries(self, x, n, logx, cdir=0): 

761 arg = self.args[0] 

762 if logx is not None: 

763 arg = arg.subs(log(x), logx) 

764 if arg.subs(x, 0).has(S.NaN, S.ComplexInfinity): 

765 raise PoleError("Cannot expand %s around 0" % (self)) 

766 return Function._eval_nseries(self, x, n=n, logx=logx, cdir=cdir) 

767 

768 def _eval_rewrite_as_exp(self, arg, **kwargs): 

769 I = S.ImaginaryUnit 

770 from sympy.functions.elementary.hyperbolic import HyperbolicFunction 

771 if isinstance(arg, (TrigonometricFunction, HyperbolicFunction)): 

772 arg = arg.func(arg.args[0]).rewrite(exp) 

773 return (exp(arg*I) + exp(-arg*I))/2 

774 

775 def _eval_rewrite_as_Pow(self, arg, **kwargs): 

776 if isinstance(arg, log): 

777 I = S.ImaginaryUnit 

778 x = arg.args[0] 

779 return x**I/2 + x**-I/2 

780 

781 def _eval_rewrite_as_sin(self, arg, **kwargs): 

782 return sin(arg + pi/2, evaluate=False) 

783 

784 def _eval_rewrite_as_tan(self, arg, **kwargs): 

785 tan_half = tan(S.Half*arg)**2 

786 return (1 - tan_half)/(1 + tan_half) 

787 

788 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

789 return sin(arg)*cos(arg)/sin(arg) 

790 

791 def _eval_rewrite_as_cot(self, arg, **kwargs): 

792 cot_half = cot(S.Half*arg)**2 

793 return Piecewise((1, And(Eq(im(arg), 0), Eq(Mod(arg, 2*pi), 0))), 

794 ((cot_half - 1)/(cot_half + 1), True)) 

795 

796 def _eval_rewrite_as_pow(self, arg, **kwargs): 

797 return self._eval_rewrite_as_sqrt(arg) 

798 

799 def _eval_rewrite_as_sqrt(self, arg: Expr, **kwargs): 

800 from sympy.functions.special.polynomials import chebyshevt 

801 

802 pi_coeff = _pi_coeff(arg) 

803 if pi_coeff is None: 

804 return None 

805 

806 if isinstance(pi_coeff, Integer): 

807 return None 

808 

809 if not isinstance(pi_coeff, Rational): 

810 return None 

811 

812 cst_table_some = cos_table() 

813 

814 if pi_coeff.q in cst_table_some: 

815 rv = chebyshevt(pi_coeff.p, cst_table_some[pi_coeff.q]()) 

816 if pi_coeff.q < 257: 

817 rv = rv.expand() 

818 return rv 

819 

820 if not pi_coeff.q % 2: # recursively remove factors of 2 

821 pico2 = pi_coeff * 2 

822 nval = cos(pico2 * pi).rewrite(sqrt) 

823 x = (pico2 + 1) / 2 

824 sign_cos = -1 if int(x) % 2 else 1 

825 return sign_cos * sqrt((1 + nval) / 2) 

826 

827 FC = fermat_coords(pi_coeff.q) 

828 if FC: 

829 denoms = FC 

830 else: 

831 denoms = [b**e for b, e in factorint(pi_coeff.q).items()] 

832 

833 apart = ipartfrac(*denoms) 

834 decomp = (pi_coeff.p * Rational(n, d) for n, d in zip(apart, denoms)) 

835 X = [(x[1], x[0]*pi) for x in zip(decomp, numbered_symbols('z'))] 

836 pcls = cos(sum(x[0] for x in X))._eval_expand_trig().subs(X) 

837 

838 if not FC or len(FC) == 1: 

839 return pcls 

840 return pcls.rewrite(sqrt) 

841 

842 def _eval_rewrite_as_sec(self, arg, **kwargs): 

843 return 1/sec(arg) 

844 

845 def _eval_rewrite_as_csc(self, arg, **kwargs): 

846 return 1/sec(arg).rewrite(csc) 

847 

848 def _eval_conjugate(self): 

849 return self.func(self.args[0].conjugate()) 

850 

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

852 from sympy.functions.elementary.hyperbolic import cosh, sinh 

853 re, im = self._as_real_imag(deep=deep, **hints) 

854 return (cos(re)*cosh(im), -sin(re)*sinh(im)) 

855 

856 def _eval_expand_trig(self, **hints): 

857 from sympy.functions.special.polynomials import chebyshevt 

858 arg = self.args[0] 

859 x = None 

860 if arg.is_Add: # TODO: Do this more efficiently for more than two terms 

861 x, y = arg.as_two_terms() 

862 sx = sin(x, evaluate=False)._eval_expand_trig() 

863 sy = sin(y, evaluate=False)._eval_expand_trig() 

864 cx = cos(x, evaluate=False)._eval_expand_trig() 

865 cy = cos(y, evaluate=False)._eval_expand_trig() 

866 return cx*cy - sx*sy 

867 elif arg.is_Mul: 

868 coeff, terms = arg.as_coeff_Mul(rational=True) 

869 if coeff.is_Integer: 

870 return chebyshevt(coeff, cos(terms)) 

871 pi_coeff = _pi_coeff(arg) 

872 if pi_coeff is not None: 

873 if pi_coeff.is_Rational: 

874 return self.rewrite(sqrt) 

875 return cos(arg) 

876 

877 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

878 from sympy.calculus.accumulationbounds import AccumBounds 

879 arg = self.args[0] 

880 x0 = arg.subs(x, 0).cancel() 

881 n = (x0 + pi/2)/pi 

882 if n.is_integer: 

883 lt = (arg - n*pi + pi/2).as_leading_term(x) 

884 return (S.NegativeOne**n)*lt 

885 if x0 is S.ComplexInfinity: 

886 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

887 if x0 in [S.Infinity, S.NegativeInfinity]: 

888 return AccumBounds(-1, 1) 

889 return self.func(x0) if x0.is_finite else self 

890 

891 def _eval_is_extended_real(self): 

892 if self.args[0].is_extended_real: 

893 return True 

894 

895 def _eval_is_finite(self): 

896 arg = self.args[0] 

897 

898 if arg.is_extended_real: 

899 return True 

900 

901 def _eval_is_complex(self): 

902 if self.args[0].is_extended_real \ 

903 or self.args[0].is_complex: 

904 return True 

905 

906 def _eval_is_zero(self): 

907 rest, pi_mult = _peeloff_pi(self.args[0]) 

908 if rest.is_zero and pi_mult: 

909 return (pi_mult - S.Half).is_integer 

910 

911 

912class tan(TrigonometricFunction): 

913 """ 

914 The tangent function. 

915 

916 Returns the tangent of x (measured in radians). 

917 

918 Explanation 

919 =========== 

920 

921 See :class:`sin` for notes about automatic evaluation. 

922 

923 Examples 

924 ======== 

925 

926 >>> from sympy import tan, pi 

927 >>> from sympy.abc import x 

928 >>> tan(x**2).diff(x) 

929 2*x*(tan(x**2)**2 + 1) 

930 >>> tan(1).diff(x) 

931 0 

932 >>> tan(pi/8).expand() 

933 -1 + sqrt(2) 

934 

935 See Also 

936 ======== 

937 

938 sin, csc, cos, sec, cot 

939 asin, acsc, acos, asec, atan, acot, atan2 

940 

941 References 

942 ========== 

943 

944 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

945 .. [2] https://dlmf.nist.gov/4.14 

946 .. [3] https://functions.wolfram.com/ElementaryFunctions/Tan 

947 

948 """ 

949 

950 def period(self, symbol=None): 

951 return self._period(pi, symbol) 

952 

953 def fdiff(self, argindex=1): 

954 if argindex == 1: 

955 return S.One + self**2 

956 else: 

957 raise ArgumentIndexError(self, argindex) 

958 

959 def inverse(self, argindex=1): 

960 """ 

961 Returns the inverse of this function. 

962 """ 

963 return atan 

964 

965 @classmethod 

966 def eval(cls, arg): 

967 from sympy.calculus.accumulationbounds import AccumBounds 

968 if arg.is_Number: 

969 if arg is S.NaN: 

970 return S.NaN 

971 elif arg.is_zero: 

972 return S.Zero 

973 elif arg in (S.Infinity, S.NegativeInfinity): 

974 return AccumBounds(S.NegativeInfinity, S.Infinity) 

975 

976 if arg is S.ComplexInfinity: 

977 return S.NaN 

978 

979 if isinstance(arg, AccumBounds): 

980 min, max = arg.min, arg.max 

981 d = floor(min/pi) 

982 if min is not S.NegativeInfinity: 

983 min = min - d*pi 

984 if max is not S.Infinity: 

985 max = max - d*pi 

986 from sympy.sets.sets import FiniteSet 

987 if AccumBounds(min, max).intersection(FiniteSet(pi/2, pi*Rational(3, 2))): 

988 return AccumBounds(S.NegativeInfinity, S.Infinity) 

989 else: 

990 return AccumBounds(tan(min), tan(max)) 

991 

992 if arg.could_extract_minus_sign(): 

993 return -cls(-arg) 

994 

995 i_coeff = _imaginary_unit_as_coefficient(arg) 

996 if i_coeff is not None: 

997 from sympy.functions.elementary.hyperbolic import tanh 

998 return S.ImaginaryUnit*tanh(i_coeff) 

999 

1000 pi_coeff = _pi_coeff(arg, 2) 

1001 if pi_coeff is not None: 

1002 if pi_coeff.is_integer: 

1003 return S.Zero 

1004 

1005 if not pi_coeff.is_Rational: 

1006 narg = pi_coeff*pi 

1007 if narg != arg: 

1008 return cls(narg) 

1009 return None 

1010 

1011 if pi_coeff.is_Rational: 

1012 q = pi_coeff.q 

1013 p = pi_coeff.p % q 

1014 # ensure simplified results are returned for n*pi/5, n*pi/10 

1015 table10 = { 

1016 1: sqrt(1 - 2*sqrt(5)/5), 

1017 2: sqrt(5 - 2*sqrt(5)), 

1018 3: sqrt(1 + 2*sqrt(5)/5), 

1019 4: sqrt(5 + 2*sqrt(5)) 

1020 } 

1021 if q in (5, 10): 

1022 n = 10*p/q 

1023 if n > 5: 

1024 n = 10 - n 

1025 return -table10[n] 

1026 else: 

1027 return table10[n] 

1028 if not pi_coeff.q % 2: 

1029 narg = pi_coeff*pi*2 

1030 cresult, sresult = cos(narg), cos(narg - pi/2) 

1031 if not isinstance(cresult, cos) \ 

1032 and not isinstance(sresult, cos): 

1033 if sresult == 0: 

1034 return S.ComplexInfinity 

1035 return 1/sresult - cresult/sresult 

1036 

1037 table2 = _table2() 

1038 if q in table2: 

1039 a, b = table2[q] 

1040 nvala, nvalb = cls(p*pi/a), cls(p*pi/b) 

1041 if None in (nvala, nvalb): 

1042 return None 

1043 return (nvala - nvalb)/(1 + nvala*nvalb) 

1044 narg = ((pi_coeff + S.Half) % 1 - S.Half)*pi 

1045 # see cos() to specify which expressions should be 

1046 # expanded automatically in terms of radicals 

1047 cresult, sresult = cos(narg), cos(narg - pi/2) 

1048 if not isinstance(cresult, cos) \ 

1049 and not isinstance(sresult, cos): 

1050 if cresult == 0: 

1051 return S.ComplexInfinity 

1052 return (sresult/cresult) 

1053 if narg != arg: 

1054 return cls(narg) 

1055 

1056 if arg.is_Add: 

1057 x, m = _peeloff_pi(arg) 

1058 if m: 

1059 tanm = tan(m*pi) 

1060 if tanm is S.ComplexInfinity: 

1061 return -cot(x) 

1062 else: # tanm == 0 

1063 return tan(x) 

1064 

1065 if arg.is_zero: 

1066 return S.Zero 

1067 

1068 if isinstance(arg, atan): 

1069 return arg.args[0] 

1070 

1071 if isinstance(arg, atan2): 

1072 y, x = arg.args 

1073 return y/x 

1074 

1075 if isinstance(arg, asin): 

1076 x = arg.args[0] 

1077 return x/sqrt(1 - x**2) 

1078 

1079 if isinstance(arg, acos): 

1080 x = arg.args[0] 

1081 return sqrt(1 - x**2)/x 

1082 

1083 if isinstance(arg, acot): 

1084 x = arg.args[0] 

1085 return 1/x 

1086 

1087 if isinstance(arg, acsc): 

1088 x = arg.args[0] 

1089 return 1/(sqrt(1 - 1/x**2)*x) 

1090 

1091 if isinstance(arg, asec): 

1092 x = arg.args[0] 

1093 return sqrt(1 - 1/x**2)*x 

1094 

1095 @staticmethod 

1096 @cacheit 

1097 def taylor_term(n, x, *previous_terms): 

1098 if n < 0 or n % 2 == 0: 

1099 return S.Zero 

1100 else: 

1101 x = sympify(x) 

1102 

1103 a, b = ((n - 1)//2), 2**(n + 1) 

1104 

1105 B = bernoulli(n + 1) 

1106 F = factorial(n + 1) 

1107 

1108 return S.NegativeOne**a*b*(b - 1)*B/F*x**n 

1109 

1110 def _eval_nseries(self, x, n, logx, cdir=0): 

1111 i = self.args[0].limit(x, 0)*2/pi 

1112 if i and i.is_Integer: 

1113 return self.rewrite(cos)._eval_nseries(x, n=n, logx=logx) 

1114 return Function._eval_nseries(self, x, n=n, logx=logx) 

1115 

1116 def _eval_rewrite_as_Pow(self, arg, **kwargs): 

1117 if isinstance(arg, log): 

1118 I = S.ImaginaryUnit 

1119 x = arg.args[0] 

1120 return I*(x**-I - x**I)/(x**-I + x**I) 

1121 

1122 def _eval_conjugate(self): 

1123 return self.func(self.args[0].conjugate()) 

1124 

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

1126 re, im = self._as_real_imag(deep=deep, **hints) 

1127 if im: 

1128 from sympy.functions.elementary.hyperbolic import cosh, sinh 

1129 denom = cos(2*re) + cosh(2*im) 

1130 return (sin(2*re)/denom, sinh(2*im)/denom) 

1131 else: 

1132 return (self.func(re), S.Zero) 

1133 

1134 def _eval_expand_trig(self, **hints): 

1135 arg = self.args[0] 

1136 x = None 

1137 if arg.is_Add: 

1138 n = len(arg.args) 

1139 TX = [] 

1140 for x in arg.args: 

1141 tx = tan(x, evaluate=False)._eval_expand_trig() 

1142 TX.append(tx) 

1143 

1144 Yg = numbered_symbols('Y') 

1145 Y = [ next(Yg) for i in range(n) ] 

1146 

1147 p = [0, 0] 

1148 for i in range(n + 1): 

1149 p[1 - i % 2] += symmetric_poly(i, Y)*(-1)**((i % 4)//2) 

1150 return (p[0]/p[1]).subs(list(zip(Y, TX))) 

1151 

1152 elif arg.is_Mul: 

1153 coeff, terms = arg.as_coeff_Mul(rational=True) 

1154 if coeff.is_Integer and coeff > 1: 

1155 I = S.ImaginaryUnit 

1156 z = Symbol('dummy', real=True) 

1157 P = ((1 + I*z)**coeff).expand() 

1158 return (im(P)/re(P)).subs([(z, tan(terms))]) 

1159 return tan(arg) 

1160 

1161 def _eval_rewrite_as_exp(self, arg, **kwargs): 

1162 I = S.ImaginaryUnit 

1163 from sympy.functions.elementary.hyperbolic import HyperbolicFunction 

1164 if isinstance(arg, (TrigonometricFunction, HyperbolicFunction)): 

1165 arg = arg.func(arg.args[0]).rewrite(exp) 

1166 neg_exp, pos_exp = exp(-arg*I), exp(arg*I) 

1167 return I*(neg_exp - pos_exp)/(neg_exp + pos_exp) 

1168 

1169 def _eval_rewrite_as_sin(self, x, **kwargs): 

1170 return 2*sin(x)**2/sin(2*x) 

1171 

1172 def _eval_rewrite_as_cos(self, x, **kwargs): 

1173 return cos(x - pi/2, evaluate=False)/cos(x) 

1174 

1175 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

1176 return sin(arg)/cos(arg) 

1177 

1178 def _eval_rewrite_as_cot(self, arg, **kwargs): 

1179 return 1/cot(arg) 

1180 

1181 def _eval_rewrite_as_sec(self, arg, **kwargs): 

1182 sin_in_sec_form = sin(arg).rewrite(sec) 

1183 cos_in_sec_form = cos(arg).rewrite(sec) 

1184 return sin_in_sec_form/cos_in_sec_form 

1185 

1186 def _eval_rewrite_as_csc(self, arg, **kwargs): 

1187 sin_in_csc_form = sin(arg).rewrite(csc) 

1188 cos_in_csc_form = cos(arg).rewrite(csc) 

1189 return sin_in_csc_form/cos_in_csc_form 

1190 

1191 def _eval_rewrite_as_pow(self, arg, **kwargs): 

1192 y = self.rewrite(cos).rewrite(pow) 

1193 if y.has(cos): 

1194 return None 

1195 return y 

1196 

1197 def _eval_rewrite_as_sqrt(self, arg, **kwargs): 

1198 y = self.rewrite(cos).rewrite(sqrt) 

1199 if y.has(cos): 

1200 return None 

1201 return y 

1202 

1203 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

1204 from sympy.calculus.accumulationbounds import AccumBounds 

1205 from sympy.functions.elementary.complexes import re 

1206 arg = self.args[0] 

1207 x0 = arg.subs(x, 0).cancel() 

1208 n = 2*x0/pi 

1209 if n.is_integer: 

1210 lt = (arg - n*pi/2).as_leading_term(x) 

1211 return lt if n.is_even else -1/lt 

1212 if x0 is S.ComplexInfinity: 

1213 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

1214 if x0 in (S.Infinity, S.NegativeInfinity): 

1215 return AccumBounds(S.NegativeInfinity, S.Infinity) 

1216 return self.func(x0) if x0.is_finite else self 

1217 

1218 def _eval_is_extended_real(self): 

1219 # FIXME: currently tan(pi/2) return zoo 

1220 return self.args[0].is_extended_real 

1221 

1222 def _eval_is_real(self): 

1223 arg = self.args[0] 

1224 if arg.is_real and (arg/pi - S.Half).is_integer is False: 

1225 return True 

1226 

1227 def _eval_is_finite(self): 

1228 arg = self.args[0] 

1229 

1230 if arg.is_real and (arg/pi - S.Half).is_integer is False: 

1231 return True 

1232 

1233 if arg.is_imaginary: 

1234 return True 

1235 

1236 def _eval_is_zero(self): 

1237 rest, pi_mult = _peeloff_pi(self.args[0]) 

1238 if rest.is_zero: 

1239 return pi_mult.is_integer 

1240 

1241 def _eval_is_complex(self): 

1242 arg = self.args[0] 

1243 

1244 if arg.is_real and (arg/pi - S.Half).is_integer is False: 

1245 return True 

1246 

1247 

1248class cot(TrigonometricFunction): 

1249 """ 

1250 The cotangent function. 

1251 

1252 Returns the cotangent of x (measured in radians). 

1253 

1254 Explanation 

1255 =========== 

1256 

1257 See :class:`sin` for notes about automatic evaluation. 

1258 

1259 Examples 

1260 ======== 

1261 

1262 >>> from sympy import cot, pi 

1263 >>> from sympy.abc import x 

1264 >>> cot(x**2).diff(x) 

1265 2*x*(-cot(x**2)**2 - 1) 

1266 >>> cot(1).diff(x) 

1267 0 

1268 >>> cot(pi/12) 

1269 sqrt(3) + 2 

1270 

1271 See Also 

1272 ======== 

1273 

1274 sin, csc, cos, sec, tan 

1275 asin, acsc, acos, asec, atan, acot, atan2 

1276 

1277 References 

1278 ========== 

1279 

1280 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

1281 .. [2] https://dlmf.nist.gov/4.14 

1282 .. [3] https://functions.wolfram.com/ElementaryFunctions/Cot 

1283 

1284 """ 

1285 

1286 def period(self, symbol=None): 

1287 return self._period(pi, symbol) 

1288 

1289 def fdiff(self, argindex=1): 

1290 if argindex == 1: 

1291 return S.NegativeOne - self**2 

1292 else: 

1293 raise ArgumentIndexError(self, argindex) 

1294 

1295 def inverse(self, argindex=1): 

1296 """ 

1297 Returns the inverse of this function. 

1298 """ 

1299 return acot 

1300 

1301 @classmethod 

1302 def eval(cls, arg): 

1303 from sympy.calculus.accumulationbounds import AccumBounds 

1304 if arg.is_Number: 

1305 if arg is S.NaN: 

1306 return S.NaN 

1307 if arg.is_zero: 

1308 return S.ComplexInfinity 

1309 elif arg in (S.Infinity, S.NegativeInfinity): 

1310 return AccumBounds(S.NegativeInfinity, S.Infinity) 

1311 

1312 if arg is S.ComplexInfinity: 

1313 return S.NaN 

1314 

1315 if isinstance(arg, AccumBounds): 

1316 return -tan(arg + pi/2) 

1317 

1318 if arg.could_extract_minus_sign(): 

1319 return -cls(-arg) 

1320 

1321 i_coeff = _imaginary_unit_as_coefficient(arg) 

1322 if i_coeff is not None: 

1323 from sympy.functions.elementary.hyperbolic import coth 

1324 return -S.ImaginaryUnit*coth(i_coeff) 

1325 

1326 pi_coeff = _pi_coeff(arg, 2) 

1327 if pi_coeff is not None: 

1328 if pi_coeff.is_integer: 

1329 return S.ComplexInfinity 

1330 

1331 if not pi_coeff.is_Rational: 

1332 narg = pi_coeff*pi 

1333 if narg != arg: 

1334 return cls(narg) 

1335 return None 

1336 

1337 if pi_coeff.is_Rational: 

1338 if pi_coeff.q in (5, 10): 

1339 return tan(pi/2 - arg) 

1340 if pi_coeff.q > 2 and not pi_coeff.q % 2: 

1341 narg = pi_coeff*pi*2 

1342 cresult, sresult = cos(narg), cos(narg - pi/2) 

1343 if not isinstance(cresult, cos) \ 

1344 and not isinstance(sresult, cos): 

1345 return 1/sresult + cresult/sresult 

1346 q = pi_coeff.q 

1347 p = pi_coeff.p % q 

1348 table2 = _table2() 

1349 if q in table2: 

1350 a, b = table2[q] 

1351 nvala, nvalb = cls(p*pi/a), cls(p*pi/b) 

1352 if None in (nvala, nvalb): 

1353 return None 

1354 return (1 + nvala*nvalb)/(nvalb - nvala) 

1355 narg = (((pi_coeff + S.Half) % 1) - S.Half)*pi 

1356 # see cos() to specify which expressions should be 

1357 # expanded automatically in terms of radicals 

1358 cresult, sresult = cos(narg), cos(narg - pi/2) 

1359 if not isinstance(cresult, cos) \ 

1360 and not isinstance(sresult, cos): 

1361 if sresult == 0: 

1362 return S.ComplexInfinity 

1363 return cresult/sresult 

1364 if narg != arg: 

1365 return cls(narg) 

1366 

1367 if arg.is_Add: 

1368 x, m = _peeloff_pi(arg) 

1369 if m: 

1370 cotm = cot(m*pi) 

1371 if cotm is S.ComplexInfinity: 

1372 return cot(x) 

1373 else: # cotm == 0 

1374 return -tan(x) 

1375 

1376 if arg.is_zero: 

1377 return S.ComplexInfinity 

1378 

1379 if isinstance(arg, acot): 

1380 return arg.args[0] 

1381 

1382 if isinstance(arg, atan): 

1383 x = arg.args[0] 

1384 return 1/x 

1385 

1386 if isinstance(arg, atan2): 

1387 y, x = arg.args 

1388 return x/y 

1389 

1390 if isinstance(arg, asin): 

1391 x = arg.args[0] 

1392 return sqrt(1 - x**2)/x 

1393 

1394 if isinstance(arg, acos): 

1395 x = arg.args[0] 

1396 return x/sqrt(1 - x**2) 

1397 

1398 if isinstance(arg, acsc): 

1399 x = arg.args[0] 

1400 return sqrt(1 - 1/x**2)*x 

1401 

1402 if isinstance(arg, asec): 

1403 x = arg.args[0] 

1404 return 1/(sqrt(1 - 1/x**2)*x) 

1405 

1406 @staticmethod 

1407 @cacheit 

1408 def taylor_term(n, x, *previous_terms): 

1409 if n == 0: 

1410 return 1/sympify(x) 

1411 elif n < 0 or n % 2 == 0: 

1412 return S.Zero 

1413 else: 

1414 x = sympify(x) 

1415 

1416 B = bernoulli(n + 1) 

1417 F = factorial(n + 1) 

1418 

1419 return S.NegativeOne**((n + 1)//2)*2**(n + 1)*B/F*x**n 

1420 

1421 def _eval_nseries(self, x, n, logx, cdir=0): 

1422 i = self.args[0].limit(x, 0)/pi 

1423 if i and i.is_Integer: 

1424 return self.rewrite(cos)._eval_nseries(x, n=n, logx=logx) 

1425 return self.rewrite(tan)._eval_nseries(x, n=n, logx=logx) 

1426 

1427 def _eval_conjugate(self): 

1428 return self.func(self.args[0].conjugate()) 

1429 

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

1431 re, im = self._as_real_imag(deep=deep, **hints) 

1432 if im: 

1433 from sympy.functions.elementary.hyperbolic import cosh, sinh 

1434 denom = cos(2*re) - cosh(2*im) 

1435 return (-sin(2*re)/denom, sinh(2*im)/denom) 

1436 else: 

1437 return (self.func(re), S.Zero) 

1438 

1439 def _eval_rewrite_as_exp(self, arg, **kwargs): 

1440 from sympy.functions.elementary.hyperbolic import HyperbolicFunction 

1441 I = S.ImaginaryUnit 

1442 if isinstance(arg, (TrigonometricFunction, HyperbolicFunction)): 

1443 arg = arg.func(arg.args[0]).rewrite(exp) 

1444 neg_exp, pos_exp = exp(-arg*I), exp(arg*I) 

1445 return I*(pos_exp + neg_exp)/(pos_exp - neg_exp) 

1446 

1447 def _eval_rewrite_as_Pow(self, arg, **kwargs): 

1448 if isinstance(arg, log): 

1449 I = S.ImaginaryUnit 

1450 x = arg.args[0] 

1451 return -I*(x**-I + x**I)/(x**-I - x**I) 

1452 

1453 def _eval_rewrite_as_sin(self, x, **kwargs): 

1454 return sin(2*x)/(2*(sin(x)**2)) 

1455 

1456 def _eval_rewrite_as_cos(self, x, **kwargs): 

1457 return cos(x)/cos(x - pi/2, evaluate=False) 

1458 

1459 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

1460 return cos(arg)/sin(arg) 

1461 

1462 def _eval_rewrite_as_tan(self, arg, **kwargs): 

1463 return 1/tan(arg) 

1464 

1465 def _eval_rewrite_as_sec(self, arg, **kwargs): 

1466 cos_in_sec_form = cos(arg).rewrite(sec) 

1467 sin_in_sec_form = sin(arg).rewrite(sec) 

1468 return cos_in_sec_form/sin_in_sec_form 

1469 

1470 def _eval_rewrite_as_csc(self, arg, **kwargs): 

1471 cos_in_csc_form = cos(arg).rewrite(csc) 

1472 sin_in_csc_form = sin(arg).rewrite(csc) 

1473 return cos_in_csc_form/sin_in_csc_form 

1474 

1475 def _eval_rewrite_as_pow(self, arg, **kwargs): 

1476 y = self.rewrite(cos).rewrite(pow) 

1477 if y.has(cos): 

1478 return None 

1479 return y 

1480 

1481 def _eval_rewrite_as_sqrt(self, arg, **kwargs): 

1482 y = self.rewrite(cos).rewrite(sqrt) 

1483 if y.has(cos): 

1484 return None 

1485 return y 

1486 

1487 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

1488 from sympy.calculus.accumulationbounds import AccumBounds 

1489 from sympy.functions.elementary.complexes import re 

1490 arg = self.args[0] 

1491 x0 = arg.subs(x, 0).cancel() 

1492 n = 2*x0/pi 

1493 if n.is_integer: 

1494 lt = (arg - n*pi/2).as_leading_term(x) 

1495 return 1/lt if n.is_even else -lt 

1496 if x0 is S.ComplexInfinity: 

1497 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

1498 if x0 in (S.Infinity, S.NegativeInfinity): 

1499 return AccumBounds(S.NegativeInfinity, S.Infinity) 

1500 return self.func(x0) if x0.is_finite else self 

1501 

1502 def _eval_is_extended_real(self): 

1503 return self.args[0].is_extended_real 

1504 

1505 def _eval_expand_trig(self, **hints): 

1506 arg = self.args[0] 

1507 x = None 

1508 if arg.is_Add: 

1509 n = len(arg.args) 

1510 CX = [] 

1511 for x in arg.args: 

1512 cx = cot(x, evaluate=False)._eval_expand_trig() 

1513 CX.append(cx) 

1514 

1515 Yg = numbered_symbols('Y') 

1516 Y = [ next(Yg) for i in range(n) ] 

1517 

1518 p = [0, 0] 

1519 for i in range(n, -1, -1): 

1520 p[(n - i) % 2] += symmetric_poly(i, Y)*(-1)**(((n - i) % 4)//2) 

1521 return (p[0]/p[1]).subs(list(zip(Y, CX))) 

1522 elif arg.is_Mul: 

1523 coeff, terms = arg.as_coeff_Mul(rational=True) 

1524 if coeff.is_Integer and coeff > 1: 

1525 I = S.ImaginaryUnit 

1526 z = Symbol('dummy', real=True) 

1527 P = ((z + I)**coeff).expand() 

1528 return (re(P)/im(P)).subs([(z, cot(terms))]) 

1529 return cot(arg) # XXX sec and csc return 1/cos and 1/sin 

1530 

1531 def _eval_is_finite(self): 

1532 arg = self.args[0] 

1533 if arg.is_real and (arg/pi).is_integer is False: 

1534 return True 

1535 if arg.is_imaginary: 

1536 return True 

1537 

1538 def _eval_is_real(self): 

1539 arg = self.args[0] 

1540 if arg.is_real and (arg/pi).is_integer is False: 

1541 return True 

1542 

1543 def _eval_is_complex(self): 

1544 arg = self.args[0] 

1545 if arg.is_real and (arg/pi).is_integer is False: 

1546 return True 

1547 

1548 def _eval_is_zero(self): 

1549 rest, pimult = _peeloff_pi(self.args[0]) 

1550 if pimult and rest.is_zero: 

1551 return (pimult - S.Half).is_integer 

1552 

1553 def _eval_subs(self, old, new): 

1554 arg = self.args[0] 

1555 argnew = arg.subs(old, new) 

1556 if arg != argnew and (argnew/pi).is_integer: 

1557 return S.ComplexInfinity 

1558 return cot(argnew) 

1559 

1560 

1561class ReciprocalTrigonometricFunction(TrigonometricFunction): 

1562 """Base class for reciprocal functions of trigonometric functions. """ 

1563 

1564 _reciprocal_of = None # mandatory, to be defined in subclass 

1565 _singularities = (S.ComplexInfinity,) 

1566 

1567 # _is_even and _is_odd are used for correct evaluation of csc(-x), sec(-x) 

1568 # TODO refactor into TrigonometricFunction common parts of 

1569 # trigonometric functions eval() like even/odd, func(x+2*k*pi), etc. 

1570 

1571 # optional, to be defined in subclasses: 

1572 _is_even: FuzzyBool = None 

1573 _is_odd: FuzzyBool = None 

1574 

1575 @classmethod 

1576 def eval(cls, arg): 

1577 if arg.could_extract_minus_sign(): 

1578 if cls._is_even: 

1579 return cls(-arg) 

1580 if cls._is_odd: 

1581 return -cls(-arg) 

1582 

1583 pi_coeff = _pi_coeff(arg) 

1584 if (pi_coeff is not None 

1585 and not (2*pi_coeff).is_integer 

1586 and pi_coeff.is_Rational): 

1587 q = pi_coeff.q 

1588 p = pi_coeff.p % (2*q) 

1589 if p > q: 

1590 narg = (pi_coeff - 1)*pi 

1591 return -cls(narg) 

1592 if 2*p > q: 

1593 narg = (1 - pi_coeff)*pi 

1594 if cls._is_odd: 

1595 return cls(narg) 

1596 elif cls._is_even: 

1597 return -cls(narg) 

1598 

1599 if hasattr(arg, 'inverse') and arg.inverse() == cls: 

1600 return arg.args[0] 

1601 

1602 t = cls._reciprocal_of.eval(arg) 

1603 if t is None: 

1604 return t 

1605 elif any(isinstance(i, cos) for i in (t, -t)): 

1606 return (1/t).rewrite(sec) 

1607 elif any(isinstance(i, sin) for i in (t, -t)): 

1608 return (1/t).rewrite(csc) 

1609 else: 

1610 return 1/t 

1611 

1612 def _call_reciprocal(self, method_name, *args, **kwargs): 

1613 # Calls method_name on _reciprocal_of 

1614 o = self._reciprocal_of(self.args[0]) 

1615 return getattr(o, method_name)(*args, **kwargs) 

1616 

1617 def _calculate_reciprocal(self, method_name, *args, **kwargs): 

1618 # If calling method_name on _reciprocal_of returns a value != None 

1619 # then return the reciprocal of that value 

1620 t = self._call_reciprocal(method_name, *args, **kwargs) 

1621 return 1/t if t is not None else t 

1622 

1623 def _rewrite_reciprocal(self, method_name, arg): 

1624 # Special handling for rewrite functions. If reciprocal rewrite returns 

1625 # unmodified expression, then return None 

1626 t = self._call_reciprocal(method_name, arg) 

1627 if t is not None and t != self._reciprocal_of(arg): 

1628 return 1/t 

1629 

1630 def _period(self, symbol): 

1631 f = expand_mul(self.args[0]) 

1632 return self._reciprocal_of(f).period(symbol) 

1633 

1634 def fdiff(self, argindex=1): 

1635 return -self._calculate_reciprocal("fdiff", argindex)/self**2 

1636 

1637 def _eval_rewrite_as_exp(self, arg, **kwargs): 

1638 return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg) 

1639 

1640 def _eval_rewrite_as_Pow(self, arg, **kwargs): 

1641 return self._rewrite_reciprocal("_eval_rewrite_as_Pow", arg) 

1642 

1643 def _eval_rewrite_as_sin(self, arg, **kwargs): 

1644 return self._rewrite_reciprocal("_eval_rewrite_as_sin", arg) 

1645 

1646 def _eval_rewrite_as_cos(self, arg, **kwargs): 

1647 return self._rewrite_reciprocal("_eval_rewrite_as_cos", arg) 

1648 

1649 def _eval_rewrite_as_tan(self, arg, **kwargs): 

1650 return self._rewrite_reciprocal("_eval_rewrite_as_tan", arg) 

1651 

1652 def _eval_rewrite_as_pow(self, arg, **kwargs): 

1653 return self._rewrite_reciprocal("_eval_rewrite_as_pow", arg) 

1654 

1655 def _eval_rewrite_as_sqrt(self, arg, **kwargs): 

1656 return self._rewrite_reciprocal("_eval_rewrite_as_sqrt", arg) 

1657 

1658 def _eval_conjugate(self): 

1659 return self.func(self.args[0].conjugate()) 

1660 

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

1662 return (1/self._reciprocal_of(self.args[0])).as_real_imag(deep, 

1663 **hints) 

1664 

1665 def _eval_expand_trig(self, **hints): 

1666 return self._calculate_reciprocal("_eval_expand_trig", **hints) 

1667 

1668 def _eval_is_extended_real(self): 

1669 return self._reciprocal_of(self.args[0])._eval_is_extended_real() 

1670 

1671 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

1672 return (1/self._reciprocal_of(self.args[0]))._eval_as_leading_term(x) 

1673 

1674 def _eval_is_finite(self): 

1675 return (1/self._reciprocal_of(self.args[0])).is_finite 

1676 

1677 def _eval_nseries(self, x, n, logx, cdir=0): 

1678 return (1/self._reciprocal_of(self.args[0]))._eval_nseries(x, n, logx) 

1679 

1680 

1681class sec(ReciprocalTrigonometricFunction): 

1682 """ 

1683 The secant function. 

1684 

1685 Returns the secant of x (measured in radians). 

1686 

1687 Explanation 

1688 =========== 

1689 

1690 See :class:`sin` for notes about automatic evaluation. 

1691 

1692 Examples 

1693 ======== 

1694 

1695 >>> from sympy import sec 

1696 >>> from sympy.abc import x 

1697 >>> sec(x**2).diff(x) 

1698 2*x*tan(x**2)*sec(x**2) 

1699 >>> sec(1).diff(x) 

1700 0 

1701 

1702 See Also 

1703 ======== 

1704 

1705 sin, csc, cos, tan, cot 

1706 asin, acsc, acos, asec, atan, acot, atan2 

1707 

1708 References 

1709 ========== 

1710 

1711 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

1712 .. [2] https://dlmf.nist.gov/4.14 

1713 .. [3] https://functions.wolfram.com/ElementaryFunctions/Sec 

1714 

1715 """ 

1716 

1717 _reciprocal_of = cos 

1718 _is_even = True 

1719 

1720 def period(self, symbol=None): 

1721 return self._period(symbol) 

1722 

1723 def _eval_rewrite_as_cot(self, arg, **kwargs): 

1724 cot_half_sq = cot(arg/2)**2 

1725 return (cot_half_sq + 1)/(cot_half_sq - 1) 

1726 

1727 def _eval_rewrite_as_cos(self, arg, **kwargs): 

1728 return (1/cos(arg)) 

1729 

1730 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

1731 return sin(arg)/(cos(arg)*sin(arg)) 

1732 

1733 def _eval_rewrite_as_sin(self, arg, **kwargs): 

1734 return (1/cos(arg).rewrite(sin)) 

1735 

1736 def _eval_rewrite_as_tan(self, arg, **kwargs): 

1737 return (1/cos(arg).rewrite(tan)) 

1738 

1739 def _eval_rewrite_as_csc(self, arg, **kwargs): 

1740 return csc(pi/2 - arg, evaluate=False) 

1741 

1742 def fdiff(self, argindex=1): 

1743 if argindex == 1: 

1744 return tan(self.args[0])*sec(self.args[0]) 

1745 else: 

1746 raise ArgumentIndexError(self, argindex) 

1747 

1748 def _eval_is_complex(self): 

1749 arg = self.args[0] 

1750 

1751 if arg.is_complex and (arg/pi - S.Half).is_integer is False: 

1752 return True 

1753 

1754 @staticmethod 

1755 @cacheit 

1756 def taylor_term(n, x, *previous_terms): 

1757 # Reference Formula: 

1758 # https://functions.wolfram.com/ElementaryFunctions/Sec/06/01/02/01/ 

1759 if n < 0 or n % 2 == 1: 

1760 return S.Zero 

1761 else: 

1762 x = sympify(x) 

1763 k = n//2 

1764 return S.NegativeOne**k*euler(2*k)/factorial(2*k)*x**(2*k) 

1765 

1766 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

1767 from sympy.calculus.accumulationbounds import AccumBounds 

1768 from sympy.functions.elementary.complexes import re 

1769 arg = self.args[0] 

1770 x0 = arg.subs(x, 0).cancel() 

1771 n = (x0 + pi/2)/pi 

1772 if n.is_integer: 

1773 lt = (arg - n*pi + pi/2).as_leading_term(x) 

1774 return (S.NegativeOne**n)/lt 

1775 if x0 is S.ComplexInfinity: 

1776 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

1777 if x0 in (S.Infinity, S.NegativeInfinity): 

1778 return AccumBounds(S.NegativeInfinity, S.Infinity) 

1779 return self.func(x0) if x0.is_finite else self 

1780 

1781 

1782class csc(ReciprocalTrigonometricFunction): 

1783 """ 

1784 The cosecant function. 

1785 

1786 Returns the cosecant of x (measured in radians). 

1787 

1788 Explanation 

1789 =========== 

1790 

1791 See :func:`sin` for notes about automatic evaluation. 

1792 

1793 Examples 

1794 ======== 

1795 

1796 >>> from sympy import csc 

1797 >>> from sympy.abc import x 

1798 >>> csc(x**2).diff(x) 

1799 -2*x*cot(x**2)*csc(x**2) 

1800 >>> csc(1).diff(x) 

1801 0 

1802 

1803 See Also 

1804 ======== 

1805 

1806 sin, cos, sec, tan, cot 

1807 asin, acsc, acos, asec, atan, acot, atan2 

1808 

1809 References 

1810 ========== 

1811 

1812 .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions 

1813 .. [2] https://dlmf.nist.gov/4.14 

1814 .. [3] https://functions.wolfram.com/ElementaryFunctions/Csc 

1815 

1816 """ 

1817 

1818 _reciprocal_of = sin 

1819 _is_odd = True 

1820 

1821 def period(self, symbol=None): 

1822 return self._period(symbol) 

1823 

1824 def _eval_rewrite_as_sin(self, arg, **kwargs): 

1825 return (1/sin(arg)) 

1826 

1827 def _eval_rewrite_as_sincos(self, arg, **kwargs): 

1828 return cos(arg)/(sin(arg)*cos(arg)) 

1829 

1830 def _eval_rewrite_as_cot(self, arg, **kwargs): 

1831 cot_half = cot(arg/2) 

1832 return (1 + cot_half**2)/(2*cot_half) 

1833 

1834 def _eval_rewrite_as_cos(self, arg, **kwargs): 

1835 return 1/sin(arg).rewrite(cos) 

1836 

1837 def _eval_rewrite_as_sec(self, arg, **kwargs): 

1838 return sec(pi/2 - arg, evaluate=False) 

1839 

1840 def _eval_rewrite_as_tan(self, arg, **kwargs): 

1841 return (1/sin(arg).rewrite(tan)) 

1842 

1843 def fdiff(self, argindex=1): 

1844 if argindex == 1: 

1845 return -cot(self.args[0])*csc(self.args[0]) 

1846 else: 

1847 raise ArgumentIndexError(self, argindex) 

1848 

1849 def _eval_is_complex(self): 

1850 arg = self.args[0] 

1851 if arg.is_real and (arg/pi).is_integer is False: 

1852 return True 

1853 

1854 @staticmethod 

1855 @cacheit 

1856 def taylor_term(n, x, *previous_terms): 

1857 if n == 0: 

1858 return 1/sympify(x) 

1859 elif n < 0 or n % 2 == 0: 

1860 return S.Zero 

1861 else: 

1862 x = sympify(x) 

1863 k = n//2 + 1 

1864 return (S.NegativeOne**(k - 1)*2*(2**(2*k - 1) - 1)* 

1865 bernoulli(2*k)*x**(2*k - 1)/factorial(2*k)) 

1866 

1867 def _eval_as_leading_term(self, x, logx=None, cdir=0): 

1868 from sympy.calculus.accumulationbounds import AccumBounds 

1869 from sympy.functions.elementary.complexes import re 

1870 arg = self.args[0] 

1871 x0 = arg.subs(x, 0).cancel() 

1872 n = x0/pi 

1873 if n.is_integer: 

1874 lt = (arg - n*pi).as_leading_term(x) 

1875 return (S.NegativeOne**n)/lt 

1876 if x0 is S.ComplexInfinity: 

1877 x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') 

1878 if x0 in (S.Infinity, S.NegativeInfinity): 

1879 return AccumBounds(S.NegativeInfinity, S.Infinity) 

1880 return self.func(x0) if x0.is_finite else self 

1881 

1882 

1883class sinc(Function): 

1884 r""" 

1885 Represents an unnormalized sinc function: 

1886 

1887 .. math:: 

1888 

1889 \operatorname{sinc}(x) = 

1890 \begin{cases} 

1891 \frac{\sin x}{x} & \qquad x \neq 0 \\ 

1892 1 & \qquad x = 0 

1893 \end{cases} 

1894 

1895 Examples 

1896 ======== 

1897 

1898 >>> from sympy import sinc, oo, jn 

1899 >>> from sympy.abc import x 

1900 >>> sinc(x) 

1901 sinc(x) 

1902 

1903 * Automated Evaluation 

1904 

1905 >>> sinc(0) 

1906 1 

1907 >>> sinc(oo) 

1908 0 

1909 

1910 * Differentiation 

1911 

1912 >>> sinc(x).diff() 

1913 cos(x)/x - sin(x)/x**2 

1914 

1915 * Series Expansion 

1916 

1917 >>> sinc(x).series() 

1918 1 - x**2/6 + x**4/120 + O(x**6) 

1919 

1920 * As zero'th order spherical Bessel Function 

1921 

1922 >>> sinc(x).rewrite(jn) 

1923 jn(0, x) 

1924 

1925 See also 

1926 ======== 

1927 

1928 sin 

1929 

1930 References 

1931 ========== 

1932 

1933 .. [1] https://en.wikipedia.org/wiki/Sinc_function 

1934 

1935 """ 

1936 _singularities = (S.ComplexInfinity,) 

1937 

1938 def fdiff(self, argindex=1): 

1939 x = self.args[0] 

1940 if argindex == 1: 

1941 # We would like to return the Piecewise here, but Piecewise.diff 

1942 # currently can't handle removable singularities, meaning things 

1943 # like sinc(x).diff(x, 2) give the wrong answer at x = 0. See 

1944 # https://github.com/sympy/sympy/issues/11402. 

1945 # 

1946 # return Piecewise(((x*cos(x) - sin(x))/x**2, Ne(x, S.Zero)), (S.Zero, S.true)) 

1947 return cos(x)/x - sin(x)/x**2 

1948 else: 

1949 raise ArgumentIndexError(self, argindex) 

1950 

1951 @classmethod 

1952 def eval(cls, arg): 

1953 if arg.is_zero: 

1954 return S.One 

1955 if arg.is_Number: 

1956 if arg in [S.Infinity, S.NegativeInfinity]: 

1957 return S.Zero 

1958 elif arg is S.NaN: 

1959 return S.NaN 

1960 

1961 if arg is S.ComplexInfinity: 

1962 return S.NaN 

1963 

1964 if arg.could_extract_minus_sign(): 

1965 return cls(-arg) 

1966 

1967 pi_coeff = _pi_coeff(arg) 

1968 if pi_coeff is not None: 

1969 if pi_coeff.is_integer: 

1970 if fuzzy_not(arg.is_zero): 

1971 return S.Zero 

1972 elif (2*pi_coeff).is_integer: 

1973 return S.NegativeOne**(pi_coeff - S.Half)/arg 

1974 

1975 def _eval_nseries(self, x, n, logx, cdir=0): 

1976 x = self.args[0] 

1977 return (sin(x)/x)._eval_nseries(x, n, logx) 

1978 

1979 def _eval_rewrite_as_jn(self, arg, **kwargs): 

1980 from sympy.functions.special.bessel import jn 

1981 return jn(0, arg) 

1982 

1983 def _eval_rewrite_as_sin(self, arg, **kwargs): 

1984 return Piecewise((sin(arg)/arg, Ne(arg, S.Zero)), (S.One, S.true)) 

1985 

1986 def _eval_is_zero(self): 

1987 if self.args[0].is_infinite: 

1988 return True 

1989 rest, pi_mult = _peeloff_pi(self.args[0]) 

1990 if rest.is_zero: 

1991 return fuzzy_and([pi_mult.is_integer, pi_mult.is_nonzero]) 

1992 if rest.is_Number and pi_mult.is_integer: 

1993 return False 

1994 

1995 def _eval_is_real(self): 

1996 if self.args[0].is_extended_real or self.args[0].is_imaginary: 

1997 return True 

1998 

1999 _eval_is_finite = _eval_is_real 

2000 

2001 

2002############################################################################### 

2003########################### TRIGONOMETRIC INVERSES ############################ 

2004############################################################################### 

2005 

2006 

2007class InverseTrigonometricFunction(Function): 

2008 """Base class for inverse trigonometric functions.""" 

2009 _singularities = (S.One, S.NegativeOne, S.Zero, S.ComplexInfinity) # type: tTuple[Expr, ...] 

2010 

2011 @staticmethod 

2012 @cacheit 

2013 def _asin_table(): 

2014 # Only keys with could_extract_minus_sign() == False 

2015 # are actually needed. 

2016 return { 

2017 sqrt(3)/2: pi/3, 

2018 sqrt(2)/2: pi/4, 

2019 1/sqrt(2): pi/4, 

2020 sqrt((5 - sqrt(5))/8): pi/5, 

2021 sqrt(2)*sqrt(5 - sqrt(5))/4: pi/5, 

2022 sqrt((5 + sqrt(5))/8): pi*Rational(2, 5), 

2023 sqrt(2)*sqrt(5 + sqrt(5))/4: pi*Rational(2, 5), 

2024 S.Half: pi/6, 

2025 sqrt(2 - sqrt(2))/2: pi/8, 

2026 sqrt(S.Half - sqrt(2)/4): pi/8, 

2027 sqrt(2 + sqrt(2))/2: pi*Rational(3, 8), 

2028 sqrt(S.Half + sqrt(2)/4): pi*Rational(3, 8), 

2029 (sqrt(5) - 1)/4: pi/10, 

2030 (1 - sqrt(5))/4: -pi/10, 

2031 (sqrt(5) + 1)/4: pi*Rational(3, 10), 

2032 sqrt(6)/4 - sqrt(2)/4: pi/12, 

2033 -sqrt(6)/4 + sqrt(2)/4: -pi/12, 

2034 (sqrt(3) - 1)/sqrt(8): pi/12, 

2035 (1 - sqrt(3))/sqrt(8): -pi/12, 

2036 sqrt(6)/4 + sqrt(2)/4: pi*Rational(5, 12), 

2037 (1 + sqrt(3))/sqrt(8): pi*Rational(5, 12) 

2038 } 

2039 

2040 

2041 @staticmethod 

2042 @cacheit 

2043 def _atan_table(): 

2044 # Only keys with could_extract_minus_sign() == False 

2045 # are actually needed. 

2046 return { 

2047 sqrt(3)/3: pi/6, 

2048 1/sqrt(3): pi/6, 

2049 sqrt(3): pi/3, 

2050 sqrt(2) - 1: pi/8, 

2051 1 - sqrt(2): -pi/8, 

2052 1 + sqrt(2): pi*Rational(3, 8), 

2053 sqrt(5 - 2*sqrt(5)): pi/5, 

2054 sqrt(5 + 2*sqrt(5)): pi*Rational(2, 5), 

2055 sqrt(1 - 2*sqrt(5)/5): pi/10, 

2056 sqrt(1 + 2*sqrt(5)/5): pi*Rational(3, 10), 

2057 2 - sqrt(3): pi/12, 

2058 -2 + sqrt(3): -pi/12, 

2059 2 + sqrt(3): pi*Rational(5, 12) 

2060 } 

2061 

2062 @staticmethod 

2063 @cacheit 

2064 def _acsc_table(): 

2065 # Keys for which could_extract_minus_sign() 

2066 # will obviously return True are omitted. 

2067 return { 

2068 2*sqrt(3)/3: pi/3, 

2069 sqrt(2): pi/4, 

2070 sqrt(2 + 2*sqrt(5)/5): pi/5, 

2071 1/sqrt(Rational(5, 8) - sqrt(5)/8): pi/5, 

2072 sqrt(2 - 2*sqrt(5)/5): pi*Rational(2, 5), 

2073 1/sqrt(Rational(5, 8) + sqrt(5)/8): pi*Rational(2, 5), 

2074 2: pi/6, 

2075 sqrt(4 + 2*sqrt(2)): pi/8, 

2076 2/sqrt(2 - sqrt(2)): pi/8, 

2077 sqrt(4 - 2*sqrt(2)): pi*Rational(3, 8), 

2078 2/sqrt(2 + sqrt(2)): pi*Rational(3, 8), 

2079 1 + sqrt(5): pi/10, 

2080 sqrt(5) - 1: pi*Rational(3, 10), 

2081 -(sqrt(5) - 1): pi*Rational(-3, 10), 

2082 sqrt(6) + sqrt(2): pi/12, 

2083 sqrt(6) - sqrt(2): pi*Rational(5, 12), 

2084 -(sqrt(6) - sqrt(2)): pi*Rational(-5, 12) 

2085 } 

2086 

2087 

2088class asin(InverseTrigonometricFunction): 

2089 r""" 

2090 The inverse sine function. 

2091 

2092 Returns the arcsine of x in radians. 

2093 

2094 Explanation 

2095 =========== 

2096 

2097 ``asin(x)`` will evaluate automatically in the cases 

2098 $x \in \{\infty, -\infty, 0, 1, -1\}$ and for some instances when the 

2099 result is a rational multiple of $\pi$ (see the ``eval`` class method). 

2100 

2101 A purely imaginary argument will lead to an asinh expression. 

2102 

2103 Examples 

2104 ======== 

2105 

2106 >>> from sympy import asin, oo 

2107 >>> asin(1) 

2108 pi/2 

2109 >>> asin(-1) 

2110 -pi/2 

2111 >>> asin(-oo) 

2112 oo*I 

2113 >>> asin(oo) 

2114 -oo*I 

2115 

2116 See Also 

2117 ======== 

2118 

2119 sin, csc, cos, sec, tan, cot 

2120 acsc, acos, asec, atan, acot, atan2 

2121 

2122 References 

2123 ========== 

2124 

2125 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

2126 .. [2] https://dlmf.nist.gov/4.23 

2127 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcSin 

2128 

2129 """ 

2130 

2131 def fdiff(self, argindex=1): 

2132 if argindex == 1: 

2133 return 1/sqrt(1 - self.args[0]**2) 

2134 else: 

2135 raise ArgumentIndexError(self, argindex) 

2136 

2137 def _eval_is_rational(self): 

2138 s = self.func(*self.args) 

2139 if s.func == self.func: 

2140 if s.args[0].is_rational: 

2141 return False 

2142 else: 

2143 return s.is_rational 

2144 

2145 def _eval_is_positive(self): 

2146 return self._eval_is_extended_real() and self.args[0].is_positive 

2147 

2148 def _eval_is_negative(self): 

2149 return self._eval_is_extended_real() and self.args[0].is_negative 

2150 

2151 @classmethod 

2152 def eval(cls, arg): 

2153 if arg.is_Number: 

2154 if arg is S.NaN: 

2155 return S.NaN 

2156 elif arg is S.Infinity: 

2157 return S.NegativeInfinity*S.ImaginaryUnit 

2158 elif arg is S.NegativeInfinity: 

2159 return S.Infinity*S.ImaginaryUnit 

2160 elif arg.is_zero: 

2161 return S.Zero 

2162 elif arg is S.One: 

2163 return pi/2 

2164 elif arg is S.NegativeOne: 

2165 return -pi/2 

2166 

2167 if arg is S.ComplexInfinity: 

2168 return S.ComplexInfinity 

2169 

2170 if arg.could_extract_minus_sign(): 

2171 return -cls(-arg) 

2172 

2173 if arg.is_number: 

2174 asin_table = cls._asin_table() 

2175 if arg in asin_table: 

2176 return asin_table[arg] 

2177 

2178 i_coeff = _imaginary_unit_as_coefficient(arg) 

2179 if i_coeff is not None: 

2180 from sympy.functions.elementary.hyperbolic import asinh 

2181 return S.ImaginaryUnit*asinh(i_coeff) 

2182 

2183 if arg.is_zero: 

2184 return S.Zero 

2185 

2186 if isinstance(arg, sin): 

2187 ang = arg.args[0] 

2188 if ang.is_comparable: 

2189 ang %= 2*pi # restrict to [0,2*pi) 

2190 if ang > pi: # restrict to (-pi,pi] 

2191 ang = pi - ang 

2192 

2193 # restrict to [-pi/2,pi/2] 

2194 if ang > pi/2: 

2195 ang = pi - ang 

2196 if ang < -pi/2: 

2197 ang = -pi - ang 

2198 

2199 return ang 

2200 

2201 if isinstance(arg, cos): # acos(x) + asin(x) = pi/2 

2202 ang = arg.args[0] 

2203 if ang.is_comparable: 

2204 return pi/2 - acos(arg) 

2205 

2206 @staticmethod 

2207 @cacheit 

2208 def taylor_term(n, x, *previous_terms): 

2209 if n < 0 or n % 2 == 0: 

2210 return S.Zero 

2211 else: 

2212 x = sympify(x) 

2213 if len(previous_terms) >= 2 and n > 2: 

2214 p = previous_terms[-2] 

2215 return p*(n - 2)**2/(n*(n - 1))*x**2 

2216 else: 

2217 k = (n - 1) // 2 

2218 R = RisingFactorial(S.Half, k) 

2219 F = factorial(k) 

2220 return R/F*x**n/n 

2221 

2222 def _eval_as_leading_term(self, x, logx=None, cdir=0): # asin 

2223 arg = self.args[0] 

2224 x0 = arg.subs(x, 0).cancel() 

2225 if x0.is_zero: 

2226 return arg.as_leading_term(x) 

2227 # Handling branch points 

2228 if x0 in (-S.One, S.One, S.ComplexInfinity): 

2229 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2230 # Handling points lying on branch cuts (-oo, -1) U (1, oo) 

2231 if (1 - x0**2).is_negative: 

2232 ndir = arg.dir(x, cdir if cdir else 1) 

2233 if im(ndir).is_negative: 

2234 if x0.is_negative: 

2235 return -pi - self.func(x0) 

2236 elif im(ndir).is_positive: 

2237 if x0.is_positive: 

2238 return pi - self.func(x0) 

2239 else: 

2240 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2241 return self.func(x0) 

2242 

2243 def _eval_nseries(self, x, n, logx, cdir=0): # asin 

2244 from sympy.series.order import O 

2245 arg0 = self.args[0].subs(x, 0) 

2246 # Handling branch points 

2247 if arg0 is S.One: 

2248 t = Dummy('t', positive=True) 

2249 ser = asin(S.One - t**2).rewrite(log).nseries(t, 0, 2*n) 

2250 arg1 = S.One - self.args[0] 

2251 f = arg1.as_leading_term(x) 

2252 g = (arg1 - f)/ f 

2253 if not g.is_meromorphic(x, 0): # cannot be expanded 

2254 return O(1) if n == 0 else pi/2 + O(sqrt(x)) 

2255 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

2256 res = (res1.removeO()*sqrt(f)).expand() 

2257 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

2258 

2259 if arg0 is S.NegativeOne: 

2260 t = Dummy('t', positive=True) 

2261 ser = asin(S.NegativeOne + t**2).rewrite(log).nseries(t, 0, 2*n) 

2262 arg1 = S.One + self.args[0] 

2263 f = arg1.as_leading_term(x) 

2264 g = (arg1 - f)/ f 

2265 if not g.is_meromorphic(x, 0): # cannot be expanded 

2266 return O(1) if n == 0 else -pi/2 + O(sqrt(x)) 

2267 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

2268 res = (res1.removeO()*sqrt(f)).expand() 

2269 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

2270 

2271 res = Function._eval_nseries(self, x, n=n, logx=logx) 

2272 if arg0 is S.ComplexInfinity: 

2273 return res 

2274 # Handling points lying on branch cuts (-oo, -1) U (1, oo) 

2275 if (1 - arg0**2).is_negative: 

2276 ndir = self.args[0].dir(x, cdir if cdir else 1) 

2277 if im(ndir).is_negative: 

2278 if arg0.is_negative: 

2279 return -pi - res 

2280 elif im(ndir).is_positive: 

2281 if arg0.is_positive: 

2282 return pi - res 

2283 else: 

2284 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2285 return res 

2286 

2287 def _eval_rewrite_as_acos(self, x, **kwargs): 

2288 return pi/2 - acos(x) 

2289 

2290 def _eval_rewrite_as_atan(self, x, **kwargs): 

2291 return 2*atan(x/(1 + sqrt(1 - x**2))) 

2292 

2293 def _eval_rewrite_as_log(self, x, **kwargs): 

2294 return -S.ImaginaryUnit*log(S.ImaginaryUnit*x + sqrt(1 - x**2)) 

2295 

2296 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

2297 

2298 def _eval_rewrite_as_acot(self, arg, **kwargs): 

2299 return 2*acot((1 + sqrt(1 - arg**2))/arg) 

2300 

2301 def _eval_rewrite_as_asec(self, arg, **kwargs): 

2302 return pi/2 - asec(1/arg) 

2303 

2304 def _eval_rewrite_as_acsc(self, arg, **kwargs): 

2305 return acsc(1/arg) 

2306 

2307 def _eval_is_extended_real(self): 

2308 x = self.args[0] 

2309 return x.is_extended_real and (1 - abs(x)).is_nonnegative 

2310 

2311 def inverse(self, argindex=1): 

2312 """ 

2313 Returns the inverse of this function. 

2314 """ 

2315 return sin 

2316 

2317 

2318class acos(InverseTrigonometricFunction): 

2319 r""" 

2320 The inverse cosine function. 

2321 

2322 Explanation 

2323 =========== 

2324 

2325 Returns the arc cosine of x (measured in radians). 

2326 

2327 ``acos(x)`` will evaluate automatically in the cases 

2328 $x \in \{\infty, -\infty, 0, 1, -1\}$ and for some instances when 

2329 the result is a rational multiple of $\pi$ (see the eval class method). 

2330 

2331 ``acos(zoo)`` evaluates to ``zoo`` 

2332 (see note in :class:`sympy.functions.elementary.trigonometric.asec`) 

2333 

2334 A purely imaginary argument will be rewritten to asinh. 

2335 

2336 Examples 

2337 ======== 

2338 

2339 >>> from sympy import acos, oo 

2340 >>> acos(1) 

2341 0 

2342 >>> acos(0) 

2343 pi/2 

2344 >>> acos(oo) 

2345 oo*I 

2346 

2347 See Also 

2348 ======== 

2349 

2350 sin, csc, cos, sec, tan, cot 

2351 asin, acsc, asec, atan, acot, atan2 

2352 

2353 References 

2354 ========== 

2355 

2356 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

2357 .. [2] https://dlmf.nist.gov/4.23 

2358 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcCos 

2359 

2360 """ 

2361 

2362 def fdiff(self, argindex=1): 

2363 if argindex == 1: 

2364 return -1/sqrt(1 - self.args[0]**2) 

2365 else: 

2366 raise ArgumentIndexError(self, argindex) 

2367 

2368 def _eval_is_rational(self): 

2369 s = self.func(*self.args) 

2370 if s.func == self.func: 

2371 if s.args[0].is_rational: 

2372 return False 

2373 else: 

2374 return s.is_rational 

2375 

2376 @classmethod 

2377 def eval(cls, arg): 

2378 if arg.is_Number: 

2379 if arg is S.NaN: 

2380 return S.NaN 

2381 elif arg is S.Infinity: 

2382 return S.Infinity*S.ImaginaryUnit 

2383 elif arg is S.NegativeInfinity: 

2384 return S.NegativeInfinity*S.ImaginaryUnit 

2385 elif arg.is_zero: 

2386 return pi/2 

2387 elif arg is S.One: 

2388 return S.Zero 

2389 elif arg is S.NegativeOne: 

2390 return pi 

2391 

2392 if arg is S.ComplexInfinity: 

2393 return S.ComplexInfinity 

2394 

2395 if arg.is_number: 

2396 asin_table = cls._asin_table() 

2397 if arg in asin_table: 

2398 return pi/2 - asin_table[arg] 

2399 elif -arg in asin_table: 

2400 return pi/2 + asin_table[-arg] 

2401 

2402 i_coeff = _imaginary_unit_as_coefficient(arg) 

2403 if i_coeff is not None: 

2404 return pi/2 - asin(arg) 

2405 

2406 if isinstance(arg, cos): 

2407 ang = arg.args[0] 

2408 if ang.is_comparable: 

2409 ang %= 2*pi # restrict to [0,2*pi) 

2410 if ang > pi: # restrict to [0,pi] 

2411 ang = 2*pi - ang 

2412 

2413 return ang 

2414 

2415 if isinstance(arg, sin): # acos(x) + asin(x) = pi/2 

2416 ang = arg.args[0] 

2417 if ang.is_comparable: 

2418 return pi/2 - asin(arg) 

2419 

2420 @staticmethod 

2421 @cacheit 

2422 def taylor_term(n, x, *previous_terms): 

2423 if n == 0: 

2424 return pi/2 

2425 elif n < 0 or n % 2 == 0: 

2426 return S.Zero 

2427 else: 

2428 x = sympify(x) 

2429 if len(previous_terms) >= 2 and n > 2: 

2430 p = previous_terms[-2] 

2431 return p*(n - 2)**2/(n*(n - 1))*x**2 

2432 else: 

2433 k = (n - 1) // 2 

2434 R = RisingFactorial(S.Half, k) 

2435 F = factorial(k) 

2436 return -R/F*x**n/n 

2437 

2438 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acos 

2439 arg = self.args[0] 

2440 x0 = arg.subs(x, 0).cancel() 

2441 # Handling branch points 

2442 if x0 == 1: 

2443 return sqrt(2)*sqrt((S.One - arg).as_leading_term(x)) 

2444 if x0 in (-S.One, S.ComplexInfinity): 

2445 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir) 

2446 # Handling points lying on branch cuts (-oo, -1) U (1, oo) 

2447 if (1 - x0**2).is_negative: 

2448 ndir = arg.dir(x, cdir if cdir else 1) 

2449 if im(ndir).is_negative: 

2450 if x0.is_negative: 

2451 return 2*pi - self.func(x0) 

2452 elif im(ndir).is_positive: 

2453 if x0.is_positive: 

2454 return -self.func(x0) 

2455 else: 

2456 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2457 return self.func(x0) 

2458 

2459 def _eval_is_extended_real(self): 

2460 x = self.args[0] 

2461 return x.is_extended_real and (1 - abs(x)).is_nonnegative 

2462 

2463 def _eval_is_nonnegative(self): 

2464 return self._eval_is_extended_real() 

2465 

2466 def _eval_nseries(self, x, n, logx, cdir=0): # acos 

2467 from sympy.series.order import O 

2468 arg0 = self.args[0].subs(x, 0) 

2469 # Handling branch points 

2470 if arg0 is S.One: 

2471 t = Dummy('t', positive=True) 

2472 ser = acos(S.One - t**2).rewrite(log).nseries(t, 0, 2*n) 

2473 arg1 = S.One - self.args[0] 

2474 f = arg1.as_leading_term(x) 

2475 g = (arg1 - f)/ f 

2476 if not g.is_meromorphic(x, 0): # cannot be expanded 

2477 return O(1) if n == 0 else O(sqrt(x)) 

2478 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

2479 res = (res1.removeO()*sqrt(f)).expand() 

2480 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

2481 

2482 if arg0 is S.NegativeOne: 

2483 t = Dummy('t', positive=True) 

2484 ser = acos(S.NegativeOne + t**2).rewrite(log).nseries(t, 0, 2*n) 

2485 arg1 = S.One + self.args[0] 

2486 f = arg1.as_leading_term(x) 

2487 g = (arg1 - f)/ f 

2488 if not g.is_meromorphic(x, 0): # cannot be expanded 

2489 return O(1) if n == 0 else pi + O(sqrt(x)) 

2490 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

2491 res = (res1.removeO()*sqrt(f)).expand() 

2492 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

2493 

2494 res = Function._eval_nseries(self, x, n=n, logx=logx) 

2495 if arg0 is S.ComplexInfinity: 

2496 return res 

2497 # Handling points lying on branch cuts (-oo, -1) U (1, oo) 

2498 if (1 - arg0**2).is_negative: 

2499 ndir = self.args[0].dir(x, cdir if cdir else 1) 

2500 if im(ndir).is_negative: 

2501 if arg0.is_negative: 

2502 return 2*pi - res 

2503 elif im(ndir).is_positive: 

2504 if arg0.is_positive: 

2505 return -res 

2506 else: 

2507 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2508 return res 

2509 

2510 def _eval_rewrite_as_log(self, x, **kwargs): 

2511 return pi/2 + S.ImaginaryUnit*\ 

2512 log(S.ImaginaryUnit*x + sqrt(1 - x**2)) 

2513 

2514 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

2515 

2516 def _eval_rewrite_as_asin(self, x, **kwargs): 

2517 return pi/2 - asin(x) 

2518 

2519 def _eval_rewrite_as_atan(self, x, **kwargs): 

2520 return atan(sqrt(1 - x**2)/x) + (pi/2)*(1 - x*sqrt(1/x**2)) 

2521 

2522 def inverse(self, argindex=1): 

2523 """ 

2524 Returns the inverse of this function. 

2525 """ 

2526 return cos 

2527 

2528 def _eval_rewrite_as_acot(self, arg, **kwargs): 

2529 return pi/2 - 2*acot((1 + sqrt(1 - arg**2))/arg) 

2530 

2531 def _eval_rewrite_as_asec(self, arg, **kwargs): 

2532 return asec(1/arg) 

2533 

2534 def _eval_rewrite_as_acsc(self, arg, **kwargs): 

2535 return pi/2 - acsc(1/arg) 

2536 

2537 def _eval_conjugate(self): 

2538 z = self.args[0] 

2539 r = self.func(self.args[0].conjugate()) 

2540 if z.is_extended_real is False: 

2541 return r 

2542 elif z.is_extended_real and (z + 1).is_nonnegative and (z - 1).is_nonpositive: 

2543 return r 

2544 

2545 

2546class atan(InverseTrigonometricFunction): 

2547 r""" 

2548 The inverse tangent function. 

2549 

2550 Returns the arc tangent of x (measured in radians). 

2551 

2552 Explanation 

2553 =========== 

2554 

2555 ``atan(x)`` will evaluate automatically in the cases 

2556 $x \in \{\infty, -\infty, 0, 1, -1\}$ and for some instances when the 

2557 result is a rational multiple of $\pi$ (see the eval class method). 

2558 

2559 Examples 

2560 ======== 

2561 

2562 >>> from sympy import atan, oo 

2563 >>> atan(0) 

2564 0 

2565 >>> atan(1) 

2566 pi/4 

2567 >>> atan(oo) 

2568 pi/2 

2569 

2570 See Also 

2571 ======== 

2572 

2573 sin, csc, cos, sec, tan, cot 

2574 asin, acsc, acos, asec, acot, atan2 

2575 

2576 References 

2577 ========== 

2578 

2579 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

2580 .. [2] https://dlmf.nist.gov/4.23 

2581 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcTan 

2582 

2583 """ 

2584 

2585 args: tTuple[Expr] 

2586 

2587 _singularities = (S.ImaginaryUnit, -S.ImaginaryUnit) 

2588 

2589 def fdiff(self, argindex=1): 

2590 if argindex == 1: 

2591 return 1/(1 + self.args[0]**2) 

2592 else: 

2593 raise ArgumentIndexError(self, argindex) 

2594 

2595 def _eval_is_rational(self): 

2596 s = self.func(*self.args) 

2597 if s.func == self.func: 

2598 if s.args[0].is_rational: 

2599 return False 

2600 else: 

2601 return s.is_rational 

2602 

2603 def _eval_is_positive(self): 

2604 return self.args[0].is_extended_positive 

2605 

2606 def _eval_is_nonnegative(self): 

2607 return self.args[0].is_extended_nonnegative 

2608 

2609 def _eval_is_zero(self): 

2610 return self.args[0].is_zero 

2611 

2612 def _eval_is_real(self): 

2613 return self.args[0].is_extended_real 

2614 

2615 @classmethod 

2616 def eval(cls, arg): 

2617 if arg.is_Number: 

2618 if arg is S.NaN: 

2619 return S.NaN 

2620 elif arg is S.Infinity: 

2621 return pi/2 

2622 elif arg is S.NegativeInfinity: 

2623 return -pi/2 

2624 elif arg.is_zero: 

2625 return S.Zero 

2626 elif arg is S.One: 

2627 return pi/4 

2628 elif arg is S.NegativeOne: 

2629 return -pi/4 

2630 

2631 if arg is S.ComplexInfinity: 

2632 from sympy.calculus.accumulationbounds import AccumBounds 

2633 return AccumBounds(-pi/2, pi/2) 

2634 

2635 if arg.could_extract_minus_sign(): 

2636 return -cls(-arg) 

2637 

2638 if arg.is_number: 

2639 atan_table = cls._atan_table() 

2640 if arg in atan_table: 

2641 return atan_table[arg] 

2642 

2643 i_coeff = _imaginary_unit_as_coefficient(arg) 

2644 if i_coeff is not None: 

2645 from sympy.functions.elementary.hyperbolic import atanh 

2646 return S.ImaginaryUnit*atanh(i_coeff) 

2647 

2648 if arg.is_zero: 

2649 return S.Zero 

2650 

2651 if isinstance(arg, tan): 

2652 ang = arg.args[0] 

2653 if ang.is_comparable: 

2654 ang %= pi # restrict to [0,pi) 

2655 if ang > pi/2: # restrict to [-pi/2,pi/2] 

2656 ang -= pi 

2657 

2658 return ang 

2659 

2660 if isinstance(arg, cot): # atan(x) + acot(x) = pi/2 

2661 ang = arg.args[0] 

2662 if ang.is_comparable: 

2663 ang = pi/2 - acot(arg) 

2664 if ang > pi/2: # restrict to [-pi/2,pi/2] 

2665 ang -= pi 

2666 return ang 

2667 

2668 @staticmethod 

2669 @cacheit 

2670 def taylor_term(n, x, *previous_terms): 

2671 if n < 0 or n % 2 == 0: 

2672 return S.Zero 

2673 else: 

2674 x = sympify(x) 

2675 return S.NegativeOne**((n - 1)//2)*x**n/n 

2676 

2677 def _eval_as_leading_term(self, x, logx=None, cdir=0): # atan 

2678 arg = self.args[0] 

2679 x0 = arg.subs(x, 0).cancel() 

2680 if x0.is_zero: 

2681 return arg.as_leading_term(x) 

2682 # Handling branch points 

2683 if x0 in (-S.ImaginaryUnit, S.ImaginaryUnit, S.ComplexInfinity): 

2684 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2685 # Handling points lying on branch cuts (-I*oo, -I) U (I, I*oo) 

2686 if (1 + x0**2).is_negative: 

2687 ndir = arg.dir(x, cdir if cdir else 1) 

2688 if re(ndir).is_negative: 

2689 if im(x0).is_positive: 

2690 return self.func(x0) - pi 

2691 elif re(ndir).is_positive: 

2692 if im(x0).is_negative: 

2693 return self.func(x0) + pi 

2694 else: 

2695 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2696 return self.func(x0) 

2697 

2698 def _eval_nseries(self, x, n, logx, cdir=0): # atan 

2699 arg0 = self.args[0].subs(x, 0) 

2700 

2701 # Handling branch points 

2702 if arg0 in (S.ImaginaryUnit, S.NegativeOne*S.ImaginaryUnit): 

2703 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2704 

2705 res = Function._eval_nseries(self, x, n=n, logx=logx) 

2706 ndir = self.args[0].dir(x, cdir if cdir else 1) 

2707 if arg0 is S.ComplexInfinity: 

2708 if re(ndir) > 0: 

2709 return res - pi 

2710 return res 

2711 # Handling points lying on branch cuts (-I*oo, -I) U (I, I*oo) 

2712 if (1 + arg0**2).is_negative: 

2713 if re(ndir).is_negative: 

2714 if im(arg0).is_positive: 

2715 return res - pi 

2716 elif re(ndir).is_positive: 

2717 if im(arg0).is_negative: 

2718 return res + pi 

2719 else: 

2720 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2721 return res 

2722 

2723 def _eval_rewrite_as_log(self, x, **kwargs): 

2724 return S.ImaginaryUnit/2*(log(S.One - S.ImaginaryUnit*x) 

2725 - log(S.One + S.ImaginaryUnit*x)) 

2726 

2727 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

2728 

2729 def _eval_aseries(self, n, args0, x, logx): 

2730 if args0[0] is S.Infinity: 

2731 return (pi/2 - atan(1/self.args[0]))._eval_nseries(x, n, logx) 

2732 elif args0[0] is S.NegativeInfinity: 

2733 return (-pi/2 - atan(1/self.args[0]))._eval_nseries(x, n, logx) 

2734 else: 

2735 return super()._eval_aseries(n, args0, x, logx) 

2736 

2737 def inverse(self, argindex=1): 

2738 """ 

2739 Returns the inverse of this function. 

2740 """ 

2741 return tan 

2742 

2743 def _eval_rewrite_as_asin(self, arg, **kwargs): 

2744 return sqrt(arg**2)/arg*(pi/2 - asin(1/sqrt(1 + arg**2))) 

2745 

2746 def _eval_rewrite_as_acos(self, arg, **kwargs): 

2747 return sqrt(arg**2)/arg*acos(1/sqrt(1 + arg**2)) 

2748 

2749 def _eval_rewrite_as_acot(self, arg, **kwargs): 

2750 return acot(1/arg) 

2751 

2752 def _eval_rewrite_as_asec(self, arg, **kwargs): 

2753 return sqrt(arg**2)/arg*asec(sqrt(1 + arg**2)) 

2754 

2755 def _eval_rewrite_as_acsc(self, arg, **kwargs): 

2756 return sqrt(arg**2)/arg*(pi/2 - acsc(sqrt(1 + arg**2))) 

2757 

2758 

2759class acot(InverseTrigonometricFunction): 

2760 r""" 

2761 The inverse cotangent function. 

2762 

2763 Returns the arc cotangent of x (measured in radians). 

2764 

2765 Explanation 

2766 =========== 

2767 

2768 ``acot(x)`` will evaluate automatically in the cases 

2769 $x \in \{\infty, -\infty, \tilde{\infty}, 0, 1, -1\}$ 

2770 and for some instances when the result is a rational multiple of $\pi$ 

2771 (see the eval class method). 

2772 

2773 A purely imaginary argument will lead to an ``acoth`` expression. 

2774 

2775 ``acot(x)`` has a branch cut along $(-i, i)$, hence it is discontinuous 

2776 at 0. Its range for real $x$ is $(-\frac{\pi}{2}, \frac{\pi}{2}]$. 

2777 

2778 Examples 

2779 ======== 

2780 

2781 >>> from sympy import acot, sqrt 

2782 >>> acot(0) 

2783 pi/2 

2784 >>> acot(1) 

2785 pi/4 

2786 >>> acot(sqrt(3) - 2) 

2787 -5*pi/12 

2788 

2789 See Also 

2790 ======== 

2791 

2792 sin, csc, cos, sec, tan, cot 

2793 asin, acsc, acos, asec, atan, atan2 

2794 

2795 References 

2796 ========== 

2797 

2798 .. [1] https://dlmf.nist.gov/4.23 

2799 .. [2] https://functions.wolfram.com/ElementaryFunctions/ArcCot 

2800 

2801 """ 

2802 _singularities = (S.ImaginaryUnit, -S.ImaginaryUnit) 

2803 

2804 def fdiff(self, argindex=1): 

2805 if argindex == 1: 

2806 return -1/(1 + self.args[0]**2) 

2807 else: 

2808 raise ArgumentIndexError(self, argindex) 

2809 

2810 def _eval_is_rational(self): 

2811 s = self.func(*self.args) 

2812 if s.func == self.func: 

2813 if s.args[0].is_rational: 

2814 return False 

2815 else: 

2816 return s.is_rational 

2817 

2818 def _eval_is_positive(self): 

2819 return self.args[0].is_nonnegative 

2820 

2821 def _eval_is_negative(self): 

2822 return self.args[0].is_negative 

2823 

2824 def _eval_is_extended_real(self): 

2825 return self.args[0].is_extended_real 

2826 

2827 @classmethod 

2828 def eval(cls, arg): 

2829 if arg.is_Number: 

2830 if arg is S.NaN: 

2831 return S.NaN 

2832 elif arg is S.Infinity: 

2833 return S.Zero 

2834 elif arg is S.NegativeInfinity: 

2835 return S.Zero 

2836 elif arg.is_zero: 

2837 return pi/ 2 

2838 elif arg is S.One: 

2839 return pi/4 

2840 elif arg is S.NegativeOne: 

2841 return -pi/4 

2842 

2843 if arg is S.ComplexInfinity: 

2844 return S.Zero 

2845 

2846 if arg.could_extract_minus_sign(): 

2847 return -cls(-arg) 

2848 

2849 if arg.is_number: 

2850 atan_table = cls._atan_table() 

2851 if arg in atan_table: 

2852 ang = pi/2 - atan_table[arg] 

2853 if ang > pi/2: # restrict to (-pi/2,pi/2] 

2854 ang -= pi 

2855 return ang 

2856 

2857 i_coeff = _imaginary_unit_as_coefficient(arg) 

2858 if i_coeff is not None: 

2859 from sympy.functions.elementary.hyperbolic import acoth 

2860 return -S.ImaginaryUnit*acoth(i_coeff) 

2861 

2862 if arg.is_zero: 

2863 return pi*S.Half 

2864 

2865 if isinstance(arg, cot): 

2866 ang = arg.args[0] 

2867 if ang.is_comparable: 

2868 ang %= pi # restrict to [0,pi) 

2869 if ang > pi/2: # restrict to (-pi/2,pi/2] 

2870 ang -= pi; 

2871 return ang 

2872 

2873 if isinstance(arg, tan): # atan(x) + acot(x) = pi/2 

2874 ang = arg.args[0] 

2875 if ang.is_comparable: 

2876 ang = pi/2 - atan(arg) 

2877 if ang > pi/2: # restrict to (-pi/2,pi/2] 

2878 ang -= pi 

2879 return ang 

2880 

2881 @staticmethod 

2882 @cacheit 

2883 def taylor_term(n, x, *previous_terms): 

2884 if n == 0: 

2885 return pi/2 # FIX THIS 

2886 elif n < 0 or n % 2 == 0: 

2887 return S.Zero 

2888 else: 

2889 x = sympify(x) 

2890 return S.NegativeOne**((n + 1)//2)*x**n/n 

2891 

2892 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acot 

2893 arg = self.args[0] 

2894 x0 = arg.subs(x, 0).cancel() 

2895 if x0 is S.ComplexInfinity: 

2896 return (1/arg).as_leading_term(x) 

2897 # Handling branch points 

2898 if x0 in (-S.ImaginaryUnit, S.ImaginaryUnit, S.Zero): 

2899 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2900 # Handling points lying on branch cuts [-I, I] 

2901 if x0.is_imaginary and (1 + x0**2).is_positive: 

2902 ndir = arg.dir(x, cdir if cdir else 1) 

2903 if re(ndir).is_positive: 

2904 if im(x0).is_positive: 

2905 return self.func(x0) + pi 

2906 elif re(ndir).is_negative: 

2907 if im(x0).is_negative: 

2908 return self.func(x0) - pi 

2909 else: 

2910 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

2911 return self.func(x0) 

2912 

2913 def _eval_nseries(self, x, n, logx, cdir=0): # acot 

2914 arg0 = self.args[0].subs(x, 0) 

2915 

2916 # Handling branch points 

2917 if arg0 in (S.ImaginaryUnit, S.NegativeOne*S.ImaginaryUnit): 

2918 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2919 

2920 res = Function._eval_nseries(self, x, n=n, logx=logx) 

2921 if arg0 is S.ComplexInfinity: 

2922 return res 

2923 ndir = self.args[0].dir(x, cdir if cdir else 1) 

2924 if arg0.is_zero: 

2925 if re(ndir) < 0: 

2926 return res - pi 

2927 return res 

2928 # Handling points lying on branch cuts [-I, I] 

2929 if arg0.is_imaginary and (1 + arg0**2).is_positive: 

2930 if re(ndir).is_positive: 

2931 if im(arg0).is_positive: 

2932 return res + pi 

2933 elif re(ndir).is_negative: 

2934 if im(arg0).is_negative: 

2935 return res - pi 

2936 else: 

2937 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

2938 return res 

2939 

2940 def _eval_aseries(self, n, args0, x, logx): 

2941 if args0[0] is S.Infinity: 

2942 return (pi/2 - acot(1/self.args[0]))._eval_nseries(x, n, logx) 

2943 elif args0[0] is S.NegativeInfinity: 

2944 return (pi*Rational(3, 2) - acot(1/self.args[0]))._eval_nseries(x, n, logx) 

2945 else: 

2946 return super(atan, self)._eval_aseries(n, args0, x, logx) 

2947 

2948 def _eval_rewrite_as_log(self, x, **kwargs): 

2949 return S.ImaginaryUnit/2*(log(1 - S.ImaginaryUnit/x) 

2950 - log(1 + S.ImaginaryUnit/x)) 

2951 

2952 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

2953 

2954 def inverse(self, argindex=1): 

2955 """ 

2956 Returns the inverse of this function. 

2957 """ 

2958 return cot 

2959 

2960 def _eval_rewrite_as_asin(self, arg, **kwargs): 

2961 return (arg*sqrt(1/arg**2)* 

2962 (pi/2 - asin(sqrt(-arg**2)/sqrt(-arg**2 - 1)))) 

2963 

2964 def _eval_rewrite_as_acos(self, arg, **kwargs): 

2965 return arg*sqrt(1/arg**2)*acos(sqrt(-arg**2)/sqrt(-arg**2 - 1)) 

2966 

2967 def _eval_rewrite_as_atan(self, arg, **kwargs): 

2968 return atan(1/arg) 

2969 

2970 def _eval_rewrite_as_asec(self, arg, **kwargs): 

2971 return arg*sqrt(1/arg**2)*asec(sqrt((1 + arg**2)/arg**2)) 

2972 

2973 def _eval_rewrite_as_acsc(self, arg, **kwargs): 

2974 return arg*sqrt(1/arg**2)*(pi/2 - acsc(sqrt((1 + arg**2)/arg**2))) 

2975 

2976 

2977class asec(InverseTrigonometricFunction): 

2978 r""" 

2979 The inverse secant function. 

2980 

2981 Returns the arc secant of x (measured in radians). 

2982 

2983 Explanation 

2984 =========== 

2985 

2986 ``asec(x)`` will evaluate automatically in the cases 

2987 $x \in \{\infty, -\infty, 0, 1, -1\}$ and for some instances when the 

2988 result is a rational multiple of $\pi$ (see the eval class method). 

2989 

2990 ``asec(x)`` has branch cut in the interval $[-1, 1]$. For complex arguments, 

2991 it can be defined [4]_ as 

2992 

2993 .. math:: 

2994 \operatorname{sec^{-1}}(z) = -i\frac{\log\left(\sqrt{1 - z^2} + 1\right)}{z} 

2995 

2996 At ``x = 0``, for positive branch cut, the limit evaluates to ``zoo``. For 

2997 negative branch cut, the limit 

2998 

2999 .. math:: 

3000 \lim_{z \to 0}-i\frac{\log\left(-\sqrt{1 - z^2} + 1\right)}{z} 

3001 

3002 simplifies to :math:`-i\log\left(z/2 + O\left(z^3\right)\right)` which 

3003 ultimately evaluates to ``zoo``. 

3004 

3005 As ``acos(x) = asec(1/x)``, a similar argument can be given for 

3006 ``acos(x)``. 

3007 

3008 Examples 

3009 ======== 

3010 

3011 >>> from sympy import asec, oo 

3012 >>> asec(1) 

3013 0 

3014 >>> asec(-1) 

3015 pi 

3016 >>> asec(0) 

3017 zoo 

3018 >>> asec(-oo) 

3019 pi/2 

3020 

3021 See Also 

3022 ======== 

3023 

3024 sin, csc, cos, sec, tan, cot 

3025 asin, acsc, acos, atan, acot, atan2 

3026 

3027 References 

3028 ========== 

3029 

3030 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

3031 .. [2] https://dlmf.nist.gov/4.23 

3032 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcSec 

3033 .. [4] https://reference.wolfram.com/language/ref/ArcSec.html 

3034 

3035 """ 

3036 

3037 @classmethod 

3038 def eval(cls, arg): 

3039 if arg.is_zero: 

3040 return S.ComplexInfinity 

3041 if arg.is_Number: 

3042 if arg is S.NaN: 

3043 return S.NaN 

3044 elif arg is S.One: 

3045 return S.Zero 

3046 elif arg is S.NegativeOne: 

3047 return pi 

3048 if arg in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: 

3049 return pi/2 

3050 

3051 if arg.is_number: 

3052 acsc_table = cls._acsc_table() 

3053 if arg in acsc_table: 

3054 return pi/2 - acsc_table[arg] 

3055 elif -arg in acsc_table: 

3056 return pi/2 + acsc_table[-arg] 

3057 

3058 if arg.is_infinite: 

3059 return pi/2 

3060 

3061 if isinstance(arg, sec): 

3062 ang = arg.args[0] 

3063 if ang.is_comparable: 

3064 ang %= 2*pi # restrict to [0,2*pi) 

3065 if ang > pi: # restrict to [0,pi] 

3066 ang = 2*pi - ang 

3067 

3068 return ang 

3069 

3070 if isinstance(arg, csc): # asec(x) + acsc(x) = pi/2 

3071 ang = arg.args[0] 

3072 if ang.is_comparable: 

3073 return pi/2 - acsc(arg) 

3074 

3075 def fdiff(self, argindex=1): 

3076 if argindex == 1: 

3077 return 1/(self.args[0]**2*sqrt(1 - 1/self.args[0]**2)) 

3078 else: 

3079 raise ArgumentIndexError(self, argindex) 

3080 

3081 def inverse(self, argindex=1): 

3082 """ 

3083 Returns the inverse of this function. 

3084 """ 

3085 return sec 

3086 

3087 @staticmethod 

3088 @cacheit 

3089 def taylor_term(n, x, *previous_terms): 

3090 if n == 0: 

3091 return S.ImaginaryUnit*log(2 / x) 

3092 elif n < 0 or n % 2 == 1: 

3093 return S.Zero 

3094 else: 

3095 x = sympify(x) 

3096 if len(previous_terms) > 2 and n > 2: 

3097 p = previous_terms[-2] 

3098 return p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2) 

3099 else: 

3100 k = n // 2 

3101 R = RisingFactorial(S.Half, k) * n 

3102 F = factorial(k) * n // 2 * n // 2 

3103 return -S.ImaginaryUnit * R / F * x**n / 4 

3104 

3105 def _eval_as_leading_term(self, x, logx=None, cdir=0): # asec 

3106 arg = self.args[0] 

3107 x0 = arg.subs(x, 0).cancel() 

3108 # Handling branch points 

3109 if x0 == 1: 

3110 return sqrt(2)*sqrt((arg - S.One).as_leading_term(x)) 

3111 if x0 in (-S.One, S.Zero): 

3112 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir) 

3113 # Handling points lying on branch cuts (-1, 1) 

3114 if x0.is_real and (1 - x0**2).is_positive: 

3115 ndir = arg.dir(x, cdir if cdir else 1) 

3116 if im(ndir).is_negative: 

3117 if x0.is_positive: 

3118 return -self.func(x0) 

3119 elif im(ndir).is_positive: 

3120 if x0.is_negative: 

3121 return 2*pi - self.func(x0) 

3122 else: 

3123 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

3124 return self.func(x0) 

3125 

3126 def _eval_nseries(self, x, n, logx, cdir=0): # asec 

3127 from sympy.series.order import O 

3128 arg0 = self.args[0].subs(x, 0) 

3129 # Handling branch points 

3130 if arg0 is S.One: 

3131 t = Dummy('t', positive=True) 

3132 ser = asec(S.One + t**2).rewrite(log).nseries(t, 0, 2*n) 

3133 arg1 = S.NegativeOne + self.args[0] 

3134 f = arg1.as_leading_term(x) 

3135 g = (arg1 - f)/ f 

3136 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

3137 res = (res1.removeO()*sqrt(f)).expand() 

3138 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

3139 

3140 if arg0 is S.NegativeOne: 

3141 t = Dummy('t', positive=True) 

3142 ser = asec(S.NegativeOne - t**2).rewrite(log).nseries(t, 0, 2*n) 

3143 arg1 = S.NegativeOne - self.args[0] 

3144 f = arg1.as_leading_term(x) 

3145 g = (arg1 - f)/ f 

3146 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

3147 res = (res1.removeO()*sqrt(f)).expand() 

3148 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

3149 

3150 res = Function._eval_nseries(self, x, n=n, logx=logx) 

3151 if arg0 is S.ComplexInfinity: 

3152 return res 

3153 # Handling points lying on branch cuts (-1, 1) 

3154 if arg0.is_real and (1 - arg0**2).is_positive: 

3155 ndir = self.args[0].dir(x, cdir if cdir else 1) 

3156 if im(ndir).is_negative: 

3157 if arg0.is_positive: 

3158 return -res 

3159 elif im(ndir).is_positive: 

3160 if arg0.is_negative: 

3161 return 2*pi - res 

3162 else: 

3163 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

3164 return res 

3165 

3166 def _eval_is_extended_real(self): 

3167 x = self.args[0] 

3168 if x.is_extended_real is False: 

3169 return False 

3170 return fuzzy_or(((x - 1).is_nonnegative, (-x - 1).is_nonnegative)) 

3171 

3172 def _eval_rewrite_as_log(self, arg, **kwargs): 

3173 return pi/2 + S.ImaginaryUnit*log(S.ImaginaryUnit/arg + sqrt(1 - 1/arg**2)) 

3174 

3175 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

3176 

3177 def _eval_rewrite_as_asin(self, arg, **kwargs): 

3178 return pi/2 - asin(1/arg) 

3179 

3180 def _eval_rewrite_as_acos(self, arg, **kwargs): 

3181 return acos(1/arg) 

3182 

3183 def _eval_rewrite_as_atan(self, x, **kwargs): 

3184 sx2x = sqrt(x**2)/x 

3185 return pi/2*(1 - sx2x) + sx2x*atan(sqrt(x**2 - 1)) 

3186 

3187 def _eval_rewrite_as_acot(self, x, **kwargs): 

3188 sx2x = sqrt(x**2)/x 

3189 return pi/2*(1 - sx2x) + sx2x*acot(1/sqrt(x**2 - 1)) 

3190 

3191 def _eval_rewrite_as_acsc(self, arg, **kwargs): 

3192 return pi/2 - acsc(arg) 

3193 

3194 

3195class acsc(InverseTrigonometricFunction): 

3196 r""" 

3197 The inverse cosecant function. 

3198 

3199 Returns the arc cosecant of x (measured in radians). 

3200 

3201 Explanation 

3202 =========== 

3203 

3204 ``acsc(x)`` will evaluate automatically in the cases 

3205 $x \in \{\infty, -\infty, 0, 1, -1\}$` and for some instances when the 

3206 result is a rational multiple of $\pi$ (see the ``eval`` class method). 

3207 

3208 Examples 

3209 ======== 

3210 

3211 >>> from sympy import acsc, oo 

3212 >>> acsc(1) 

3213 pi/2 

3214 >>> acsc(-1) 

3215 -pi/2 

3216 >>> acsc(oo) 

3217 0 

3218 >>> acsc(-oo) == acsc(oo) 

3219 True 

3220 >>> acsc(0) 

3221 zoo 

3222 

3223 See Also 

3224 ======== 

3225 

3226 sin, csc, cos, sec, tan, cot 

3227 asin, acos, asec, atan, acot, atan2 

3228 

3229 References 

3230 ========== 

3231 

3232 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

3233 .. [2] https://dlmf.nist.gov/4.23 

3234 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcCsc 

3235 

3236 """ 

3237 

3238 @classmethod 

3239 def eval(cls, arg): 

3240 if arg.is_zero: 

3241 return S.ComplexInfinity 

3242 if arg.is_Number: 

3243 if arg is S.NaN: 

3244 return S.NaN 

3245 elif arg is S.One: 

3246 return pi/2 

3247 elif arg is S.NegativeOne: 

3248 return -pi/2 

3249 if arg in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: 

3250 return S.Zero 

3251 

3252 if arg.could_extract_minus_sign(): 

3253 return -cls(-arg) 

3254 

3255 if arg.is_infinite: 

3256 return S.Zero 

3257 

3258 if arg.is_number: 

3259 acsc_table = cls._acsc_table() 

3260 if arg in acsc_table: 

3261 return acsc_table[arg] 

3262 

3263 if isinstance(arg, csc): 

3264 ang = arg.args[0] 

3265 if ang.is_comparable: 

3266 ang %= 2*pi # restrict to [0,2*pi) 

3267 if ang > pi: # restrict to (-pi,pi] 

3268 ang = pi - ang 

3269 

3270 # restrict to [-pi/2,pi/2] 

3271 if ang > pi/2: 

3272 ang = pi - ang 

3273 if ang < -pi/2: 

3274 ang = -pi - ang 

3275 

3276 return ang 

3277 

3278 if isinstance(arg, sec): # asec(x) + acsc(x) = pi/2 

3279 ang = arg.args[0] 

3280 if ang.is_comparable: 

3281 return pi/2 - asec(arg) 

3282 

3283 def fdiff(self, argindex=1): 

3284 if argindex == 1: 

3285 return -1/(self.args[0]**2*sqrt(1 - 1/self.args[0]**2)) 

3286 else: 

3287 raise ArgumentIndexError(self, argindex) 

3288 

3289 def inverse(self, argindex=1): 

3290 """ 

3291 Returns the inverse of this function. 

3292 """ 

3293 return csc 

3294 

3295 @staticmethod 

3296 @cacheit 

3297 def taylor_term(n, x, *previous_terms): 

3298 if n == 0: 

3299 return pi/2 - S.ImaginaryUnit*log(2) + S.ImaginaryUnit*log(x) 

3300 elif n < 0 or n % 2 == 1: 

3301 return S.Zero 

3302 else: 

3303 x = sympify(x) 

3304 if len(previous_terms) > 2 and n > 2: 

3305 p = previous_terms[-2] 

3306 return p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2) 

3307 else: 

3308 k = n // 2 

3309 R = RisingFactorial(S.Half, k) * n 

3310 F = factorial(k) * n // 2 * n // 2 

3311 return S.ImaginaryUnit * R / F * x**n / 4 

3312 

3313 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acsc 

3314 arg = self.args[0] 

3315 x0 = arg.subs(x, 0).cancel() 

3316 # Handling branch points 

3317 if x0 in (-S.One, S.One, S.Zero): 

3318 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

3319 if x0 is S.ComplexInfinity: 

3320 return (1/arg).as_leading_term(x) 

3321 # Handling points lying on branch cuts (-1, 1) 

3322 if x0.is_real and (1 - x0**2).is_positive: 

3323 ndir = arg.dir(x, cdir if cdir else 1) 

3324 if im(ndir).is_negative: 

3325 if x0.is_positive: 

3326 return pi - self.func(x0) 

3327 elif im(ndir).is_positive: 

3328 if x0.is_negative: 

3329 return -pi - self.func(x0) 

3330 else: 

3331 return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir).expand() 

3332 return self.func(x0) 

3333 

3334 def _eval_nseries(self, x, n, logx, cdir=0): # acsc 

3335 from sympy.series.order import O 

3336 arg0 = self.args[0].subs(x, 0) 

3337 # Handling branch points 

3338 if arg0 is S.One: 

3339 t = Dummy('t', positive=True) 

3340 ser = acsc(S.One + t**2).rewrite(log).nseries(t, 0, 2*n) 

3341 arg1 = S.NegativeOne + self.args[0] 

3342 f = arg1.as_leading_term(x) 

3343 g = (arg1 - f)/ f 

3344 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

3345 res = (res1.removeO()*sqrt(f)).expand() 

3346 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

3347 

3348 if arg0 is S.NegativeOne: 

3349 t = Dummy('t', positive=True) 

3350 ser = acsc(S.NegativeOne - t**2).rewrite(log).nseries(t, 0, 2*n) 

3351 arg1 = S.NegativeOne - self.args[0] 

3352 f = arg1.as_leading_term(x) 

3353 g = (arg1 - f)/ f 

3354 res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) 

3355 res = (res1.removeO()*sqrt(f)).expand() 

3356 return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) 

3357 

3358 res = Function._eval_nseries(self, x, n=n, logx=logx) 

3359 if arg0 is S.ComplexInfinity: 

3360 return res 

3361 # Handling points lying on branch cuts (-1, 1) 

3362 if arg0.is_real and (1 - arg0**2).is_positive: 

3363 ndir = self.args[0].dir(x, cdir if cdir else 1) 

3364 if im(ndir).is_negative: 

3365 if arg0.is_positive: 

3366 return pi - res 

3367 elif im(ndir).is_positive: 

3368 if arg0.is_negative: 

3369 return -pi - res 

3370 else: 

3371 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir) 

3372 return res 

3373 

3374 def _eval_rewrite_as_log(self, arg, **kwargs): 

3375 return -S.ImaginaryUnit*log(S.ImaginaryUnit/arg + sqrt(1 - 1/arg**2)) 

3376 

3377 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

3378 

3379 def _eval_rewrite_as_asin(self, arg, **kwargs): 

3380 return asin(1/arg) 

3381 

3382 def _eval_rewrite_as_acos(self, arg, **kwargs): 

3383 return pi/2 - acos(1/arg) 

3384 

3385 def _eval_rewrite_as_atan(self, x, **kwargs): 

3386 return sqrt(x**2)/x*(pi/2 - atan(sqrt(x**2 - 1))) 

3387 

3388 def _eval_rewrite_as_acot(self, arg, **kwargs): 

3389 return sqrt(arg**2)/arg*(pi/2 - acot(1/sqrt(arg**2 - 1))) 

3390 

3391 def _eval_rewrite_as_asec(self, arg, **kwargs): 

3392 return pi/2 - asec(arg) 

3393 

3394 

3395class atan2(InverseTrigonometricFunction): 

3396 r""" 

3397 The function ``atan2(y, x)`` computes `\operatorname{atan}(y/x)` taking 

3398 two arguments `y` and `x`. Signs of both `y` and `x` are considered to 

3399 determine the appropriate quadrant of `\operatorname{atan}(y/x)`. 

3400 The range is `(-\pi, \pi]`. The complete definition reads as follows: 

3401 

3402 .. math:: 

3403 

3404 \operatorname{atan2}(y, x) = 

3405 \begin{cases} 

3406 \arctan\left(\frac y x\right) & \qquad x > 0 \\ 

3407 \arctan\left(\frac y x\right) + \pi& \qquad y \ge 0, x < 0 \\ 

3408 \arctan\left(\frac y x\right) - \pi& \qquad y < 0, x < 0 \\ 

3409 +\frac{\pi}{2} & \qquad y > 0, x = 0 \\ 

3410 -\frac{\pi}{2} & \qquad y < 0, x = 0 \\ 

3411 \text{undefined} & \qquad y = 0, x = 0 

3412 \end{cases} 

3413 

3414 Attention: Note the role reversal of both arguments. The `y`-coordinate 

3415 is the first argument and the `x`-coordinate the second. 

3416 

3417 If either `x` or `y` is complex: 

3418 

3419 .. math:: 

3420 

3421 \operatorname{atan2}(y, x) = 

3422 -i\log\left(\frac{x + iy}{\sqrt{x^2 + y^2}}\right) 

3423 

3424 Examples 

3425 ======== 

3426 

3427 Going counter-clock wise around the origin we find the 

3428 following angles: 

3429 

3430 >>> from sympy import atan2 

3431 >>> atan2(0, 1) 

3432 0 

3433 >>> atan2(1, 1) 

3434 pi/4 

3435 >>> atan2(1, 0) 

3436 pi/2 

3437 >>> atan2(1, -1) 

3438 3*pi/4 

3439 >>> atan2(0, -1) 

3440 pi 

3441 >>> atan2(-1, -1) 

3442 -3*pi/4 

3443 >>> atan2(-1, 0) 

3444 -pi/2 

3445 >>> atan2(-1, 1) 

3446 -pi/4 

3447 

3448 which are all correct. Compare this to the results of the ordinary 

3449 `\operatorname{atan}` function for the point `(x, y) = (-1, 1)` 

3450 

3451 >>> from sympy import atan, S 

3452 >>> atan(S(1)/-1) 

3453 -pi/4 

3454 >>> atan2(1, -1) 

3455 3*pi/4 

3456 

3457 where only the `\operatorname{atan2}` function reurns what we expect. 

3458 We can differentiate the function with respect to both arguments: 

3459 

3460 >>> from sympy import diff 

3461 >>> from sympy.abc import x, y 

3462 >>> diff(atan2(y, x), x) 

3463 -y/(x**2 + y**2) 

3464 

3465 >>> diff(atan2(y, x), y) 

3466 x/(x**2 + y**2) 

3467 

3468 We can express the `\operatorname{atan2}` function in terms of 

3469 complex logarithms: 

3470 

3471 >>> from sympy import log 

3472 >>> atan2(y, x).rewrite(log) 

3473 -I*log((x + I*y)/sqrt(x**2 + y**2)) 

3474 

3475 and in terms of `\operatorname(atan)`: 

3476 

3477 >>> from sympy import atan 

3478 >>> atan2(y, x).rewrite(atan) 

3479 Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, re(x) < 0), (0, Ne(x, 0)), (nan, True)) 

3480 

3481 but note that this form is undefined on the negative real axis. 

3482 

3483 See Also 

3484 ======== 

3485 

3486 sin, csc, cos, sec, tan, cot 

3487 asin, acsc, acos, asec, atan, acot 

3488 

3489 References 

3490 ========== 

3491 

3492 .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions 

3493 .. [2] https://en.wikipedia.org/wiki/Atan2 

3494 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcTan2 

3495 

3496 """ 

3497 

3498 @classmethod 

3499 def eval(cls, y, x): 

3500 from sympy.functions.special.delta_functions import Heaviside 

3501 if x is S.NegativeInfinity: 

3502 if y.is_zero: 

3503 # Special case y = 0 because we define Heaviside(0) = 1/2 

3504 return pi 

3505 return 2*pi*(Heaviside(re(y))) - pi 

3506 elif x is S.Infinity: 

3507 return S.Zero 

3508 elif x.is_imaginary and y.is_imaginary and x.is_number and y.is_number: 

3509 x = im(x) 

3510 y = im(y) 

3511 

3512 if x.is_extended_real and y.is_extended_real: 

3513 if x.is_positive: 

3514 return atan(y/x) 

3515 elif x.is_negative: 

3516 if y.is_negative: 

3517 return atan(y/x) - pi 

3518 elif y.is_nonnegative: 

3519 return atan(y/x) + pi 

3520 elif x.is_zero: 

3521 if y.is_positive: 

3522 return pi/2 

3523 elif y.is_negative: 

3524 return -pi/2 

3525 elif y.is_zero: 

3526 return S.NaN 

3527 if y.is_zero: 

3528 if x.is_extended_nonzero: 

3529 return pi*(S.One - Heaviside(x)) 

3530 if x.is_number: 

3531 return Piecewise((pi, re(x) < 0), 

3532 (0, Ne(x, 0)), 

3533 (S.NaN, True)) 

3534 if x.is_number and y.is_number: 

3535 return -S.ImaginaryUnit*log( 

3536 (x + S.ImaginaryUnit*y)/sqrt(x**2 + y**2)) 

3537 

3538 def _eval_rewrite_as_log(self, y, x, **kwargs): 

3539 return -S.ImaginaryUnit*log((x + S.ImaginaryUnit*y)/sqrt(x**2 + y**2)) 

3540 

3541 def _eval_rewrite_as_atan(self, y, x, **kwargs): 

3542 return Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), 

3543 (pi, re(x) < 0), 

3544 (0, Ne(x, 0)), 

3545 (S.NaN, True)) 

3546 

3547 def _eval_rewrite_as_arg(self, y, x, **kwargs): 

3548 if x.is_extended_real and y.is_extended_real: 

3549 return arg_f(x + y*S.ImaginaryUnit) 

3550 n = x + S.ImaginaryUnit*y 

3551 d = x**2 + y**2 

3552 return arg_f(n/sqrt(d)) - S.ImaginaryUnit*log(abs(n)/sqrt(abs(d))) 

3553 

3554 def _eval_is_extended_real(self): 

3555 return self.args[0].is_extended_real and self.args[1].is_extended_real 

3556 

3557 def _eval_conjugate(self): 

3558 return self.func(self.args[0].conjugate(), self.args[1].conjugate()) 

3559 

3560 def fdiff(self, argindex): 

3561 y, x = self.args 

3562 if argindex == 1: 

3563 # Diff wrt y 

3564 return x/(x**2 + y**2) 

3565 elif argindex == 2: 

3566 # Diff wrt x 

3567 return -y/(x**2 + y**2) 

3568 else: 

3569 raise ArgumentIndexError(self, argindex) 

3570 

3571 def _eval_evalf(self, prec): 

3572 y, x = self.args 

3573 if x.is_extended_real and y.is_extended_real: 

3574 return super()._eval_evalf(prec)