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
« 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
20def _rewrite_hyperbolics_as_exp(expr):
21 return expr.xreplace({h: h.rewrite(exp)
22 for h in expr.atoms(HyperbolicFunction)})
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 }
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 }
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 }
101###############################################################################
102########################### HYPERBOLIC FUNCTIONS ##############################
103###############################################################################
106class HyperbolicFunction(Function):
107 """
108 Base class for hyperbolic functions.
110 See Also
111 ========
113 sinh, cosh, tanh, coth
114 """
116 unbranched = True
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``.
125 Examples
126 ========
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
148 m1 = (K % S.Half)
149 m2 = K - m1
150 return arg - m2*ipi, m2
153class sinh(HyperbolicFunction):
154 r"""
155 ``sinh(x)`` is the hyperbolic sine of ``x``.
157 The hyperbolic sine function is $\frac{e^x - e^{-x}}{2}$.
159 Examples
160 ========
162 >>> from sympy import sinh
163 >>> from sympy.abc import x
164 >>> sinh(x)
165 sinh(x)
167 See Also
168 ========
170 cosh, tanh, asinh
171 """
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)
182 def inverse(self, argindex=1):
183 """
184 Returns the inverse of this function.
185 """
186 return asinh
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
205 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
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)
219 if arg.is_zero:
220 return S.Zero
222 if arg.func == asinh:
223 return arg.args[0]
225 if arg.func == acosh:
226 x = arg.args[0]
227 return sqrt(x - 1) * sqrt(x + 1)
229 if arg.func == atanh:
230 x = arg.args[0]
231 return x/sqrt(1 - x**2)
233 if arg.func == acoth:
234 x = arg.args[0]
235 return 1/(sqrt(x - 1) * sqrt(x + 1))
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)
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)
254 def _eval_conjugate(self):
255 return self.func(self.args[0].conjugate())
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))
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
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)
294 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
295 return (exp(arg) - exp(-arg)) / 2
297 def _eval_rewrite_as_exp(self, arg, **kwargs):
298 return (exp(arg) - exp(-arg)) / 2
300 def _eval_rewrite_as_sin(self, arg, **kwargs):
301 return -I * sin(I * arg)
303 def _eval_rewrite_as_csc(self, arg, **kwargs):
304 return -I / csc(I * arg)
306 def _eval_rewrite_as_cosh(self, arg, **kwargs):
307 return -I*cosh(arg + pi*I/2)
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)
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)
317 def _eval_rewrite_as_csch(self, arg, **kwargs):
318 return 1 / csch(arg)
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)
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
333 def _eval_is_real(self):
334 arg = self.args[0]
335 if arg.is_real:
336 return True
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
343 def _eval_is_extended_real(self):
344 if self.args[0].is_extended_real:
345 return True
347 def _eval_is_positive(self):
348 if self.args[0].is_extended_real:
349 return self.args[0].is_positive
351 def _eval_is_negative(self):
352 if self.args[0].is_extended_real:
353 return self.args[0].is_negative
355 def _eval_is_finite(self):
356 arg = self.args[0]
357 return arg.is_finite
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
365class cosh(HyperbolicFunction):
366 r"""
367 ``cosh(x)`` is the hyperbolic cosine of ``x``.
369 The hyperbolic cosine function is $\frac{e^x + e^{-x}}{2}$.
371 Examples
372 ========
374 >>> from sympy import cosh
375 >>> from sympy.abc import x
376 >>> cosh(x)
377 cosh(x)
379 See Also
380 ========
382 sinh, tanh, acosh
383 """
385 def fdiff(self, argindex=1):
386 if argindex == 1:
387 return sinh(self.args[0])
388 else:
389 raise ArgumentIndexError(self, argindex)
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
409 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
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)
423 if arg.is_zero:
424 return S.One
426 if arg.func == asinh:
427 return sqrt(1 + arg.args[0]**2)
429 if arg.func == acosh:
430 return arg.args[0]
432 if arg.func == atanh:
433 return 1/sqrt(1 - arg.args[0]**2)
435 if arg.func == acoth:
436 x = arg.args[0]
437 return x/(sqrt(x - 1) * sqrt(x + 1))
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)
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)
453 def _eval_conjugate(self):
454 return self.func(self.args[0].conjugate())
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()
468 return (cosh(re)*cos(im), sinh(re)*sin(im))
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
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)
491 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
492 return (exp(arg) + exp(-arg)) / 2
494 def _eval_rewrite_as_exp(self, arg, **kwargs):
495 return (exp(arg) + exp(-arg)) / 2
497 def _eval_rewrite_as_cos(self, arg, **kwargs):
498 return cos(I * arg)
500 def _eval_rewrite_as_sec(self, arg, **kwargs):
501 return 1 / sec(I * arg)
503 def _eval_rewrite_as_sinh(self, arg, **kwargs):
504 return -I*sinh(arg + pi*I/2)
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)
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)
514 def _eval_rewrite_as_sech(self, arg, **kwargs):
515 return 1 / sech(arg)
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)
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
530 def _eval_is_real(self):
531 arg = self.args[0]
533 # `cosh(x)` is real for real OR purely imaginary `x`
534 if arg.is_real or arg.is_imaginary:
535 return True
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
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]
551 x, y = z.as_real_imag()
552 ymod = y % (2*pi)
554 yzero = ymod.is_zero
555 # shortcut if ymod is zero
556 if yzero:
557 return True
559 xzero = x.is_zero
560 # shortcut x is not zero
561 if xzero is False:
562 return yzero
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 ])
575 def _eval_is_nonnegative(self):
576 z = self.args[0]
578 x, y = z.as_real_imag()
579 ymod = y % (2*pi)
581 yzero = ymod.is_zero
582 # shortcut if ymod is zero
583 if yzero:
584 return True
586 xzero = x.is_zero
587 # shortcut x is not zero
588 if xzero is False:
589 return yzero
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 ])
601 def _eval_is_finite(self):
602 arg = self.args[0]
603 return arg.is_finite
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
611class tanh(HyperbolicFunction):
612 r"""
613 ``tanh(x)`` is the hyperbolic tangent of ``x``.
615 The hyperbolic tangent function is $\frac{\sinh(x)}{\cosh(x)}$.
617 Examples
618 ========
620 >>> from sympy import tanh
621 >>> from sympy.abc import x
622 >>> tanh(x)
623 tanh(x)
625 See Also
626 ========
628 sinh, cosh, atanh
629 """
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)
637 def inverse(self, argindex=1):
638 """
639 Returns the inverse of this function.
640 """
641 return atanh
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
660 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
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)
679 if arg.is_zero:
680 return S.Zero
682 if arg.func == asinh:
683 x = arg.args[0]
684 return x/sqrt(1 + x**2)
686 if arg.func == acosh:
687 x = arg.args[0]
688 return sqrt(x - 1) * sqrt(x + 1) / x
690 if arg.func == atanh:
691 return arg.args[0]
693 if arg.func == acoth:
694 return 1/arg.args[0]
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)
704 a = 2**(n + 1)
706 B = bernoulli(n + 1)
707 F = factorial(n + 1)
709 return a*(a - 1) * B/F * x**n
711 def _eval_conjugate(self):
712 return self.func(self.args[0].conjugate())
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)
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)
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)
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)
755 def _eval_rewrite_as_tan(self, arg, **kwargs):
756 return -I * tan(I * arg)
758 def _eval_rewrite_as_cot(self, arg, **kwargs):
759 return -I / cot(I * arg)
761 def _eval_rewrite_as_sinh(self, arg, **kwargs):
762 return I*sinh(arg)/sinh(pi*I/2 - arg)
764 def _eval_rewrite_as_cosh(self, arg, **kwargs):
765 return I*cosh(pi*I/2 - arg)/cosh(arg)
767 def _eval_rewrite_as_coth(self, arg, **kwargs):
768 return 1/coth(arg)
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)
774 if x in arg.free_symbols and Order(1, x).contains(arg):
775 return arg
776 else:
777 return self.func(arg)
779 def _eval_is_real(self):
780 arg = self.args[0]
781 if arg.is_real:
782 return True
784 re, im = arg.as_real_imag()
786 # if denom = 0, tanh(arg) = zoo
787 if re == 0 and im % pi == pi/2:
788 return None
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
794 def _eval_is_extended_real(self):
795 if self.args[0].is_extended_real:
796 return True
798 def _eval_is_positive(self):
799 if self.args[0].is_extended_real:
800 return self.args[0].is_positive
802 def _eval_is_negative(self):
803 if self.args[0].is_extended_real:
804 return self.args[0].is_negative
806 def _eval_is_finite(self):
807 arg = self.args[0]
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
818 def _eval_is_zero(self):
819 arg = self.args[0]
820 if arg.is_zero:
821 return True
824class coth(HyperbolicFunction):
825 r"""
826 ``coth(x)`` is the hyperbolic cotangent of ``x``.
828 The hyperbolic cotangent function is $\frac{\cosh(x)}{\sinh(x)}$.
830 Examples
831 ========
833 >>> from sympy import coth
834 >>> from sympy.abc import x
835 >>> coth(x)
836 coth(x)
838 See Also
839 ========
841 sinh, cosh, acoth
842 """
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)
850 def inverse(self, argindex=1):
851 """
852 Returns the inverse of this function.
853 """
854 return acoth
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
873 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
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)
892 if arg.is_zero:
893 return S.ComplexInfinity
895 if arg.func == asinh:
896 x = arg.args[0]
897 return sqrt(1 + x**2)/x
899 if arg.func == acosh:
900 x = arg.args[0]
901 return x/(sqrt(x - 1) * sqrt(x + 1))
903 if arg.func == atanh:
904 return 1/arg.args[0]
906 if arg.func == acoth:
907 return arg.args[0]
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)
919 B = bernoulli(n + 1)
920 F = factorial(n + 1)
922 return 2**(n + 1) * B/F * x**n
924 def _eval_conjugate(self):
925 return self.func(self.args[0].conjugate())
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)
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)
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)
950 def _eval_rewrite_as_sinh(self, arg, **kwargs):
951 return -I*sinh(pi*I/2 - arg)/sinh(arg)
953 def _eval_rewrite_as_cosh(self, arg, **kwargs):
954 return -I*cosh(arg)/cosh(pi*I/2 - arg)
956 def _eval_rewrite_as_tanh(self, arg, **kwargs):
957 return 1/tanh(arg)
959 def _eval_is_positive(self):
960 if self.args[0].is_extended_real:
961 return self.args[0].is_positive
963 def _eval_is_negative(self):
964 if self.args[0].is_extended_real:
965 return self.args[0].is_negative
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)
971 if x in arg.free_symbols and Order(1, x).contains(arg):
972 return 1/arg
973 else:
974 return self.func(arg)
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)
996class ReciprocalHyperbolicFunction(HyperbolicFunction):
997 """Base class for reciprocal functions of hyperbolic functions. """
999 #To be defined in class
1000 _reciprocal_of = None
1001 _is_even: FuzzyBool = None
1002 _is_odd: FuzzyBool = None
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)
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
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)
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
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
1035 def _eval_rewrite_as_exp(self, arg, **kwargs):
1036 return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg)
1038 def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
1039 return self._rewrite_reciprocal("_eval_rewrite_as_tractable", arg)
1041 def _eval_rewrite_as_tanh(self, arg, **kwargs):
1042 return self._rewrite_reciprocal("_eval_rewrite_as_tanh", arg)
1044 def _eval_rewrite_as_coth(self, arg, **kwargs):
1045 return self._rewrite_reciprocal("_eval_rewrite_as_coth", arg)
1047 def as_real_imag(self, deep = True, **hints):
1048 return (1 / self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints)
1050 def _eval_conjugate(self):
1051 return self.func(self.args[0].conjugate())
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
1057 def _eval_expand_trig(self, **hints):
1058 return self._calculate_reciprocal("_eval_expand_trig", **hints)
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)
1063 def _eval_is_extended_real(self):
1064 return self._reciprocal_of(self.args[0]).is_extended_real
1066 def _eval_is_finite(self):
1067 return (1/self._reciprocal_of(self.args[0])).is_finite
1070class csch(ReciprocalHyperbolicFunction):
1071 r"""
1072 ``csch(x)`` is the hyperbolic cosecant of ``x``.
1074 The hyperbolic cosecant function is $\frac{2}{e^x - e^{-x}}$
1076 Examples
1077 ========
1079 >>> from sympy import csch
1080 >>> from sympy.abc import x
1081 >>> csch(x)
1082 csch(x)
1084 See Also
1085 ========
1087 sinh, cosh, tanh, sech, asinh, acosh
1088 """
1090 _reciprocal_of = sinh
1091 _is_odd = True
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)
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)
1115 B = bernoulli(n + 1)
1116 F = factorial(n + 1)
1118 return 2 * (1 - 2**n) * B/F * x**n
1120 def _eval_rewrite_as_sin(self, arg, **kwargs):
1121 return I / sin(I * arg)
1123 def _eval_rewrite_as_csc(self, arg, **kwargs):
1124 return I * csc(I * arg)
1126 def _eval_rewrite_as_cosh(self, arg, **kwargs):
1127 return I / cosh(arg + I * pi / 2)
1129 def _eval_rewrite_as_sinh(self, arg, **kwargs):
1130 return 1 / sinh(arg)
1132 def _eval_is_positive(self):
1133 if self.args[0].is_extended_real:
1134 return self.args[0].is_positive
1136 def _eval_is_negative(self):
1137 if self.args[0].is_extended_real:
1138 return self.args[0].is_negative
1141class sech(ReciprocalHyperbolicFunction):
1142 r"""
1143 ``sech(x)`` is the hyperbolic secant of ``x``.
1145 The hyperbolic secant function is $\frac{2}{e^x + e^{-x}}$
1147 Examples
1148 ========
1150 >>> from sympy import sech
1151 >>> from sympy.abc import x
1152 >>> sech(x)
1153 sech(x)
1155 See Also
1156 ========
1158 sinh, cosh, tanh, coth, csch, asinh, acosh
1159 """
1161 _reciprocal_of = cosh
1162 _is_even = True
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)
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)
1179 def _eval_rewrite_as_cos(self, arg, **kwargs):
1180 return 1 / cos(I * arg)
1182 def _eval_rewrite_as_sec(self, arg, **kwargs):
1183 return sec(I * arg)
1185 def _eval_rewrite_as_sinh(self, arg, **kwargs):
1186 return I / sinh(arg + I * pi /2)
1188 def _eval_rewrite_as_cosh(self, arg, **kwargs):
1189 return 1 / cosh(arg)
1191 def _eval_is_positive(self):
1192 if self.args[0].is_extended_real:
1193 return True
1196###############################################################################
1197############################# HYPERBOLIC INVERSES #############################
1198###############################################################################
1200class InverseHyperbolicFunction(Function):
1201 """Base class for inverse hyperbolic functions."""
1203 pass
1206class asinh(InverseHyperbolicFunction):
1207 """
1208 ``asinh(x)`` is the inverse hyperbolic sine of ``x``.
1210 The inverse hyperbolic sine function.
1212 Examples
1213 ========
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))
1222 See Also
1223 ========
1225 acosh, atanh, sinh
1226 """
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)
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
1255 if arg.is_zero:
1256 return S.Zero
1258 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
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
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
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)
1317 def _eval_nseries(self, x, n, logx, cdir=0): # asinh
1318 arg = self.args[0]
1319 arg0 = arg.subs(x, 0)
1321 # Handling branch points
1322 if arg0 in (I, -I):
1323 return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1325 res = Function._eval_nseries(self, x, n=n, logx=logx)
1326 if arg0 is S.ComplexInfinity:
1327 return res
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
1342 def _eval_rewrite_as_log(self, x, **kwargs):
1343 return log(x + sqrt(x**2 + 1))
1345 _eval_rewrite_as_tractable = _eval_rewrite_as_log
1347 def _eval_rewrite_as_atanh(self, x, **kwargs):
1348 return atanh(x/sqrt(1 + x**2))
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)
1354 def _eval_rewrite_as_asin(self, x, **kwargs):
1355 return -I * asin(I * x)
1357 def _eval_rewrite_as_acos(self, x, **kwargs):
1358 return I * acos(I * x) - I*pi/2
1360 def inverse(self, argindex=1):
1361 """
1362 Returns the inverse of this function.
1363 """
1364 return sinh
1366 def _eval_is_zero(self):
1367 return self.args[0].is_zero
1370class acosh(InverseHyperbolicFunction):
1371 """
1372 ``acosh(x)`` is the inverse hyperbolic cosine of ``x``.
1374 The inverse hyperbolic cosine function.
1376 Examples
1377 ========
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
1386 See Also
1387 ========
1389 asinh, atanh, cosh
1390 """
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)
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
1415 if arg.is_number:
1416 cst_table = _acosh_table()
1418 if arg in cst_table:
1419 if arg.is_extended_real:
1420 return cst_table[arg]*I
1421 return cst_table[arg]
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
1430 if arg.is_zero:
1431 return pi*I*S.Half
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
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
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)
1489 def _eval_nseries(self, x, n, logx, cdir=0): # acosh
1490 arg = self.args[0]
1491 arg0 = arg.subs(x, 0)
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)
1497 res = Function._eval_nseries(self, x, n=n, logx=logx)
1498 if arg0 is S.ComplexInfinity:
1499 return res
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
1512 def _eval_rewrite_as_log(self, x, **kwargs):
1513 return log(x + sqrt(x + 1) * sqrt(x - 1))
1515 _eval_rewrite_as_tractable = _eval_rewrite_as_log
1517 def _eval_rewrite_as_acos(self, x, **kwargs):
1518 return sqrt(x - 1)/sqrt(1 - x) * acos(x)
1520 def _eval_rewrite_as_asin(self, x, **kwargs):
1521 return sqrt(x - 1)/sqrt(1 - x) * (pi/2 - asin(x))
1523 def _eval_rewrite_as_asinh(self, x, **kwargs):
1524 return sqrt(x - 1)/sqrt(1 - x) * (pi/2 + I*asinh(I*x))
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))
1533 def inverse(self, argindex=1):
1534 """
1535 Returns the inverse of this function.
1536 """
1537 return cosh
1539 def _eval_is_zero(self):
1540 if (self.args[0] - 1).is_zero:
1541 return True
1544class atanh(InverseHyperbolicFunction):
1545 """
1546 ``atanh(x)`` is the inverse hyperbolic tangent of ``x``.
1548 The inverse hyperbolic tangent function.
1550 Examples
1551 ========
1553 >>> from sympy import atanh
1554 >>> from sympy.abc import x
1555 >>> atanh(x).diff(x)
1556 1/(1 - x**2)
1558 See Also
1559 ========
1561 asinh, acosh, tanh
1562 """
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)
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)
1592 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
1600 if arg.is_zero:
1601 return S.Zero
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
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
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)
1647 def _eval_nseries(self, x, n, logx, cdir=0): # atanh
1648 arg = self.args[0]
1649 arg0 = arg.subs(x, 0)
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)
1655 res = Function._eval_nseries(self, x, n=n, logx=logx)
1656 if arg0 is S.ComplexInfinity:
1657 return res
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
1672 def _eval_rewrite_as_log(self, x, **kwargs):
1673 return (log(1 + x) - log(1 - x)) / 2
1675 _eval_rewrite_as_tractable = _eval_rewrite_as_log
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))
1682 def _eval_is_zero(self):
1683 if self.args[0].is_zero:
1684 return True
1686 def _eval_is_imaginary(self):
1687 return self.args[0].is_imaginary
1689 def inverse(self, argindex=1):
1690 """
1691 Returns the inverse of this function.
1692 """
1693 return tanh
1696class acoth(InverseHyperbolicFunction):
1697 """
1698 ``acoth(x)`` is the inverse hyperbolic cotangent of ``x``.
1700 The inverse hyperbolic cotangent function.
1702 Examples
1703 ========
1705 >>> from sympy import acoth
1706 >>> from sympy.abc import x
1707 >>> acoth(x).diff(x)
1708 1/(1 - x**2)
1710 See Also
1711 ========
1713 asinh, acosh, coth
1714 """
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)
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
1743 i_coeff = _imaginary_unit_as_coefficient(arg)
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)
1751 if arg.is_zero:
1752 return pi*I*S.Half
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
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)
1786 def _eval_nseries(self, x, n, logx, cdir=0): # acoth
1787 arg = self.args[0]
1788 arg0 = arg.subs(x, 0)
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)
1794 res = Function._eval_nseries(self, x, n=n, logx=logx)
1795 if arg0 is S.ComplexInfinity:
1796 return res
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
1811 def _eval_rewrite_as_log(self, x, **kwargs):
1812 return (log(1 + 1/x) - log(1 - 1/x)) / 2
1814 _eval_rewrite_as_tractable = _eval_rewrite_as_log
1816 def _eval_rewrite_as_atanh(self, x, **kwargs):
1817 return atanh(1/x)
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))))
1823 def inverse(self, argindex=1):
1824 """
1825 Returns the inverse of this function.
1826 """
1827 return coth
1830class asech(InverseHyperbolicFunction):
1831 """
1832 ``asech(x)`` is the inverse hyperbolic secant of ``x``.
1834 The inverse hyperbolic secant function.
1836 Examples
1837 ========
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
1854 See Also
1855 ========
1857 asinh, atanh, cosh, acoth
1859 References
1860 ==========
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/
1866 """
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)
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
1891 if arg.is_number:
1892 cst_table = _asech_table()
1894 if arg in cst_table:
1895 if arg.is_extended_real:
1896 return cst_table[arg]*I
1897 return cst_table[arg]
1899 if arg is S.ComplexInfinity:
1900 from sympy.calculus.accumulationbounds import AccumBounds
1901 return I*AccumBounds(-pi/2, pi/2)
1903 if arg.is_zero:
1904 return S.Infinity
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
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)
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)
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)
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)
1971 res = Function._eval_nseries(self, x, n=n, logx=logx)
1972 if arg0 is S.ComplexInfinity:
1973 return res
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
1986 def inverse(self, argindex=1):
1987 """
1988 Returns the inverse of this function.
1989 """
1990 return sech
1992 def _eval_rewrite_as_log(self, arg, **kwargs):
1993 return log(1/arg + sqrt(1/arg - 1) * sqrt(1/arg + 1))
1995 _eval_rewrite_as_tractable = _eval_rewrite_as_log
1997 def _eval_rewrite_as_acosh(self, arg, **kwargs):
1998 return acosh(1/arg)
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)
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)))
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))
2012class acsch(InverseHyperbolicFunction):
2013 """
2014 ``acsch(x)`` is the inverse hyperbolic cosecant of ``x``.
2016 The inverse hyperbolic cosecant function.
2018 Examples
2019 ========
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
2036 See Also
2037 ========
2039 asinh
2041 References
2042 ==========
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/
2048 """
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)
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))
2073 if arg.is_number:
2074 cst_table = _acsch_table()
2076 if arg in cst_table:
2077 return cst_table[arg]*I
2079 if arg is S.ComplexInfinity:
2080 return S.Zero
2082 if arg.is_infinite:
2083 return S.Zero
2085 if arg.is_zero:
2086 return S.ComplexInfinity
2088 if arg.could_extract_minus_sign():
2089 return -cls(-arg)
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
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)
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)
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
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)
2161 res = Function._eval_nseries(self, x, n=n, logx=logx)
2162 if arg0 is S.ComplexInfinity:
2163 return res
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
2178 def inverse(self, argindex=1):
2179 """
2180 Returns the inverse of this function.
2181 """
2182 return csch
2184 def _eval_rewrite_as_log(self, arg, **kwargs):
2185 return log(1/arg + sqrt(1/arg**2 + 1))
2187 _eval_rewrite_as_tractable = _eval_rewrite_as_log
2189 def _eval_rewrite_as_asinh(self, arg, **kwargs):
2190 return asinh(1/arg)
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)
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)))
2202 def _eval_is_zero(self):
2203 return self.args[0].is_infinite