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

1326 statements  

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

1from sympy.core import S, sympify, cacheit 

2from sympy.core.add import Add 

3from sympy.core.function import Function, ArgumentIndexError 

4from sympy.core.logic import fuzzy_or, fuzzy_and, FuzzyBool 

5from sympy.core.numbers import I, pi, Rational 

6from sympy.core.symbol import Dummy 

7from sympy.functions.combinatorial.factorials import (binomial, factorial, 

8 RisingFactorial) 

9from sympy.functions.combinatorial.numbers import bernoulli, euler, nC 

10from sympy.functions.elementary.complexes import Abs, im, re 

11from sympy.functions.elementary.exponential import exp, log, match_real_imag 

12from sympy.functions.elementary.integers import floor 

13from sympy.functions.elementary.miscellaneous import sqrt 

14from sympy.functions.elementary.trigonometric import ( 

15 acos, acot, asin, atan, cos, cot, csc, sec, sin, tan, 

16 _imaginary_unit_as_coefficient) 

17from sympy.polys.specialpolys import symmetric_poly 

18 

19 

20def _rewrite_hyperbolics_as_exp(expr): 

21 return expr.xreplace({h: h.rewrite(exp) 

22 for h in expr.atoms(HyperbolicFunction)}) 

23 

24 

25@cacheit 

26def _acosh_table(): 

27 return { 

28 I: log(I*(1 + sqrt(2))), 

29 -I: log(-I*(1 + sqrt(2))), 

30 S.Half: pi/3, 

31 Rational(-1, 2): pi*Rational(2, 3), 

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

33 -sqrt(2)/2: pi*Rational(3, 4), 

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

35 -1/sqrt(2): pi*Rational(3, 4), 

36 sqrt(3)/2: pi/6, 

37 -sqrt(3)/2: pi*Rational(5, 6), 

38 (sqrt(3) - 1)/sqrt(2**3): pi*Rational(5, 12), 

39 -(sqrt(3) - 1)/sqrt(2**3): pi*Rational(7, 12), 

40 sqrt(2 + sqrt(2))/2: pi/8, 

41 -sqrt(2 + sqrt(2))/2: pi*Rational(7, 8), 

42 sqrt(2 - sqrt(2))/2: pi*Rational(3, 8), 

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

44 (1 + sqrt(3))/(2*sqrt(2)): pi/12, 

45 -(1 + sqrt(3))/(2*sqrt(2)): pi*Rational(11, 12), 

46 (sqrt(5) + 1)/4: pi/5, 

47 -(sqrt(5) + 1)/4: pi*Rational(4, 5) 

48 } 

49 

50 

51@cacheit 

52def _acsch_table(): 

53 return { 

54 I: -pi / 2, 

55 I*(sqrt(2) + sqrt(6)): -pi / 12, 

56 I*(1 + sqrt(5)): -pi / 10, 

57 I*2 / sqrt(2 - sqrt(2)): -pi / 8, 

58 I*2: -pi / 6, 

59 I*sqrt(2 + 2/sqrt(5)): -pi / 5, 

60 I*sqrt(2): -pi / 4, 

61 I*(sqrt(5)-1): -3*pi / 10, 

62 I*2 / sqrt(3): -pi / 3, 

63 I*2 / sqrt(2 + sqrt(2)): -3*pi / 8, 

64 I*sqrt(2 - 2/sqrt(5)): -2*pi / 5, 

65 I*(sqrt(6) - sqrt(2)): -5*pi / 12, 

66 S(2): -I*log((1+sqrt(5))/2), 

67 } 

68 

69 

70@cacheit 

71def _asech_table(): 

72 return { 

73 I: - (pi*I / 2) + log(1 + sqrt(2)), 

74 -I: (pi*I / 2) + log(1 + sqrt(2)), 

75 (sqrt(6) - sqrt(2)): pi / 12, 

76 (sqrt(2) - sqrt(6)): 11*pi / 12, 

77 sqrt(2 - 2/sqrt(5)): pi / 10, 

78 -sqrt(2 - 2/sqrt(5)): 9*pi / 10, 

79 2 / sqrt(2 + sqrt(2)): pi / 8, 

80 -2 / sqrt(2 + sqrt(2)): 7*pi / 8, 

81 2 / sqrt(3): pi / 6, 

82 -2 / sqrt(3): 5*pi / 6, 

83 (sqrt(5) - 1): pi / 5, 

84 (1 - sqrt(5)): 4*pi / 5, 

85 sqrt(2): pi / 4, 

86 -sqrt(2): 3*pi / 4, 

87 sqrt(2 + 2/sqrt(5)): 3*pi / 10, 

88 -sqrt(2 + 2/sqrt(5)): 7*pi / 10, 

89 S(2): pi / 3, 

90 -S(2): 2*pi / 3, 

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

92 -sqrt(2*(2 + sqrt(2))): 5*pi / 8, 

93 (1 + sqrt(5)): 2*pi / 5, 

94 (-1 - sqrt(5)): 3*pi / 5, 

95 (sqrt(6) + sqrt(2)): 5*pi / 12, 

96 (-sqrt(6) - sqrt(2)): 7*pi / 12, 

97 I*S.Infinity: -pi*I / 2, 

98 I*S.NegativeInfinity: pi*I / 2, 

99 } 

100 

101############################################################################### 

102########################### HYPERBOLIC FUNCTIONS ############################## 

103############################################################################### 

104 

105 

106class HyperbolicFunction(Function): 

107 """ 

108 Base class for hyperbolic functions. 

109 

110 See Also 

111 ======== 

112 

113 sinh, cosh, tanh, coth 

114 """ 

115 

116 unbranched = True 

117 

118 

119def _peeloff_ipi(arg): 

120 r""" 

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

122 This assumes ARG to be an ``Add``. 

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

124 

125 Examples 

126 ======== 

127 

128 >>> from sympy.functions.elementary.hyperbolic import _peeloff_ipi as peel 

129 >>> from sympy import pi, I 

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

131 >>> peel(x + I*pi/2) 

132 (x, 1/2) 

133 >>> peel(x + I*2*pi/3 + I*pi*y) 

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

135 """ 

136 ipi = pi*I 

137 for a in Add.make_args(arg): 

138 if a == ipi: 

139 K = S.One 

140 break 

141 elif a.is_Mul: 

142 K, p = a.as_two_terms() 

143 if p == ipi and K.is_Rational: 

144 break 

145 else: 

146 return arg, S.Zero 

147 

148 m1 = (K % S.Half) 

149 m2 = K - m1 

150 return arg - m2*ipi, m2 

151 

152 

153class sinh(HyperbolicFunction): 

154 r""" 

155 ``sinh(x)`` is the hyperbolic sine of ``x``. 

156 

157 The hyperbolic sine function is $\frac{e^x - e^{-x}}{2}$. 

158 

159 Examples 

160 ======== 

161 

162 >>> from sympy import sinh 

163 >>> from sympy.abc import x 

164 >>> sinh(x) 

165 sinh(x) 

166 

167 See Also 

168 ======== 

169 

170 cosh, tanh, asinh 

171 """ 

172 

173 def fdiff(self, argindex=1): 

174 """ 

175 Returns the first derivative of this function. 

176 """ 

177 if argindex == 1: 

178 return cosh(self.args[0]) 

179 else: 

180 raise ArgumentIndexError(self, argindex) 

181 

182 def inverse(self, argindex=1): 

183 """ 

184 Returns the inverse of this function. 

185 """ 

186 return asinh 

187 

188 @classmethod 

189 def eval(cls, arg): 

190 if arg.is_Number: 

191 if arg is S.NaN: 

192 return S.NaN 

193 elif arg is S.Infinity: 

194 return S.Infinity 

195 elif arg is S.NegativeInfinity: 

196 return S.NegativeInfinity 

197 elif arg.is_zero: 

198 return S.Zero 

199 elif arg.is_negative: 

200 return -cls(-arg) 

201 else: 

202 if arg is S.ComplexInfinity: 

203 return S.NaN 

204 

205 i_coeff = _imaginary_unit_as_coefficient(arg) 

206 

207 if i_coeff is not None: 

208 return I * sin(i_coeff) 

209 else: 

210 if arg.could_extract_minus_sign(): 

211 return -cls(-arg) 

212 

213 if arg.is_Add: 

214 x, m = _peeloff_ipi(arg) 

215 if m: 

216 m = m*pi*I 

217 return sinh(m)*cosh(x) + cosh(m)*sinh(x) 

218 

219 if arg.is_zero: 

220 return S.Zero 

221 

222 if arg.func == asinh: 

223 return arg.args[0] 

224 

225 if arg.func == acosh: 

226 x = arg.args[0] 

227 return sqrt(x - 1) * sqrt(x + 1) 

228 

229 if arg.func == atanh: 

230 x = arg.args[0] 

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

232 

233 if arg.func == acoth: 

234 x = arg.args[0] 

235 return 1/(sqrt(x - 1) * sqrt(x + 1)) 

236 

237 @staticmethod 

238 @cacheit 

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

240 """ 

241 Returns the next term in the Taylor series expansion. 

242 """ 

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

244 return S.Zero 

245 else: 

246 x = sympify(x) 

247 

248 if len(previous_terms) > 2: 

249 p = previous_terms[-2] 

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

251 else: 

252 return x**(n) / factorial(n) 

253 

254 def _eval_conjugate(self): 

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

256 

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

258 """ 

259 Returns this function as a complex coordinate. 

260 """ 

261 if self.args[0].is_extended_real: 

262 if deep: 

263 hints['complex'] = False 

264 return (self.expand(deep, **hints), S.Zero) 

265 else: 

266 return (self, S.Zero) 

267 if deep: 

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

269 else: 

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

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

272 

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

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

275 return re_part + im_part*I 

276 

277 def _eval_expand_trig(self, deep=True, **hints): 

278 if deep: 

279 arg = self.args[0].expand(deep, **hints) 

280 else: 

281 arg = self.args[0] 

282 x = None 

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

284 x, y = arg.as_two_terms() 

285 else: 

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

287 if coeff is not S.One and coeff.is_Integer and terms is not S.One: 

288 x = terms 

289 y = (coeff - 1)*x 

290 if x is not None: 

291 return (sinh(x)*cosh(y) + sinh(y)*cosh(x)).expand(trig=True) 

292 return sinh(arg) 

293 

294 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): 

295 return (exp(arg) - exp(-arg)) / 2 

296 

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

298 return (exp(arg) - exp(-arg)) / 2 

299 

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

301 return -I * sin(I * arg) 

302 

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

304 return -I / csc(I * arg) 

305 

306 def _eval_rewrite_as_cosh(self, arg, **kwargs): 

307 return -I*cosh(arg + pi*I/2) 

308 

309 def _eval_rewrite_as_tanh(self, arg, **kwargs): 

310 tanh_half = tanh(S.Half*arg) 

311 return 2*tanh_half/(1 - tanh_half**2) 

312 

313 def _eval_rewrite_as_coth(self, arg, **kwargs): 

314 coth_half = coth(S.Half*arg) 

315 return 2*coth_half/(coth_half**2 - 1) 

316 

317 def _eval_rewrite_as_csch(self, arg, **kwargs): 

318 return 1 / csch(arg) 

319 

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

321 arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) 

322 arg0 = arg.subs(x, 0) 

323 

324 if arg0 is S.NaN: 

325 arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+') 

326 if arg0.is_zero: 

327 return arg 

328 elif arg0.is_finite: 

329 return self.func(arg0) 

330 else: 

331 return self 

332 

333 def _eval_is_real(self): 

334 arg = self.args[0] 

335 if arg.is_real: 

336 return True 

337 

338 # if `im` is of the form n*pi 

339 # else, check if it is a number 

340 re, im = arg.as_real_imag() 

341 return (im%pi).is_zero 

342 

343 def _eval_is_extended_real(self): 

344 if self.args[0].is_extended_real: 

345 return True 

346 

347 def _eval_is_positive(self): 

348 if self.args[0].is_extended_real: 

349 return self.args[0].is_positive 

350 

351 def _eval_is_negative(self): 

352 if self.args[0].is_extended_real: 

353 return self.args[0].is_negative 

354 

355 def _eval_is_finite(self): 

356 arg = self.args[0] 

357 return arg.is_finite 

358 

359 def _eval_is_zero(self): 

360 rest, ipi_mult = _peeloff_ipi(self.args[0]) 

361 if rest.is_zero: 

362 return ipi_mult.is_integer 

363 

364 

365class cosh(HyperbolicFunction): 

366 r""" 

367 ``cosh(x)`` is the hyperbolic cosine of ``x``. 

368 

369 The hyperbolic cosine function is $\frac{e^x + e^{-x}}{2}$. 

370 

371 Examples 

372 ======== 

373 

374 >>> from sympy import cosh 

375 >>> from sympy.abc import x 

376 >>> cosh(x) 

377 cosh(x) 

378 

379 See Also 

380 ======== 

381 

382 sinh, tanh, acosh 

383 """ 

384 

385 def fdiff(self, argindex=1): 

386 if argindex == 1: 

387 return sinh(self.args[0]) 

388 else: 

389 raise ArgumentIndexError(self, argindex) 

390 

391 @classmethod 

392 def eval(cls, arg): 

393 from sympy.functions.elementary.trigonometric import cos 

394 if arg.is_Number: 

395 if arg is S.NaN: 

396 return S.NaN 

397 elif arg is S.Infinity: 

398 return S.Infinity 

399 elif arg is S.NegativeInfinity: 

400 return S.Infinity 

401 elif arg.is_zero: 

402 return S.One 

403 elif arg.is_negative: 

404 return cls(-arg) 

405 else: 

406 if arg is S.ComplexInfinity: 

407 return S.NaN 

408 

409 i_coeff = _imaginary_unit_as_coefficient(arg) 

410 

411 if i_coeff is not None: 

412 return cos(i_coeff) 

413 else: 

414 if arg.could_extract_minus_sign(): 

415 return cls(-arg) 

416 

417 if arg.is_Add: 

418 x, m = _peeloff_ipi(arg) 

419 if m: 

420 m = m*pi*I 

421 return cosh(m)*cosh(x) + sinh(m)*sinh(x) 

422 

423 if arg.is_zero: 

424 return S.One 

425 

426 if arg.func == asinh: 

427 return sqrt(1 + arg.args[0]**2) 

428 

429 if arg.func == acosh: 

430 return arg.args[0] 

431 

432 if arg.func == atanh: 

433 return 1/sqrt(1 - arg.args[0]**2) 

434 

435 if arg.func == acoth: 

436 x = arg.args[0] 

437 return x/(sqrt(x - 1) * sqrt(x + 1)) 

438 

439 @staticmethod 

440 @cacheit 

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

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

443 return S.Zero 

444 else: 

445 x = sympify(x) 

446 

447 if len(previous_terms) > 2: 

448 p = previous_terms[-2] 

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

450 else: 

451 return x**(n)/factorial(n) 

452 

453 def _eval_conjugate(self): 

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

455 

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

457 if self.args[0].is_extended_real: 

458 if deep: 

459 hints['complex'] = False 

460 return (self.expand(deep, **hints), S.Zero) 

461 else: 

462 return (self, S.Zero) 

463 if deep: 

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

465 else: 

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

467 

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

469 

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

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

472 return re_part + im_part*I 

473 

474 def _eval_expand_trig(self, deep=True, **hints): 

475 if deep: 

476 arg = self.args[0].expand(deep, **hints) 

477 else: 

478 arg = self.args[0] 

479 x = None 

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

481 x, y = arg.as_two_terms() 

482 else: 

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

484 if coeff is not S.One and coeff.is_Integer and terms is not S.One: 

485 x = terms 

486 y = (coeff - 1)*x 

487 if x is not None: 

488 return (cosh(x)*cosh(y) + sinh(x)*sinh(y)).expand(trig=True) 

489 return cosh(arg) 

490 

491 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): 

492 return (exp(arg) + exp(-arg)) / 2 

493 

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

495 return (exp(arg) + exp(-arg)) / 2 

496 

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

498 return cos(I * arg) 

499 

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

501 return 1 / sec(I * arg) 

502 

503 def _eval_rewrite_as_sinh(self, arg, **kwargs): 

504 return -I*sinh(arg + pi*I/2) 

505 

506 def _eval_rewrite_as_tanh(self, arg, **kwargs): 

507 tanh_half = tanh(S.Half*arg)**2 

508 return (1 + tanh_half)/(1 - tanh_half) 

509 

510 def _eval_rewrite_as_coth(self, arg, **kwargs): 

511 coth_half = coth(S.Half*arg)**2 

512 return (coth_half + 1)/(coth_half - 1) 

513 

514 def _eval_rewrite_as_sech(self, arg, **kwargs): 

515 return 1 / sech(arg) 

516 

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

518 arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) 

519 arg0 = arg.subs(x, 0) 

520 

521 if arg0 is S.NaN: 

522 arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+') 

523 if arg0.is_zero: 

524 return S.One 

525 elif arg0.is_finite: 

526 return self.func(arg0) 

527 else: 

528 return self 

529 

530 def _eval_is_real(self): 

531 arg = self.args[0] 

532 

533 # `cosh(x)` is real for real OR purely imaginary `x` 

534 if arg.is_real or arg.is_imaginary: 

535 return True 

536 

537 # cosh(a+ib) = cos(b)*cosh(a) + i*sin(b)*sinh(a) 

538 # the imaginary part can be an expression like n*pi 

539 # if not, check if the imaginary part is a number 

540 re, im = arg.as_real_imag() 

541 return (im%pi).is_zero 

542 

543 def _eval_is_positive(self): 

544 # cosh(x+I*y) = cos(y)*cosh(x) + I*sin(y)*sinh(x) 

545 # cosh(z) is positive iff it is real and the real part is positive. 

546 # So we need sin(y)*sinh(x) = 0 which gives x=0 or y=n*pi 

547 # Case 1 (y=n*pi): cosh(z) = (-1)**n * cosh(x) -> positive for n even 

548 # Case 2 (x=0): cosh(z) = cos(y) -> positive when cos(y) is positive 

549 z = self.args[0] 

550 

551 x, y = z.as_real_imag() 

552 ymod = y % (2*pi) 

553 

554 yzero = ymod.is_zero 

555 # shortcut if ymod is zero 

556 if yzero: 

557 return True 

558 

559 xzero = x.is_zero 

560 # shortcut x is not zero 

561 if xzero is False: 

562 return yzero 

563 

564 return fuzzy_or([ 

565 # Case 1: 

566 yzero, 

567 # Case 2: 

568 fuzzy_and([ 

569 xzero, 

570 fuzzy_or([ymod < pi/2, ymod > 3*pi/2]) 

571 ]) 

572 ]) 

573 

574 

575 def _eval_is_nonnegative(self): 

576 z = self.args[0] 

577 

578 x, y = z.as_real_imag() 

579 ymod = y % (2*pi) 

580 

581 yzero = ymod.is_zero 

582 # shortcut if ymod is zero 

583 if yzero: 

584 return True 

585 

586 xzero = x.is_zero 

587 # shortcut x is not zero 

588 if xzero is False: 

589 return yzero 

590 

591 return fuzzy_or([ 

592 # Case 1: 

593 yzero, 

594 # Case 2: 

595 fuzzy_and([ 

596 xzero, 

597 fuzzy_or([ymod <= pi/2, ymod >= 3*pi/2]) 

598 ]) 

599 ]) 

600 

601 def _eval_is_finite(self): 

602 arg = self.args[0] 

603 return arg.is_finite 

604 

605 def _eval_is_zero(self): 

606 rest, ipi_mult = _peeloff_ipi(self.args[0]) 

607 if ipi_mult and rest.is_zero: 

608 return (ipi_mult - S.Half).is_integer 

609 

610 

611class tanh(HyperbolicFunction): 

612 r""" 

613 ``tanh(x)`` is the hyperbolic tangent of ``x``. 

614 

615 The hyperbolic tangent function is $\frac{\sinh(x)}{\cosh(x)}$. 

616 

617 Examples 

618 ======== 

619 

620 >>> from sympy import tanh 

621 >>> from sympy.abc import x 

622 >>> tanh(x) 

623 tanh(x) 

624 

625 See Also 

626 ======== 

627 

628 sinh, cosh, atanh 

629 """ 

630 

631 def fdiff(self, argindex=1): 

632 if argindex == 1: 

633 return S.One - tanh(self.args[0])**2 

634 else: 

635 raise ArgumentIndexError(self, argindex) 

636 

637 def inverse(self, argindex=1): 

638 """ 

639 Returns the inverse of this function. 

640 """ 

641 return atanh 

642 

643 @classmethod 

644 def eval(cls, arg): 

645 if arg.is_Number: 

646 if arg is S.NaN: 

647 return S.NaN 

648 elif arg is S.Infinity: 

649 return S.One 

650 elif arg is S.NegativeInfinity: 

651 return S.NegativeOne 

652 elif arg.is_zero: 

653 return S.Zero 

654 elif arg.is_negative: 

655 return -cls(-arg) 

656 else: 

657 if arg is S.ComplexInfinity: 

658 return S.NaN 

659 

660 i_coeff = _imaginary_unit_as_coefficient(arg) 

661 

662 if i_coeff is not None: 

663 if i_coeff.could_extract_minus_sign(): 

664 return -I * tan(-i_coeff) 

665 return I * tan(i_coeff) 

666 else: 

667 if arg.could_extract_minus_sign(): 

668 return -cls(-arg) 

669 

670 if arg.is_Add: 

671 x, m = _peeloff_ipi(arg) 

672 if m: 

673 tanhm = tanh(m*pi*I) 

674 if tanhm is S.ComplexInfinity: 

675 return coth(x) 

676 else: # tanhm == 0 

677 return tanh(x) 

678 

679 if arg.is_zero: 

680 return S.Zero 

681 

682 if arg.func == asinh: 

683 x = arg.args[0] 

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

685 

686 if arg.func == acosh: 

687 x = arg.args[0] 

688 return sqrt(x - 1) * sqrt(x + 1) / x 

689 

690 if arg.func == atanh: 

691 return arg.args[0] 

692 

693 if arg.func == acoth: 

694 return 1/arg.args[0] 

695 

696 @staticmethod 

697 @cacheit 

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

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

700 return S.Zero 

701 else: 

702 x = sympify(x) 

703 

704 a = 2**(n + 1) 

705 

706 B = bernoulli(n + 1) 

707 F = factorial(n + 1) 

708 

709 return a*(a - 1) * B/F * x**n 

710 

711 def _eval_conjugate(self): 

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

713 

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

715 if self.args[0].is_extended_real: 

716 if deep: 

717 hints['complex'] = False 

718 return (self.expand(deep, **hints), S.Zero) 

719 else: 

720 return (self, S.Zero) 

721 if deep: 

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

723 else: 

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

725 denom = sinh(re)**2 + cos(im)**2 

726 return (sinh(re)*cosh(re)/denom, sin(im)*cos(im)/denom) 

727 

728 def _eval_expand_trig(self, **hints): 

729 arg = self.args[0] 

730 if arg.is_Add: 

731 n = len(arg.args) 

732 TX = [tanh(x, evaluate=False)._eval_expand_trig() 

733 for x in arg.args] 

734 p = [0, 0] # [den, num] 

735 for i in range(n + 1): 

736 p[i % 2] += symmetric_poly(i, TX) 

737 return p[1]/p[0] 

738 elif arg.is_Mul: 

739 coeff, terms = arg.as_coeff_Mul() 

740 if coeff.is_Integer and coeff > 1: 

741 T = tanh(terms) 

742 n = [nC(range(coeff), k)*T**k for k in range(1, coeff + 1, 2)] 

743 d = [nC(range(coeff), k)*T**k for k in range(0, coeff + 1, 2)] 

744 return Add(*n)/Add(*d) 

745 return tanh(arg) 

746 

747 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): 

748 neg_exp, pos_exp = exp(-arg), exp(arg) 

749 return (pos_exp - neg_exp)/(pos_exp + neg_exp) 

750 

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

752 neg_exp, pos_exp = exp(-arg), exp(arg) 

753 return (pos_exp - neg_exp)/(pos_exp + neg_exp) 

754 

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

756 return -I * tan(I * arg) 

757 

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

759 return -I / cot(I * arg) 

760 

761 def _eval_rewrite_as_sinh(self, arg, **kwargs): 

762 return I*sinh(arg)/sinh(pi*I/2 - arg) 

763 

764 def _eval_rewrite_as_cosh(self, arg, **kwargs): 

765 return I*cosh(pi*I/2 - arg)/cosh(arg) 

766 

767 def _eval_rewrite_as_coth(self, arg, **kwargs): 

768 return 1/coth(arg) 

769 

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

771 from sympy.series.order import Order 

772 arg = self.args[0].as_leading_term(x) 

773 

774 if x in arg.free_symbols and Order(1, x).contains(arg): 

775 return arg 

776 else: 

777 return self.func(arg) 

778 

779 def _eval_is_real(self): 

780 arg = self.args[0] 

781 if arg.is_real: 

782 return True 

783 

784 re, im = arg.as_real_imag() 

785 

786 # if denom = 0, tanh(arg) = zoo 

787 if re == 0 and im % pi == pi/2: 

788 return None 

789 

790 # check if im is of the form n*pi/2 to make sin(2*im) = 0 

791 # if not, im could be a number, return False in that case 

792 return (im % (pi/2)).is_zero 

793 

794 def _eval_is_extended_real(self): 

795 if self.args[0].is_extended_real: 

796 return True 

797 

798 def _eval_is_positive(self): 

799 if self.args[0].is_extended_real: 

800 return self.args[0].is_positive 

801 

802 def _eval_is_negative(self): 

803 if self.args[0].is_extended_real: 

804 return self.args[0].is_negative 

805 

806 def _eval_is_finite(self): 

807 arg = self.args[0] 

808 

809 re, im = arg.as_real_imag() 

810 denom = cos(im)**2 + sinh(re)**2 

811 if denom == 0: 

812 return False 

813 elif denom.is_number: 

814 return True 

815 if arg.is_extended_real: 

816 return True 

817 

818 def _eval_is_zero(self): 

819 arg = self.args[0] 

820 if arg.is_zero: 

821 return True 

822 

823 

824class coth(HyperbolicFunction): 

825 r""" 

826 ``coth(x)`` is the hyperbolic cotangent of ``x``. 

827 

828 The hyperbolic cotangent function is $\frac{\cosh(x)}{\sinh(x)}$. 

829 

830 Examples 

831 ======== 

832 

833 >>> from sympy import coth 

834 >>> from sympy.abc import x 

835 >>> coth(x) 

836 coth(x) 

837 

838 See Also 

839 ======== 

840 

841 sinh, cosh, acoth 

842 """ 

843 

844 def fdiff(self, argindex=1): 

845 if argindex == 1: 

846 return -1/sinh(self.args[0])**2 

847 else: 

848 raise ArgumentIndexError(self, argindex) 

849 

850 def inverse(self, argindex=1): 

851 """ 

852 Returns the inverse of this function. 

853 """ 

854 return acoth 

855 

856 @classmethod 

857 def eval(cls, arg): 

858 if arg.is_Number: 

859 if arg is S.NaN: 

860 return S.NaN 

861 elif arg is S.Infinity: 

862 return S.One 

863 elif arg is S.NegativeInfinity: 

864 return S.NegativeOne 

865 elif arg.is_zero: 

866 return S.ComplexInfinity 

867 elif arg.is_negative: 

868 return -cls(-arg) 

869 else: 

870 if arg is S.ComplexInfinity: 

871 return S.NaN 

872 

873 i_coeff = _imaginary_unit_as_coefficient(arg) 

874 

875 if i_coeff is not None: 

876 if i_coeff.could_extract_minus_sign(): 

877 return I * cot(-i_coeff) 

878 return -I * cot(i_coeff) 

879 else: 

880 if arg.could_extract_minus_sign(): 

881 return -cls(-arg) 

882 

883 if arg.is_Add: 

884 x, m = _peeloff_ipi(arg) 

885 if m: 

886 cothm = coth(m*pi*I) 

887 if cothm is S.ComplexInfinity: 

888 return coth(x) 

889 else: # cothm == 0 

890 return tanh(x) 

891 

892 if arg.is_zero: 

893 return S.ComplexInfinity 

894 

895 if arg.func == asinh: 

896 x = arg.args[0] 

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

898 

899 if arg.func == acosh: 

900 x = arg.args[0] 

901 return x/(sqrt(x - 1) * sqrt(x + 1)) 

902 

903 if arg.func == atanh: 

904 return 1/arg.args[0] 

905 

906 if arg.func == acoth: 

907 return arg.args[0] 

908 

909 @staticmethod 

910 @cacheit 

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

912 if n == 0: 

913 return 1 / sympify(x) 

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

915 return S.Zero 

916 else: 

917 x = sympify(x) 

918 

919 B = bernoulli(n + 1) 

920 F = factorial(n + 1) 

921 

922 return 2**(n + 1) * B/F * x**n 

923 

924 def _eval_conjugate(self): 

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

926 

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

928 from sympy.functions.elementary.trigonometric import (cos, sin) 

929 if self.args[0].is_extended_real: 

930 if deep: 

931 hints['complex'] = False 

932 return (self.expand(deep, **hints), S.Zero) 

933 else: 

934 return (self, S.Zero) 

935 if deep: 

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

937 else: 

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

939 denom = sinh(re)**2 + sin(im)**2 

940 return (sinh(re)*cosh(re)/denom, -sin(im)*cos(im)/denom) 

941 

942 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): 

943 neg_exp, pos_exp = exp(-arg), exp(arg) 

944 return (pos_exp + neg_exp)/(pos_exp - neg_exp) 

945 

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

947 neg_exp, pos_exp = exp(-arg), exp(arg) 

948 return (pos_exp + neg_exp)/(pos_exp - neg_exp) 

949 

950 def _eval_rewrite_as_sinh(self, arg, **kwargs): 

951 return -I*sinh(pi*I/2 - arg)/sinh(arg) 

952 

953 def _eval_rewrite_as_cosh(self, arg, **kwargs): 

954 return -I*cosh(arg)/cosh(pi*I/2 - arg) 

955 

956 def _eval_rewrite_as_tanh(self, arg, **kwargs): 

957 return 1/tanh(arg) 

958 

959 def _eval_is_positive(self): 

960 if self.args[0].is_extended_real: 

961 return self.args[0].is_positive 

962 

963 def _eval_is_negative(self): 

964 if self.args[0].is_extended_real: 

965 return self.args[0].is_negative 

966 

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

968 from sympy.series.order import Order 

969 arg = self.args[0].as_leading_term(x) 

970 

971 if x in arg.free_symbols and Order(1, x).contains(arg): 

972 return 1/arg 

973 else: 

974 return self.func(arg) 

975 

976 def _eval_expand_trig(self, **hints): 

977 arg = self.args[0] 

978 if arg.is_Add: 

979 CX = [coth(x, evaluate=False)._eval_expand_trig() for x in arg.args] 

980 p = [[], []] 

981 n = len(arg.args) 

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

983 p[(n - i) % 2].append(symmetric_poly(i, CX)) 

984 return Add(*p[0])/Add(*p[1]) 

985 elif arg.is_Mul: 

986 coeff, x = arg.as_coeff_Mul(rational=True) 

987 if coeff.is_Integer and coeff > 1: 

988 c = coth(x, evaluate=False) 

989 p = [[], []] 

990 for i in range(coeff, -1, -1): 

991 p[(coeff - i) % 2].append(binomial(coeff, i)*c**i) 

992 return Add(*p[0])/Add(*p[1]) 

993 return coth(arg) 

994 

995 

996class ReciprocalHyperbolicFunction(HyperbolicFunction): 

997 """Base class for reciprocal functions of hyperbolic functions. """ 

998 

999 #To be defined in class 

1000 _reciprocal_of = None 

1001 _is_even: FuzzyBool = None 

1002 _is_odd: FuzzyBool = None 

1003 

1004 @classmethod 

1005 def eval(cls, arg): 

1006 if arg.could_extract_minus_sign(): 

1007 if cls._is_even: 

1008 return cls(-arg) 

1009 if cls._is_odd: 

1010 return -cls(-arg) 

1011 

1012 t = cls._reciprocal_of.eval(arg) 

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

1014 return arg.args[0] 

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

1016 

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

1018 # Calls method_name on _reciprocal_of 

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

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

1021 

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

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

1024 # then return the reciprocal of that value 

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

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

1027 

1028 def _rewrite_reciprocal(self, method_name, arg): 

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

1030 # unmodified expression, then return None 

1031 t = self._call_reciprocal(method_name, arg) 

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

1033 return 1/t 

1034 

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

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

1037 

1038 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): 

1039 return self._rewrite_reciprocal("_eval_rewrite_as_tractable", arg) 

1040 

1041 def _eval_rewrite_as_tanh(self, arg, **kwargs): 

1042 return self._rewrite_reciprocal("_eval_rewrite_as_tanh", arg) 

1043 

1044 def _eval_rewrite_as_coth(self, arg, **kwargs): 

1045 return self._rewrite_reciprocal("_eval_rewrite_as_coth", arg) 

1046 

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

1048 return (1 / self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints) 

1049 

1050 def _eval_conjugate(self): 

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

1052 

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

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

1055 return re_part + I*im_part 

1056 

1057 def _eval_expand_trig(self, **hints): 

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

1059 

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

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

1062 

1063 def _eval_is_extended_real(self): 

1064 return self._reciprocal_of(self.args[0]).is_extended_real 

1065 

1066 def _eval_is_finite(self): 

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

1068 

1069 

1070class csch(ReciprocalHyperbolicFunction): 

1071 r""" 

1072 ``csch(x)`` is the hyperbolic cosecant of ``x``. 

1073 

1074 The hyperbolic cosecant function is $\frac{2}{e^x - e^{-x}}$ 

1075 

1076 Examples 

1077 ======== 

1078 

1079 >>> from sympy import csch 

1080 >>> from sympy.abc import x 

1081 >>> csch(x) 

1082 csch(x) 

1083 

1084 See Also 

1085 ======== 

1086 

1087 sinh, cosh, tanh, sech, asinh, acosh 

1088 """ 

1089 

1090 _reciprocal_of = sinh 

1091 _is_odd = True 

1092 

1093 def fdiff(self, argindex=1): 

1094 """ 

1095 Returns the first derivative of this function 

1096 """ 

1097 if argindex == 1: 

1098 return -coth(self.args[0]) * csch(self.args[0]) 

1099 else: 

1100 raise ArgumentIndexError(self, argindex) 

1101 

1102 @staticmethod 

1103 @cacheit 

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

1105 """ 

1106 Returns the next term in the Taylor series expansion 

1107 """ 

1108 if n == 0: 

1109 return 1/sympify(x) 

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

1111 return S.Zero 

1112 else: 

1113 x = sympify(x) 

1114 

1115 B = bernoulli(n + 1) 

1116 F = factorial(n + 1) 

1117 

1118 return 2 * (1 - 2**n) * B/F * x**n 

1119 

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

1121 return I / sin(I * arg) 

1122 

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

1124 return I * csc(I * arg) 

1125 

1126 def _eval_rewrite_as_cosh(self, arg, **kwargs): 

1127 return I / cosh(arg + I * pi / 2) 

1128 

1129 def _eval_rewrite_as_sinh(self, arg, **kwargs): 

1130 return 1 / sinh(arg) 

1131 

1132 def _eval_is_positive(self): 

1133 if self.args[0].is_extended_real: 

1134 return self.args[0].is_positive 

1135 

1136 def _eval_is_negative(self): 

1137 if self.args[0].is_extended_real: 

1138 return self.args[0].is_negative 

1139 

1140 

1141class sech(ReciprocalHyperbolicFunction): 

1142 r""" 

1143 ``sech(x)`` is the hyperbolic secant of ``x``. 

1144 

1145 The hyperbolic secant function is $\frac{2}{e^x + e^{-x}}$ 

1146 

1147 Examples 

1148 ======== 

1149 

1150 >>> from sympy import sech 

1151 >>> from sympy.abc import x 

1152 >>> sech(x) 

1153 sech(x) 

1154 

1155 See Also 

1156 ======== 

1157 

1158 sinh, cosh, tanh, coth, csch, asinh, acosh 

1159 """ 

1160 

1161 _reciprocal_of = cosh 

1162 _is_even = True 

1163 

1164 def fdiff(self, argindex=1): 

1165 if argindex == 1: 

1166 return - tanh(self.args[0])*sech(self.args[0]) 

1167 else: 

1168 raise ArgumentIndexError(self, argindex) 

1169 

1170 @staticmethod 

1171 @cacheit 

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

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

1174 return S.Zero 

1175 else: 

1176 x = sympify(x) 

1177 return euler(n) / factorial(n) * x**(n) 

1178 

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

1180 return 1 / cos(I * arg) 

1181 

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

1183 return sec(I * arg) 

1184 

1185 def _eval_rewrite_as_sinh(self, arg, **kwargs): 

1186 return I / sinh(arg + I * pi /2) 

1187 

1188 def _eval_rewrite_as_cosh(self, arg, **kwargs): 

1189 return 1 / cosh(arg) 

1190 

1191 def _eval_is_positive(self): 

1192 if self.args[0].is_extended_real: 

1193 return True 

1194 

1195 

1196############################################################################### 

1197############################# HYPERBOLIC INVERSES ############################# 

1198############################################################################### 

1199 

1200class InverseHyperbolicFunction(Function): 

1201 """Base class for inverse hyperbolic functions.""" 

1202 

1203 pass 

1204 

1205 

1206class asinh(InverseHyperbolicFunction): 

1207 """ 

1208 ``asinh(x)`` is the inverse hyperbolic sine of ``x``. 

1209 

1210 The inverse hyperbolic sine function. 

1211 

1212 Examples 

1213 ======== 

1214 

1215 >>> from sympy import asinh 

1216 >>> from sympy.abc import x 

1217 >>> asinh(x).diff(x) 

1218 1/sqrt(x**2 + 1) 

1219 >>> asinh(1) 

1220 log(1 + sqrt(2)) 

1221 

1222 See Also 

1223 ======== 

1224 

1225 acosh, atanh, sinh 

1226 """ 

1227 

1228 def fdiff(self, argindex=1): 

1229 if argindex == 1: 

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

1231 else: 

1232 raise ArgumentIndexError(self, argindex) 

1233 

1234 @classmethod 

1235 def eval(cls, arg): 

1236 if arg.is_Number: 

1237 if arg is S.NaN: 

1238 return S.NaN 

1239 elif arg is S.Infinity: 

1240 return S.Infinity 

1241 elif arg is S.NegativeInfinity: 

1242 return S.NegativeInfinity 

1243 elif arg.is_zero: 

1244 return S.Zero 

1245 elif arg is S.One: 

1246 return log(sqrt(2) + 1) 

1247 elif arg is S.NegativeOne: 

1248 return log(sqrt(2) - 1) 

1249 elif arg.is_negative: 

1250 return -cls(-arg) 

1251 else: 

1252 if arg is S.ComplexInfinity: 

1253 return S.ComplexInfinity 

1254 

1255 if arg.is_zero: 

1256 return S.Zero 

1257 

1258 i_coeff = _imaginary_unit_as_coefficient(arg) 

1259 

1260 if i_coeff is not None: 

1261 return I * asin(i_coeff) 

1262 else: 

1263 if arg.could_extract_minus_sign(): 

1264 return -cls(-arg) 

1265 

1266 if isinstance(arg, sinh) and arg.args[0].is_number: 

1267 z = arg.args[0] 

1268 if z.is_real: 

1269 return z 

1270 r, i = match_real_imag(z) 

1271 if r is not None and i is not None: 

1272 f = floor((i + pi/2)/pi) 

1273 m = z - I*pi*f 

1274 even = f.is_even 

1275 if even is True: 

1276 return m 

1277 elif even is False: 

1278 return -m 

1279 

1280 @staticmethod 

1281 @cacheit 

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

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

1284 return S.Zero 

1285 else: 

1286 x = sympify(x) 

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

1288 p = previous_terms[-2] 

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

1290 else: 

1291 k = (n - 1) // 2 

1292 R = RisingFactorial(S.Half, k) 

1293 F = factorial(k) 

1294 return S.NegativeOne**k * R / F * x**n / n 

1295 

1296 def _eval_as_leading_term(self, x, logx=None, cdir=0): # asinh 

1297 arg = self.args[0] 

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

1299 if x0.is_zero: 

1300 return arg.as_leading_term(x) 

1301 # Handling branch points 

1302 if x0 in (-I, I, S.ComplexInfinity): 

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

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

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

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

1307 if re(ndir).is_positive: 

1308 if im(x0).is_negative: 

1309 return -self.func(x0) - I*pi 

1310 elif re(ndir).is_negative: 

1311 if im(x0).is_positive: 

1312 return -self.func(x0) + I*pi 

1313 else: 

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

1315 return self.func(x0) 

1316 

1317 def _eval_nseries(self, x, n, logx, cdir=0): # asinh 

1318 arg = self.args[0] 

1319 arg0 = arg.subs(x, 0) 

1320 

1321 # Handling branch points 

1322 if arg0 in (I, -I): 

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

1324 

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

1326 if arg0 is S.ComplexInfinity: 

1327 return res 

1328 

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

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

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

1332 if re(ndir).is_positive: 

1333 if im(arg0).is_negative: 

1334 return -res - I*pi 

1335 elif re(ndir).is_negative: 

1336 if im(arg0).is_positive: 

1337 return -res + I*pi 

1338 else: 

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

1340 return res 

1341 

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

1343 return log(x + sqrt(x**2 + 1)) 

1344 

1345 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

1346 

1347 def _eval_rewrite_as_atanh(self, x, **kwargs): 

1348 return atanh(x/sqrt(1 + x**2)) 

1349 

1350 def _eval_rewrite_as_acosh(self, x, **kwargs): 

1351 ix = I*x 

1352 return I*(sqrt(1 - ix)/sqrt(ix - 1) * acosh(ix) - pi/2) 

1353 

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

1355 return -I * asin(I * x) 

1356 

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

1358 return I * acos(I * x) - I*pi/2 

1359 

1360 def inverse(self, argindex=1): 

1361 """ 

1362 Returns the inverse of this function. 

1363 """ 

1364 return sinh 

1365 

1366 def _eval_is_zero(self): 

1367 return self.args[0].is_zero 

1368 

1369 

1370class acosh(InverseHyperbolicFunction): 

1371 """ 

1372 ``acosh(x)`` is the inverse hyperbolic cosine of ``x``. 

1373 

1374 The inverse hyperbolic cosine function. 

1375 

1376 Examples 

1377 ======== 

1378 

1379 >>> from sympy import acosh 

1380 >>> from sympy.abc import x 

1381 >>> acosh(x).diff(x) 

1382 1/(sqrt(x - 1)*sqrt(x + 1)) 

1383 >>> acosh(1) 

1384 0 

1385 

1386 See Also 

1387 ======== 

1388 

1389 asinh, atanh, cosh 

1390 """ 

1391 

1392 def fdiff(self, argindex=1): 

1393 if argindex == 1: 

1394 arg = self.args[0] 

1395 return 1/(sqrt(arg - 1)*sqrt(arg + 1)) 

1396 else: 

1397 raise ArgumentIndexError(self, argindex) 

1398 

1399 @classmethod 

1400 def eval(cls, arg): 

1401 if arg.is_Number: 

1402 if arg is S.NaN: 

1403 return S.NaN 

1404 elif arg is S.Infinity: 

1405 return S.Infinity 

1406 elif arg is S.NegativeInfinity: 

1407 return S.Infinity 

1408 elif arg.is_zero: 

1409 return pi*I / 2 

1410 elif arg is S.One: 

1411 return S.Zero 

1412 elif arg is S.NegativeOne: 

1413 return pi*I 

1414 

1415 if arg.is_number: 

1416 cst_table = _acosh_table() 

1417 

1418 if arg in cst_table: 

1419 if arg.is_extended_real: 

1420 return cst_table[arg]*I 

1421 return cst_table[arg] 

1422 

1423 if arg is S.ComplexInfinity: 

1424 return S.ComplexInfinity 

1425 if arg == I*S.Infinity: 

1426 return S.Infinity + I*pi/2 

1427 if arg == -I*S.Infinity: 

1428 return S.Infinity - I*pi/2 

1429 

1430 if arg.is_zero: 

1431 return pi*I*S.Half 

1432 

1433 if isinstance(arg, cosh) and arg.args[0].is_number: 

1434 z = arg.args[0] 

1435 if z.is_real: 

1436 return Abs(z) 

1437 r, i = match_real_imag(z) 

1438 if r is not None and i is not None: 

1439 f = floor(i/pi) 

1440 m = z - I*pi*f 

1441 even = f.is_even 

1442 if even is True: 

1443 if r.is_nonnegative: 

1444 return m 

1445 elif r.is_negative: 

1446 return -m 

1447 elif even is False: 

1448 m -= I*pi 

1449 if r.is_nonpositive: 

1450 return -m 

1451 elif r.is_positive: 

1452 return m 

1453 

1454 @staticmethod 

1455 @cacheit 

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

1457 if n == 0: 

1458 return I*pi/2 

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

1460 return S.Zero 

1461 else: 

1462 x = sympify(x) 

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

1464 p = previous_terms[-2] 

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

1466 else: 

1467 k = (n - 1) // 2 

1468 R = RisingFactorial(S.Half, k) 

1469 F = factorial(k) 

1470 return -R / F * I * x**n / n 

1471 

1472 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acosh 

1473 arg = self.args[0] 

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

1475 # Handling branch points 

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

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

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

1479 if (x0 - 1).is_negative: 

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

1481 if im(ndir).is_negative: 

1482 if (x0 + 1).is_negative: 

1483 return self.func(x0) - 2*I*pi 

1484 return -self.func(x0) 

1485 elif not im(ndir).is_positive: 

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

1487 return self.func(x0) 

1488 

1489 def _eval_nseries(self, x, n, logx, cdir=0): # acosh 

1490 arg = self.args[0] 

1491 arg0 = arg.subs(x, 0) 

1492 

1493 # Handling branch points 

1494 if arg0 in (S.One, S.NegativeOne): 

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

1496 

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

1498 if arg0 is S.ComplexInfinity: 

1499 return res 

1500 

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

1502 if (arg0 - 1).is_negative: 

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

1504 if im(ndir).is_negative: 

1505 if (arg0 + 1).is_negative: 

1506 return res - 2*I*pi 

1507 return -res 

1508 elif not im(ndir).is_positive: 

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

1510 return res 

1511 

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

1513 return log(x + sqrt(x + 1) * sqrt(x - 1)) 

1514 

1515 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

1516 

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

1518 return sqrt(x - 1)/sqrt(1 - x) * acos(x) 

1519 

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

1521 return sqrt(x - 1)/sqrt(1 - x) * (pi/2 - asin(x)) 

1522 

1523 def _eval_rewrite_as_asinh(self, x, **kwargs): 

1524 return sqrt(x - 1)/sqrt(1 - x) * (pi/2 + I*asinh(I*x)) 

1525 

1526 def _eval_rewrite_as_atanh(self, x, **kwargs): 

1527 sxm1 = sqrt(x - 1) 

1528 s1mx = sqrt(1 - x) 

1529 sx2m1 = sqrt(x**2 - 1) 

1530 return (pi/2*sxm1/s1mx*(1 - x * sqrt(1/x**2)) + 

1531 sxm1*sqrt(x + 1)/sx2m1 * atanh(sx2m1/x)) 

1532 

1533 def inverse(self, argindex=1): 

1534 """ 

1535 Returns the inverse of this function. 

1536 """ 

1537 return cosh 

1538 

1539 def _eval_is_zero(self): 

1540 if (self.args[0] - 1).is_zero: 

1541 return True 

1542 

1543 

1544class atanh(InverseHyperbolicFunction): 

1545 """ 

1546 ``atanh(x)`` is the inverse hyperbolic tangent of ``x``. 

1547 

1548 The inverse hyperbolic tangent function. 

1549 

1550 Examples 

1551 ======== 

1552 

1553 >>> from sympy import atanh 

1554 >>> from sympy.abc import x 

1555 >>> atanh(x).diff(x) 

1556 1/(1 - x**2) 

1557 

1558 See Also 

1559 ======== 

1560 

1561 asinh, acosh, tanh 

1562 """ 

1563 

1564 def fdiff(self, argindex=1): 

1565 if argindex == 1: 

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

1567 else: 

1568 raise ArgumentIndexError(self, argindex) 

1569 

1570 @classmethod 

1571 def eval(cls, arg): 

1572 if arg.is_Number: 

1573 if arg is S.NaN: 

1574 return S.NaN 

1575 elif arg.is_zero: 

1576 return S.Zero 

1577 elif arg is S.One: 

1578 return S.Infinity 

1579 elif arg is S.NegativeOne: 

1580 return S.NegativeInfinity 

1581 elif arg is S.Infinity: 

1582 return -I * atan(arg) 

1583 elif arg is S.NegativeInfinity: 

1584 return I * atan(-arg) 

1585 elif arg.is_negative: 

1586 return -cls(-arg) 

1587 else: 

1588 if arg is S.ComplexInfinity: 

1589 from sympy.calculus.accumulationbounds import AccumBounds 

1590 return I*AccumBounds(-pi/2, pi/2) 

1591 

1592 i_coeff = _imaginary_unit_as_coefficient(arg) 

1593 

1594 if i_coeff is not None: 

1595 return I * atan(i_coeff) 

1596 else: 

1597 if arg.could_extract_minus_sign(): 

1598 return -cls(-arg) 

1599 

1600 if arg.is_zero: 

1601 return S.Zero 

1602 

1603 if isinstance(arg, tanh) and arg.args[0].is_number: 

1604 z = arg.args[0] 

1605 if z.is_real: 

1606 return z 

1607 r, i = match_real_imag(z) 

1608 if r is not None and i is not None: 

1609 f = floor(2*i/pi) 

1610 even = f.is_even 

1611 m = z - I*f*pi/2 

1612 if even is True: 

1613 return m 

1614 elif even is False: 

1615 return m - I*pi/2 

1616 

1617 @staticmethod 

1618 @cacheit 

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

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

1621 return S.Zero 

1622 else: 

1623 x = sympify(x) 

1624 return x**n / n 

1625 

1626 def _eval_as_leading_term(self, x, logx=None, cdir=0): # atanh 

1627 arg = self.args[0] 

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

1629 if x0.is_zero: 

1630 return arg.as_leading_term(x) 

1631 # Handling branch points 

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

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

1634 # Handling points lying on branch cuts (-oo, -1] U [1, oo) 

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

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

1637 if im(ndir).is_negative: 

1638 if x0.is_negative: 

1639 return self.func(x0) - I*pi 

1640 elif im(ndir).is_positive: 

1641 if x0.is_positive: 

1642 return self.func(x0) + I*pi 

1643 else: 

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

1645 return self.func(x0) 

1646 

1647 def _eval_nseries(self, x, n, logx, cdir=0): # atanh 

1648 arg = self.args[0] 

1649 arg0 = arg.subs(x, 0) 

1650 

1651 # Handling branch points 

1652 if arg0 in (S.One, S.NegativeOne): 

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

1654 

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

1656 if arg0 is S.ComplexInfinity: 

1657 return res 

1658 

1659 # Handling points lying on branch cuts (-oo, -1] U [1, oo) 

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

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

1662 if im(ndir).is_negative: 

1663 if arg0.is_negative: 

1664 return res - I*pi 

1665 elif im(ndir).is_positive: 

1666 if arg0.is_positive: 

1667 return res + I*pi 

1668 else: 

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

1670 return res 

1671 

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

1673 return (log(1 + x) - log(1 - x)) / 2 

1674 

1675 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

1676 

1677 def _eval_rewrite_as_asinh(self, x, **kwargs): 

1678 f = sqrt(1/(x**2 - 1)) 

1679 return (pi*x/(2*sqrt(-x**2)) - 

1680 sqrt(-x)*sqrt(1 - x**2)/sqrt(x)*f*asinh(f)) 

1681 

1682 def _eval_is_zero(self): 

1683 if self.args[0].is_zero: 

1684 return True 

1685 

1686 def _eval_is_imaginary(self): 

1687 return self.args[0].is_imaginary 

1688 

1689 def inverse(self, argindex=1): 

1690 """ 

1691 Returns the inverse of this function. 

1692 """ 

1693 return tanh 

1694 

1695 

1696class acoth(InverseHyperbolicFunction): 

1697 """ 

1698 ``acoth(x)`` is the inverse hyperbolic cotangent of ``x``. 

1699 

1700 The inverse hyperbolic cotangent function. 

1701 

1702 Examples 

1703 ======== 

1704 

1705 >>> from sympy import acoth 

1706 >>> from sympy.abc import x 

1707 >>> acoth(x).diff(x) 

1708 1/(1 - x**2) 

1709 

1710 See Also 

1711 ======== 

1712 

1713 asinh, acosh, coth 

1714 """ 

1715 

1716 def fdiff(self, argindex=1): 

1717 if argindex == 1: 

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

1719 else: 

1720 raise ArgumentIndexError(self, argindex) 

1721 

1722 @classmethod 

1723 def eval(cls, arg): 

1724 if arg.is_Number: 

1725 if arg is S.NaN: 

1726 return S.NaN 

1727 elif arg is S.Infinity: 

1728 return S.Zero 

1729 elif arg is S.NegativeInfinity: 

1730 return S.Zero 

1731 elif arg.is_zero: 

1732 return pi*I / 2 

1733 elif arg is S.One: 

1734 return S.Infinity 

1735 elif arg is S.NegativeOne: 

1736 return S.NegativeInfinity 

1737 elif arg.is_negative: 

1738 return -cls(-arg) 

1739 else: 

1740 if arg is S.ComplexInfinity: 

1741 return S.Zero 

1742 

1743 i_coeff = _imaginary_unit_as_coefficient(arg) 

1744 

1745 if i_coeff is not None: 

1746 return -I * acot(i_coeff) 

1747 else: 

1748 if arg.could_extract_minus_sign(): 

1749 return -cls(-arg) 

1750 

1751 if arg.is_zero: 

1752 return pi*I*S.Half 

1753 

1754 @staticmethod 

1755 @cacheit 

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

1757 if n == 0: 

1758 return -I*pi/2 

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

1760 return S.Zero 

1761 else: 

1762 x = sympify(x) 

1763 return x**n / n 

1764 

1765 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acoth 

1766 arg = self.args[0] 

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

1768 if x0 is S.ComplexInfinity: 

1769 return (1/arg).as_leading_term(x) 

1770 # Handling branch points 

1771 if x0 in (-S.One, S.One, S.Zero): 

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

1773 # Handling points lying on branch cuts [-1, 1] 

1774 if x0.is_real and (1 - x0**2).is_positive: 

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

1776 if im(ndir).is_negative: 

1777 if x0.is_positive: 

1778 return self.func(x0) + I*pi 

1779 elif im(ndir).is_positive: 

1780 if x0.is_negative: 

1781 return self.func(x0) - I*pi 

1782 else: 

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

1784 return self.func(x0) 

1785 

1786 def _eval_nseries(self, x, n, logx, cdir=0): # acoth 

1787 arg = self.args[0] 

1788 arg0 = arg.subs(x, 0) 

1789 

1790 # Handling branch points 

1791 if arg0 in (S.One, S.NegativeOne): 

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

1793 

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

1795 if arg0 is S.ComplexInfinity: 

1796 return res 

1797 

1798 # Handling points lying on branch cuts [-1, 1] 

1799 if arg0.is_real and (1 - arg0**2).is_positive: 

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

1801 if im(ndir).is_negative: 

1802 if arg0.is_positive: 

1803 return res + I*pi 

1804 elif im(ndir).is_positive: 

1805 if arg0.is_negative: 

1806 return res - I*pi 

1807 else: 

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

1809 return res 

1810 

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

1812 return (log(1 + 1/x) - log(1 - 1/x)) / 2 

1813 

1814 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

1815 

1816 def _eval_rewrite_as_atanh(self, x, **kwargs): 

1817 return atanh(1/x) 

1818 

1819 def _eval_rewrite_as_asinh(self, x, **kwargs): 

1820 return (pi*I/2*(sqrt((x - 1)/x)*sqrt(x/(x - 1)) - sqrt(1 + 1/x)*sqrt(x/(x + 1))) + 

1821 x*sqrt(1/x**2)*asinh(sqrt(1/(x**2 - 1)))) 

1822 

1823 def inverse(self, argindex=1): 

1824 """ 

1825 Returns the inverse of this function. 

1826 """ 

1827 return coth 

1828 

1829 

1830class asech(InverseHyperbolicFunction): 

1831 """ 

1832 ``asech(x)`` is the inverse hyperbolic secant of ``x``. 

1833 

1834 The inverse hyperbolic secant function. 

1835 

1836 Examples 

1837 ======== 

1838 

1839 >>> from sympy import asech, sqrt, S 

1840 >>> from sympy.abc import x 

1841 >>> asech(x).diff(x) 

1842 -1/(x*sqrt(1 - x**2)) 

1843 >>> asech(1).diff(x) 

1844 0 

1845 >>> asech(1) 

1846 0 

1847 >>> asech(S(2)) 

1848 I*pi/3 

1849 >>> asech(-sqrt(2)) 

1850 3*I*pi/4 

1851 >>> asech((sqrt(6) - sqrt(2))) 

1852 I*pi/12 

1853 

1854 See Also 

1855 ======== 

1856 

1857 asinh, atanh, cosh, acoth 

1858 

1859 References 

1860 ========== 

1861 

1862 .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function 

1863 .. [2] https://dlmf.nist.gov/4.37 

1864 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcSech/ 

1865 

1866 """ 

1867 

1868 def fdiff(self, argindex=1): 

1869 if argindex == 1: 

1870 z = self.args[0] 

1871 return -1/(z*sqrt(1 - z**2)) 

1872 else: 

1873 raise ArgumentIndexError(self, argindex) 

1874 

1875 @classmethod 

1876 def eval(cls, arg): 

1877 if arg.is_Number: 

1878 if arg is S.NaN: 

1879 return S.NaN 

1880 elif arg is S.Infinity: 

1881 return pi*I / 2 

1882 elif arg is S.NegativeInfinity: 

1883 return pi*I / 2 

1884 elif arg.is_zero: 

1885 return S.Infinity 

1886 elif arg is S.One: 

1887 return S.Zero 

1888 elif arg is S.NegativeOne: 

1889 return pi*I 

1890 

1891 if arg.is_number: 

1892 cst_table = _asech_table() 

1893 

1894 if arg in cst_table: 

1895 if arg.is_extended_real: 

1896 return cst_table[arg]*I 

1897 return cst_table[arg] 

1898 

1899 if arg is S.ComplexInfinity: 

1900 from sympy.calculus.accumulationbounds import AccumBounds 

1901 return I*AccumBounds(-pi/2, pi/2) 

1902 

1903 if arg.is_zero: 

1904 return S.Infinity 

1905 

1906 @staticmethod 

1907 @cacheit 

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

1909 if n == 0: 

1910 return log(2 / x) 

1911 elif n < 0 or n % 2 == 1: 

1912 return S.Zero 

1913 else: 

1914 x = sympify(x) 

1915 if len(previous_terms) > 2 and n > 2: 

1916 p = previous_terms[-2] 

1917 return p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2) 

1918 else: 

1919 k = n // 2 

1920 R = RisingFactorial(S.Half, k) * n 

1921 F = factorial(k) * n // 2 * n // 2 

1922 return -1 * R / F * x**n / 4 

1923 

1924 def _eval_as_leading_term(self, x, logx=None, cdir=0): # asech 

1925 arg = self.args[0] 

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

1927 # Handling branch points 

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

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

1930 # Handling points lying on branch cuts (-oo, 0] U (1, oo) 

1931 if x0.is_negative or (1 - x0).is_negative: 

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

1933 if im(ndir).is_positive: 

1934 if x0.is_positive or (x0 + 1).is_negative: 

1935 return -self.func(x0) 

1936 return self.func(x0) - 2*I*pi 

1937 elif not im(ndir).is_negative: 

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

1939 return self.func(x0) 

1940 

1941 def _eval_nseries(self, x, n, logx, cdir=0): # asech 

1942 from sympy.series.order import O 

1943 arg = self.args[0] 

1944 arg0 = arg.subs(x, 0) 

1945 

1946 # Handling branch points 

1947 if arg0 is S.One: 

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

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

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

1951 f = arg1.as_leading_term(x) 

1952 g = (arg1 - f)/ f 

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

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

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

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

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

1958 

1959 if arg0 is S.NegativeOne: 

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

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

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

1963 f = arg1.as_leading_term(x) 

1964 g = (arg1 - f)/ f 

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

1966 return O(1) if n == 0 else I*pi + O(sqrt(x)) 

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

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

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

1970 

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

1972 if arg0 is S.ComplexInfinity: 

1973 return res 

1974 

1975 # Handling points lying on branch cuts (-oo, 0] U (1, oo) 

1976 if arg0.is_negative or (1 - arg0).is_negative: 

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

1978 if im(ndir).is_positive: 

1979 if arg0.is_positive or (arg0 + 1).is_negative: 

1980 return -res 

1981 return res - 2*I*pi 

1982 elif not im(ndir).is_negative: 

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

1984 return res 

1985 

1986 def inverse(self, argindex=1): 

1987 """ 

1988 Returns the inverse of this function. 

1989 """ 

1990 return sech 

1991 

1992 def _eval_rewrite_as_log(self, arg, **kwargs): 

1993 return log(1/arg + sqrt(1/arg - 1) * sqrt(1/arg + 1)) 

1994 

1995 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

1996 

1997 def _eval_rewrite_as_acosh(self, arg, **kwargs): 

1998 return acosh(1/arg) 

1999 

2000 def _eval_rewrite_as_asinh(self, arg, **kwargs): 

2001 return sqrt(1/arg - 1)/sqrt(1 - 1/arg)*(I*asinh(I/arg) 

2002 + pi*S.Half) 

2003 

2004 def _eval_rewrite_as_atanh(self, x, **kwargs): 

2005 return (I*pi*(1 - sqrt(x)*sqrt(1/x) - I/2*sqrt(-x)/sqrt(x) - I/2*sqrt(x**2)/sqrt(-x**2)) 

2006 + sqrt(1/(x + 1))*sqrt(x + 1)*atanh(sqrt(1 - x**2))) 

2007 

2008 def _eval_rewrite_as_acsch(self, x, **kwargs): 

2009 return sqrt(1/x - 1)/sqrt(1 - 1/x)*(pi/2 - I*acsch(I*x)) 

2010 

2011 

2012class acsch(InverseHyperbolicFunction): 

2013 """ 

2014 ``acsch(x)`` is the inverse hyperbolic cosecant of ``x``. 

2015 

2016 The inverse hyperbolic cosecant function. 

2017 

2018 Examples 

2019 ======== 

2020 

2021 >>> from sympy import acsch, sqrt, I 

2022 >>> from sympy.abc import x 

2023 >>> acsch(x).diff(x) 

2024 -1/(x**2*sqrt(1 + x**(-2))) 

2025 >>> acsch(1).diff(x) 

2026 0 

2027 >>> acsch(1) 

2028 log(1 + sqrt(2)) 

2029 >>> acsch(I) 

2030 -I*pi/2 

2031 >>> acsch(-2*I) 

2032 I*pi/6 

2033 >>> acsch(I*(sqrt(6) - sqrt(2))) 

2034 -5*I*pi/12 

2035 

2036 See Also 

2037 ======== 

2038 

2039 asinh 

2040 

2041 References 

2042 ========== 

2043 

2044 .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function 

2045 .. [2] https://dlmf.nist.gov/4.37 

2046 .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcCsch/ 

2047 

2048 """ 

2049 

2050 def fdiff(self, argindex=1): 

2051 if argindex == 1: 

2052 z = self.args[0] 

2053 return -1/(z**2*sqrt(1 + 1/z**2)) 

2054 else: 

2055 raise ArgumentIndexError(self, argindex) 

2056 

2057 @classmethod 

2058 def eval(cls, arg): 

2059 if arg.is_Number: 

2060 if arg is S.NaN: 

2061 return S.NaN 

2062 elif arg is S.Infinity: 

2063 return S.Zero 

2064 elif arg is S.NegativeInfinity: 

2065 return S.Zero 

2066 elif arg.is_zero: 

2067 return S.ComplexInfinity 

2068 elif arg is S.One: 

2069 return log(1 + sqrt(2)) 

2070 elif arg is S.NegativeOne: 

2071 return - log(1 + sqrt(2)) 

2072 

2073 if arg.is_number: 

2074 cst_table = _acsch_table() 

2075 

2076 if arg in cst_table: 

2077 return cst_table[arg]*I 

2078 

2079 if arg is S.ComplexInfinity: 

2080 return S.Zero 

2081 

2082 if arg.is_infinite: 

2083 return S.Zero 

2084 

2085 if arg.is_zero: 

2086 return S.ComplexInfinity 

2087 

2088 if arg.could_extract_minus_sign(): 

2089 return -cls(-arg) 

2090 

2091 @staticmethod 

2092 @cacheit 

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

2094 if n == 0: 

2095 return log(2 / x) 

2096 elif n < 0 or n % 2 == 1: 

2097 return S.Zero 

2098 else: 

2099 x = sympify(x) 

2100 if len(previous_terms) > 2 and n > 2: 

2101 p = previous_terms[-2] 

2102 return -p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2) 

2103 else: 

2104 k = n // 2 

2105 R = RisingFactorial(S.Half, k) * n 

2106 F = factorial(k) * n // 2 * n // 2 

2107 return S.NegativeOne**(k +1) * R / F * x**n / 4 

2108 

2109 def _eval_as_leading_term(self, x, logx=None, cdir=0): # acsch 

2110 arg = self.args[0] 

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

2112 # Handling branch points 

2113 if x0 in (-I, I, S.Zero): 

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

2115 if x0 is S.ComplexInfinity: 

2116 return (1/arg).as_leading_term(x) 

2117 # Handling points lying on branch cuts (-I, I) 

2118 if x0.is_imaginary and (1 + x0**2).is_positive: 

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

2120 if re(ndir).is_positive: 

2121 if im(x0).is_positive: 

2122 return -self.func(x0) - I*pi 

2123 elif re(ndir).is_negative: 

2124 if im(x0).is_negative: 

2125 return -self.func(x0) + I*pi 

2126 else: 

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

2128 return self.func(x0) 

2129 

2130 def _eval_nseries(self, x, n, logx, cdir=0): # acsch 

2131 from sympy.series.order import O 

2132 arg = self.args[0] 

2133 arg0 = arg.subs(x, 0) 

2134 

2135 # Handling branch points 

2136 if arg0 is I: 

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

2138 ser = acsch(I + t**2).rewrite(log).nseries(t, 0, 2*n) 

2139 arg1 = -I + self.args[0] 

2140 f = arg1.as_leading_term(x) 

2141 g = (arg1 - f)/ f 

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

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

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

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

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

2147 return res 

2148 

2149 if arg0 == S.NegativeOne*I: 

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

2151 ser = acsch(-I + t**2).rewrite(log).nseries(t, 0, 2*n) 

2152 arg1 = I + self.args[0] 

2153 f = arg1.as_leading_term(x) 

2154 g = (arg1 - f)/ f 

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

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

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

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

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

2160 

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

2162 if arg0 is S.ComplexInfinity: 

2163 return res 

2164 

2165 # Handling points lying on branch cuts (-I, I) 

2166 if arg0.is_imaginary and (1 + arg0**2).is_positive: 

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

2168 if re(ndir).is_positive: 

2169 if im(arg0).is_positive: 

2170 return -res - I*pi 

2171 elif re(ndir).is_negative: 

2172 if im(arg0).is_negative: 

2173 return -res + I*pi 

2174 else: 

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

2176 return res 

2177 

2178 def inverse(self, argindex=1): 

2179 """ 

2180 Returns the inverse of this function. 

2181 """ 

2182 return csch 

2183 

2184 def _eval_rewrite_as_log(self, arg, **kwargs): 

2185 return log(1/arg + sqrt(1/arg**2 + 1)) 

2186 

2187 _eval_rewrite_as_tractable = _eval_rewrite_as_log 

2188 

2189 def _eval_rewrite_as_asinh(self, arg, **kwargs): 

2190 return asinh(1/arg) 

2191 

2192 def _eval_rewrite_as_acosh(self, arg, **kwargs): 

2193 return I*(sqrt(1 - I/arg)/sqrt(I/arg - 1)* 

2194 acosh(I/arg) - pi*S.Half) 

2195 

2196 def _eval_rewrite_as_atanh(self, arg, **kwargs): 

2197 arg2 = arg**2 

2198 arg2p1 = arg2 + 1 

2199 return sqrt(-arg2)/arg*(pi*S.Half - 

2200 sqrt(-arg2p1**2)/arg2p1*atanh(sqrt(arg2p1))) 

2201 

2202 def _eval_is_zero(self): 

2203 return self.args[0].is_infinite