text: from __future__ import print_function, division
  
  from sympy.core.logic import FuzzyBool
  
  from sympy.core import S, sympify, cacheit, pi, I, Rational
  from sympy.core.add import Add
  from sympy.core.function import Function, ArgumentIndexError, _coeff_isneg
  from sympy.functions.combinatorial.factorials import factorial, RisingFactorial
  from sympy.functions.elementary.exponential import exp, log, match_real_imag
  from sympy.functions.elementary.miscellaneous import sqrt
  from sympy.functions.elementary.integers import floor
  
  from sympy.core.logic import fuzzy_or, fuzzy_and
  
  
  
  def _rewrite_hyperbolics_as_exp(expr):
      expr = sympify(expr)
      return expr.xreplace({h: h.rewrite(exp)
          for h in expr.atoms(HyperbolicFunction)})
  
  
  ###############################################################################
  ########################### HYPERBOLIC FUNCTIONS ##############################
  ###############################################################################
  
  
  class HyperbolicFunction(Function):
      """
      Base class for hyperbolic functions.
  
      See Also
      ========
  
      sinh, cosh, tanh, coth
      """
  
      unbranched = True
  
  
  def _peeloff_ipi(arg):
      """
      Split ARG into two parts, a "rest" and a multiple of I*pi/2.
      This assumes ARG to be an Add.
      The multiple of I*pi returned in the second position is always a Rational.
  
      Examples
      ========
  
      >>> from sympy.functions.elementary.hyperbolic import _peeloff_ipi as peel
      >>> from sympy import pi, I
      >>> from sympy.abc import x, y
      >>> peel(x + I*pi/2)
      (x, I*pi/2)
      >>> peel(x + I*2*pi/3 + I*pi*y)
      (x + I*pi*y + I*pi/6, I*pi/2)
      """
      for a in Add.make_args(arg):
          if a == S.Pi*S.ImaginaryUnit:
              K = S.One
              break
          elif a.is_Mul:
              K, p = a.as_two_terms()
              if p == S.Pi*S.ImaginaryUnit and K.is_Rational:
                  break
      else:
          return arg, S.Zero
  
      m1 = (K % S.Half)*S.Pi*S.ImaginaryUnit
      m2 = K*S.Pi*S.ImaginaryUnit - m1
      return arg - m2, m2
  
  
  class sinh(HyperbolicFunction):
      r"""
      The hyperbolic sine function, `\frac{e^x - e^{-x}}{2}`.
  
      * sinh(x) -> Returns the hyperbolic sine of x
  
      See Also
      ========
  
      cosh, tanh, asinh
      """
  
      def fdiff(self, argindex=1):
          """
          Returns the first derivative of this function.
          """
          if argindex == 1:
              return cosh(self.args[0])
          else:
              raise ArgumentIndexError(self, argindex)
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return asinh
  
      @classmethod
      def eval(cls, arg):
          from sympy import sin
  
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Infinity
              elif arg is S.NegativeInfinity:
                  return S.NegativeInfinity
              elif arg.is_zero:
                  return S.Zero
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.NaN
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  return S.ImaginaryUnit * sin(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
              if arg.is_Add:
                  x, m = _peeloff_ipi(arg)
                  if m:
                      return sinh(m)*cosh(x) + cosh(m)*sinh(x)
  
              if arg.is_zero:
                  return S.Zero
  
              if arg.func == asinh:
                  return arg.args[0]
  
              if arg.func == acosh:
                  x = arg.args[0]
                  return sqrt(x - 1) * sqrt(x + 1)
  
              if arg.func == atanh:
                  x = arg.args[0]
                  return x/sqrt(1 - x**2)
  
              if arg.func == acoth:
                  x = arg.args[0]
                  return 1/(sqrt(x - 1) * sqrt(x + 1))
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          """
          Returns the next term in the Taylor series expansion.
          """
          if n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
  
              if len(previous_terms) > 2:
                  p = previous_terms[-2]
                  return p * x**2 / (n*(n - 1))
              else:
                  return x**(n) / factorial(n)
  
      def _eval_conjugate(self):
          return self.func(self.args[0].conjugate())
  
      def as_real_imag(self, deep=True, **hints):
          """
          Returns this function as a complex coordinate.
          """
          from sympy import cos, sin
          if self.args[0].is_extended_real:
              if deep:
                  hints['complex'] = False
                  return (self.expand(deep, **hints), S.Zero)
              else:
                  return (self, S.Zero)
          if deep:
              re, im = self.args[0].expand(deep, **hints).as_real_imag()
          else:
              re, im = self.args[0].as_real_imag()
          return (sinh(re)*cos(im), cosh(re)*sin(im))
  
      def _eval_expand_complex(self, deep=True, **hints):
          re_part, im_part = self.as_real_imag(deep=deep, **hints)
          return re_part + im_part*S.ImaginaryUnit
  
      def _eval_expand_trig(self, deep=True, **hints):
          if deep:
              arg = self.args[0].expand(deep, **hints)
          else:
              arg = self.args[0]
          x = None
          if arg.is_Add: # TODO, implement more if deep stuff here
              x, y = arg.as_two_terms()
          else:
              coeff, terms = arg.as_coeff_Mul(rational=True)
              if coeff is not S.One and coeff.is_Integer and terms is not S.One:
                  x = terms
                  y = (coeff - 1)*x
          if x is not None:
              return (sinh(x)*cosh(y) + sinh(y)*cosh(x)).expand(trig=True)
          return sinh(arg)
  
      def _eval_rewrite_as_tractable(self, arg, **kwargs):
          return (exp(arg) - exp(-arg)) / 2
  
      def _eval_rewrite_as_exp(self, arg, **kwargs):
          return (exp(arg) - exp(-arg)) / 2
  
      def _eval_rewrite_as_cosh(self, arg, **kwargs):
          return -S.ImaginaryUnit*cosh(arg + S.Pi*S.ImaginaryUnit/2)
  
      def _eval_rewrite_as_tanh(self, arg, **kwargs):
          tanh_half = tanh(S.Half*arg)
          return 2*tanh_half/(1 - tanh_half**2)
  
      def _eval_rewrite_as_coth(self, arg, **kwargs):
          coth_half = coth(S.Half*arg)
          return 2*coth_half/(coth_half**2 - 1)
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return arg
          else:
              return self.func(arg)
  
      def _eval_is_real(self):
          arg = self.args[0]
          if arg.is_real:
              return True
  
          # if `im` is of the form n*pi
          # else, check if it is a number
          re, im = arg.as_real_imag()
          return (im%pi).is_zero
  
      def _eval_is_extended_real(self):
          if self.args[0].is_extended_real:
              return True
  
      def _eval_is_positive(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_positive
  
      def _eval_is_negative(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_negative
  
      def _eval_is_finite(self):
          arg = self.args[0]
          return arg.is_finite
  
      def _eval_is_zero(self):
          arg = self.args[0]
          if arg.is_zero:
              return True
  
  
  class cosh(HyperbolicFunction):
      r"""
      The hyperbolic cosine function, `\frac{e^x + e^{-x}}{2}`.
  
      * cosh(x) -> Returns the hyperbolic cosine of x
  
      See Also
      ========
  
      sinh, tanh, acosh
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return sinh(self.args[0])
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          from sympy import cos
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Infinity
              elif arg is S.NegativeInfinity:
                  return S.Infinity
              elif arg.is_zero:
                  return S.One
              elif arg.is_negative:
                  return cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.NaN
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  return cos(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return cls(-arg)
  
              if arg.is_Add:
                  x, m = _peeloff_ipi(arg)
                  if m:
                      return cosh(m)*cosh(x) + sinh(m)*sinh(x)
  
              if arg.is_zero:
                  return S.One
  
              if arg.func == asinh:
                  return sqrt(1 + arg.args[0]**2)
  
              if arg.func == acosh:
                  return arg.args[0]
  
              if arg.func == atanh:
                  return 1/sqrt(1 - arg.args[0]**2)
  
              if arg.func == acoth:
                  x = arg.args[0]
                  return x/(sqrt(x - 1) * sqrt(x + 1))
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          if n < 0 or n % 2 == 1:
              return S.Zero
          else:
              x = sympify(x)
  
              if len(previous_terms) > 2:
                  p = previous_terms[-2]
                  return p * x**2 / (n*(n - 1))
              else:
                  return x**(n)/factorial(n)
  
      def _eval_conjugate(self):
          return self.func(self.args[0].conjugate())
  
      def as_real_imag(self, deep=True, **hints):
          from sympy import cos, sin
          if self.args[0].is_extended_real:
              if deep:
                  hints['complex'] = False
                  return (self.expand(deep, **hints), S.Zero)
              else:
                  return (self, S.Zero)
          if deep:
              re, im = self.args[0].expand(deep, **hints).as_real_imag()
          else:
              re, im = self.args[0].as_real_imag()
  
          return (cosh(re)*cos(im), sinh(re)*sin(im))
  
      def _eval_expand_complex(self, deep=True, **hints):
          re_part, im_part = self.as_real_imag(deep=deep, **hints)
          return re_part + im_part*S.ImaginaryUnit
  
      def _eval_expand_trig(self, deep=True, **hints):
          if deep:
              arg = self.args[0].expand(deep, **hints)
          else:
              arg = self.args[0]
          x = None
          if arg.is_Add: # TODO, implement more if deep stuff here
              x, y = arg.as_two_terms()
          else:
              coeff, terms = arg.as_coeff_Mul(rational=True)
              if coeff is not S.One and coeff.is_Integer and terms is not S.One:
                  x = terms
                  y = (coeff - 1)*x
          if x is not None:
              return (cosh(x)*cosh(y) + sinh(x)*sinh(y)).expand(trig=True)
          return cosh(arg)
  
      def _eval_rewrite_as_tractable(self, arg, **kwargs):
          return (exp(arg) + exp(-arg)) / 2
  
      def _eval_rewrite_as_exp(self, arg, **kwargs):
          return (exp(arg) + exp(-arg)) / 2
  
      def _eval_rewrite_as_sinh(self, arg, **kwargs):
          return -S.ImaginaryUnit*sinh(arg + S.Pi*S.ImaginaryUnit/2)
  
      def _eval_rewrite_as_tanh(self, arg, **kwargs):
          tanh_half = tanh(S.Half*arg)**2
          return (1 + tanh_half)/(1 - tanh_half)
  
      def _eval_rewrite_as_coth(self, arg, **kwargs):
          coth_half = coth(S.Half*arg)**2
          return (coth_half + 1)/(coth_half - 1)
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return S.One
          else:
              return self.func(arg)
  
      def _eval_is_real(self):
          arg = self.args[0]
  
          # `cosh(x)` is real for real OR purely imaginary `x`
          if arg.is_real or arg.is_imaginary:
              return True
  
          # cosh(a+ib) = cos(b)*cosh(a) + i*sin(b)*sinh(a)
          # the imaginary part can be an expression like n*pi
          # if not, check if the imaginary part is a number
          re, im = arg.as_real_imag()
          return (im%pi).is_zero
  
      def _eval_is_positive(self):
          # cosh(x+I*y) = cos(y)*cosh(x) + I*sin(y)*sinh(x)
          # cosh(z) is positive iff it is real and the real part is positive.
          # So we need sin(y)*sinh(x) = 0 which gives x=0 or y=n*pi
          # Case 1 (y=n*pi): cosh(z) = (-1)**n * cosh(x) -> positive for n even
          # Case 2 (x=0): cosh(z) = cos(y) -> positive when cos(y) is positive
          z = self.args[0]
  
          x, y = z.as_real_imag()
          ymod = y % (2*pi)
  
          yzero = ymod.is_zero
          # shortcut if ymod is zero
          if yzero:
              return True
  
          xzero = x.is_zero
          # shortcut x is not zero
          if xzero is False:
              return yzero
  
          return fuzzy_or([
                  # Case 1:
                  yzero,
                  # Case 2:
                  fuzzy_and([
                      xzero,
                      fuzzy_or([ymod < pi/2, ymod > 3*pi/2])
                  ])
              ])
  
  
      def _eval_is_nonnegative(self):
          z = self.args[0]
  
          x, y = z.as_real_imag()
          ymod = y % (2*pi)
  
          yzero = ymod.is_zero
          # shortcut if ymod is zero
          if yzero:
              return True
  
          xzero = x.is_zero
          # shortcut x is not zero
          if xzero is False:
              return yzero
  
          return fuzzy_or([
                  # Case 1:
                  yzero,
                  # Case 2:
                  fuzzy_and([
                      xzero,
                      fuzzy_or([ymod <= pi/2, ymod >= 3*pi/2])
                  ])
              ])
  
      def _eval_is_finite(self):
          arg = self.args[0]
          return arg.is_finite
  
  
  class tanh(HyperbolicFunction):
      r"""
      The hyperbolic tangent function, `\frac{\sinh(x)}{\cosh(x)}`.
  
      * tanh(x) -> Returns the hyperbolic tangent of x
  
      See Also
      ========
  
      sinh, cosh, atanh
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return S.One - tanh(self.args[0])**2
          else:
              raise ArgumentIndexError(self, argindex)
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return atanh
  
      @classmethod
      def eval(cls, arg):
          from sympy import tan
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.One
              elif arg is S.NegativeInfinity:
                  return S.NegativeOne
              elif arg.is_zero:
                  return S.Zero
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.NaN
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  if _coeff_isneg(i_coeff):
                      return -S.ImaginaryUnit * tan(-i_coeff)
                  return S.ImaginaryUnit * tan(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
              if arg.is_Add:
                  x, m = _peeloff_ipi(arg)
                  if m:
                      tanhm = tanh(m)
                      if tanhm is S.ComplexInfinity:
                          return coth(x)
                      else: # tanhm == 0
                          return tanh(x)
  
              if arg.is_zero:
                  return S.Zero
  
              if arg.func == asinh:
                  x = arg.args[0]
                  return x/sqrt(1 + x**2)
  
              if arg.func == acosh:
                  x = arg.args[0]
                  return sqrt(x - 1) * sqrt(x + 1) / x
  
              if arg.func == atanh:
                  return arg.args[0]
  
              if arg.func == acoth:
                  return 1/arg.args[0]
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          from sympy import bernoulli
          if n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
  
              a = 2**(n + 1)
  
              B = bernoulli(n + 1)
              F = factorial(n + 1)
  
              return a*(a - 1) * B/F * x**n
  
      def _eval_conjugate(self):
          return self.func(self.args[0].conjugate())
  
      def as_real_imag(self, deep=True, **hints):
          from sympy import cos, sin
          if self.args[0].is_extended_real:
              if deep:
                  hints['complex'] = False
                  return (self.expand(deep, **hints), S.Zero)
              else:
                  return (self, S.Zero)
          if deep:
              re, im = self.args[0].expand(deep, **hints).as_real_imag()
          else:
              re, im = self.args[0].as_real_imag()
          denom = sinh(re)**2 + cos(im)**2
          return (sinh(re)*cosh(re)/denom, sin(im)*cos(im)/denom)
  
      def _eval_rewrite_as_tractable(self, arg, **kwargs):
          neg_exp, pos_exp = exp(-arg), exp(arg)
          return (pos_exp - neg_exp)/(pos_exp + neg_exp)
  
      def _eval_rewrite_as_exp(self, arg, **kwargs):
          neg_exp, pos_exp = exp(-arg), exp(arg)
          return (pos_exp - neg_exp)/(pos_exp + neg_exp)
  
      def _eval_rewrite_as_sinh(self, arg, **kwargs):
          return S.ImaginaryUnit*sinh(arg)/sinh(S.Pi*S.ImaginaryUnit/2 - arg)
  
      def _eval_rewrite_as_cosh(self, arg, **kwargs):
          return S.ImaginaryUnit*cosh(S.Pi*S.ImaginaryUnit/2 - arg)/cosh(arg)
  
      def _eval_rewrite_as_coth(self, arg, **kwargs):
          return 1/coth(arg)
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return arg
          else:
              return self.func(arg)
  
      def _eval_is_real(self):
          arg = self.args[0]
          if arg.is_real:
              return True
  
          re, im = arg.as_real_imag()
  
          # if denom = 0, tanh(arg) = zoo
          if re == 0 and im % pi == pi/2:
              return None
  
          # check if im is of the form n*pi/2 to make sin(2*im) = 0
          # if not, im could be a number, return False in that case
          return (im % (pi/2)).is_zero
  
      def _eval_is_extended_real(self):
          if self.args[0].is_extended_real:
              return True
  
      def _eval_is_positive(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_positive
  
      def _eval_is_negative(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_negative
  
      def _eval_is_finite(self):
          from sympy import sinh, cos
          arg = self.args[0]
  
          re, im = arg.as_real_imag()
          denom = cos(im)**2 + sinh(re)**2
          if denom == 0:
              return False
          elif denom.is_number:
              return True
          if arg.is_extended_real:
              return True
  
      def _eval_is_zero(self):
          arg = self.args[0]
          if arg.is_zero:
              return True
  
  
  class coth(HyperbolicFunction):
      r"""
      The hyperbolic cotangent function, `\frac{\cosh(x)}{\sinh(x)}`.
  
      * coth(x) -> Returns the hyperbolic cotangent of x
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return -1/sinh(self.args[0])**2
          else:
              raise ArgumentIndexError(self, argindex)
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return acoth
  
      @classmethod
      def eval(cls, arg):
          from sympy import cot
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.One
              elif arg is S.NegativeInfinity:
                  return S.NegativeOne
              elif arg.is_zero:
                  return S.ComplexInfinity
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.NaN
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  if _coeff_isneg(i_coeff):
                      return S.ImaginaryUnit * cot(-i_coeff)
                  return -S.ImaginaryUnit * cot(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
              if arg.is_Add:
                  x, m = _peeloff_ipi(arg)
                  if m:
                      cothm = coth(m)
                      if cothm is S.ComplexInfinity:
                          return coth(x)
                      else: # cothm == 0
                          return tanh(x)
  
              if arg.is_zero:
                  return S.ComplexInfinity
  
              if arg.func == asinh:
                  x = arg.args[0]
                  return sqrt(1 + x**2)/x
  
              if arg.func == acosh:
                  x = arg.args[0]
                  return x/(sqrt(x - 1) * sqrt(x + 1))
  
              if arg.func == atanh:
                  return 1/arg.args[0]
  
              if arg.func == acoth:
                  return arg.args[0]
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          from sympy import bernoulli
          if n == 0:
              return 1 / sympify(x)
          elif n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
  
              B = bernoulli(n + 1)
              F = factorial(n + 1)
  
              return 2**(n + 1) * B/F * x**n
  
      def _eval_conjugate(self):
          return self.func(self.args[0].conjugate())
  
      def as_real_imag(self, deep=True, **hints):
          from sympy import cos, sin
          if self.args[0].is_extended_real:
              if deep:
                  hints['complex'] = False
                  return (self.expand(deep, **hints), S.Zero)
              else:
                  return (self, S.Zero)
          if deep:
              re, im = self.args[0].expand(deep, **hints).as_real_imag()
          else:
              re, im = self.args[0].as_real_imag()
          denom = sinh(re)**2 + sin(im)**2
          return (sinh(re)*cosh(re)/denom, -sin(im)*cos(im)/denom)
  
      def _eval_rewrite_as_tractable(self, arg, **kwargs):
          neg_exp, pos_exp = exp(-arg), exp(arg)
          return (pos_exp + neg_exp)/(pos_exp - neg_exp)
  
      def _eval_rewrite_as_exp(self, arg, **kwargs):
          neg_exp, pos_exp = exp(-arg), exp(arg)
          return (pos_exp + neg_exp)/(pos_exp - neg_exp)
  
      def _eval_rewrite_as_sinh(self, arg, **kwargs):
          return -S.ImaginaryUnit*sinh(S.Pi*S.ImaginaryUnit/2 - arg)/sinh(arg)
  
      def _eval_rewrite_as_cosh(self, arg, **kwargs):
          return -S.ImaginaryUnit*cosh(arg)/cosh(S.Pi*S.ImaginaryUnit/2 - arg)
  
      def _eval_rewrite_as_tanh(self, arg, **kwargs):
          return 1/tanh(arg)
  
      def _eval_is_positive(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_positive
  
      def _eval_is_negative(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_negative
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return 1/arg
          else:
              return self.func(arg)
  
  
  class ReciprocalHyperbolicFunction(HyperbolicFunction):
      """Base class for reciprocal functions of hyperbolic functions. """
  
      #To be defined in class
      _reciprocal_of = None
      _is_even = None  # type: FuzzyBool
      _is_odd = None  # type: FuzzyBool
  
      @classmethod
      def eval(cls, arg):
          if arg.could_extract_minus_sign():
              if cls._is_even:
                  return cls(-arg)
              if cls._is_odd:
                  return -cls(-arg)
  
          t = cls._reciprocal_of.eval(arg)
          if hasattr(arg, 'inverse') and arg.inverse() == cls:
              return arg.args[0]
          return 1/t if t is not None else t
  
      def _call_reciprocal(self, method_name, *args, **kwargs):
          # Calls method_name on _reciprocal_of
          o = self._reciprocal_of(self.args[0])
          return getattr(o, method_name)(*args, **kwargs)
  
      def _calculate_reciprocal(self, method_name, *args, **kwargs):
          # If calling method_name on _reciprocal_of returns a value != None
          # then return the reciprocal of that value
          t = self._call_reciprocal(method_name, *args, **kwargs)
          return 1/t if t is not None else t
  
      def _rewrite_reciprocal(self, method_name, arg):
          # Special handling for rewrite functions. If reciprocal rewrite returns
          # unmodified expression, then return None
          t = self._call_reciprocal(method_name, arg)
          if t is not None and t != self._reciprocal_of(arg):
              return 1/t
  
      def _eval_rewrite_as_exp(self, arg, **kwargs):
          return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg)
  
      def _eval_rewrite_as_tractable(self, arg, **kwargs):
          return self._rewrite_reciprocal("_eval_rewrite_as_tractable", arg)
  
      def _eval_rewrite_as_tanh(self, arg, **kwargs):
          return self._rewrite_reciprocal("_eval_rewrite_as_tanh", arg)
  
      def _eval_rewrite_as_coth(self, arg, **kwargs):
          return self._rewrite_reciprocal("_eval_rewrite_as_coth", arg)
  
      def as_real_imag(self, deep = True, **hints):
          return (1 / self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints)
  
      def _eval_conjugate(self):
          return self.func(self.args[0].conjugate())
  
      def _eval_expand_complex(self, deep=True, **hints):
          re_part, im_part = self.as_real_imag(deep=True, **hints)
          return re_part + S.ImaginaryUnit*im_part
  
      def _eval_as_leading_term(self, x):
          return (1/self._reciprocal_of(self.args[0]))._eval_as_leading_term(x)
  
      def _eval_is_extended_real(self):
          return self._reciprocal_of(self.args[0]).is_extended_real
  
      def _eval_is_finite(self):
          return (1/self._reciprocal_of(self.args[0])).is_finite
  
  
  class csch(ReciprocalHyperbolicFunction):
      r"""
      The hyperbolic cosecant function, `\frac{2}{e^x - e^{-x}}`
  
      * csch(x) -> Returns the hyperbolic cosecant of x
  
      See Also
      ========
  
      sinh, cosh, tanh, sech, asinh, acosh
      """
  
      _reciprocal_of = sinh
      _is_odd = True
  
      def fdiff(self, argindex=1):
          """
          Returns the first derivative of this function
          """
          if argindex == 1:
              return -coth(self.args[0]) * csch(self.args[0])
          else:
              raise ArgumentIndexError(self, argindex)
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          """
          Returns the next term in the Taylor series expansion
          """
          from sympy import bernoulli
          if n == 0:
              return 1/sympify(x)
          elif n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
  
              B = bernoulli(n + 1)
              F = factorial(n + 1)
  
              return 2 * (1 - 2**n) * B/F * x**n
  
      def _eval_rewrite_as_cosh(self, arg, **kwargs):
          return S.ImaginaryUnit / cosh(arg + S.ImaginaryUnit * S.Pi / 2)
  
      def _eval_is_positive(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_positive
  
      def _eval_is_negative(self):
          if self.args[0].is_extended_real:
              return self.args[0].is_negative
  
      def _sage_(self):
          import sage.all as sage
          return sage.csch(self.args[0]._sage_())
  
  
  class sech(ReciprocalHyperbolicFunction):
      r"""
      The hyperbolic secant function, `\frac{2}{e^x + e^{-x}}`
  
      * sech(x) -> Returns the hyperbolic secant of x
  
      See Also
      ========
  
      sinh, cosh, tanh, coth, csch, asinh, acosh
      """
  
      _reciprocal_of = cosh
      _is_even = True
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return - tanh(self.args[0])*sech(self.args[0])
          else:
              raise ArgumentIndexError(self, argindex)
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          from sympy.functions.combinatorial.numbers import euler
          if n < 0 or n % 2 == 1:
              return S.Zero
          else:
              x = sympify(x)
              return euler(n) / factorial(n) * x**(n)
  
      def _eval_rewrite_as_sinh(self, arg, **kwargs):
          return S.ImaginaryUnit / sinh(arg + S.ImaginaryUnit * S.Pi /2)
  
      def _eval_is_positive(self):
          if self.args[0].is_extended_real:
              return True
  
      def _sage_(self):
          import sage.all as sage
          return sage.sech(self.args[0]._sage_())
  
  
  
  ###############################################################################
  ############################# HYPERBOLIC INVERSES #############################
  ###############################################################################
  
  class InverseHyperbolicFunction(Function):
      """Base class for inverse hyperbolic functions."""
  
      pass
  
  
  class asinh(InverseHyperbolicFunction):
      """
      The inverse hyperbolic sine function.
  
      * asinh(x) -> Returns the inverse hyperbolic sine of x
  
      See Also
      ========
  
      acosh, atanh, sinh
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return 1/sqrt(self.args[0]**2 + 1)
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          from sympy import asin
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Infinity
              elif arg is S.NegativeInfinity:
                  return S.NegativeInfinity
              elif arg.is_zero:
                  return S.Zero
              elif arg is S.One:
                  return log(sqrt(2) + 1)
              elif arg is S.NegativeOne:
                  return log(sqrt(2) - 1)
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.ComplexInfinity
  
              if arg.is_zero:
                  return S.Zero
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  return S.ImaginaryUnit * asin(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
          if isinstance(arg, sinh) and arg.args[0].is_number:
              z = arg.args[0]
              if z.is_real:
                  return z
              r, i = match_real_imag(z)
              if r is not None and i is not None:
                  f = floor((i + pi/2)/pi)
                  m = z - I*pi*f
                  even = f.is_even
                  if even is True:
                      return m
                  elif even is False:
                      return -m
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          if n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
              if len(previous_terms) >= 2 and n > 2:
                  p = previous_terms[-2]
                  return -p * (n - 2)**2/(n*(n - 1)) * x**2
              else:
                  k = (n - 1) // 2
                  R = RisingFactorial(S.Half, k)
                  F = factorial(k)
                  return (-1)**k * R / F * x**n / n
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return arg
          else:
              return self.func(arg)
  
      def _eval_rewrite_as_log(self, x, **kwargs):
          return log(x + sqrt(x**2 + 1))
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return sinh
  
      def _eval_is_zero(self):
          arg = self.args[0]
          if arg.is_zero:
              return True
  
  
  class acosh(InverseHyperbolicFunction):
      """
      The inverse hyperbolic cosine function.
  
      * acosh(x) -> Returns the inverse hyperbolic cosine of x
  
      See Also
      ========
  
      asinh, atanh, cosh
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return 1/sqrt(self.args[0]**2 - 1)
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Infinity
              elif arg is S.NegativeInfinity:
                  return S.Infinity
              elif arg.is_zero:
                  return S.Pi*S.ImaginaryUnit / 2
              elif arg is S.One:
                  return S.Zero
              elif arg is S.NegativeOne:
                  return S.Pi*S.ImaginaryUnit
  
          if arg.is_number:
              cst_table = {
                  S.ImaginaryUnit: log(S.ImaginaryUnit*(1 + sqrt(2))),
                  -S.ImaginaryUnit: log(-S.ImaginaryUnit*(1 + sqrt(2))),
                  S.Half: S.Pi/3,
                  Rational(-1, 2): S.Pi*Rational(2, 3),
                  sqrt(2)/2: S.Pi/4,
                  -sqrt(2)/2: S.Pi*Rational(3, 4),
                  1/sqrt(2): S.Pi/4,
                  -1/sqrt(2): S.Pi*Rational(3, 4),
                  sqrt(3)/2: S.Pi/6,
                  -sqrt(3)/2: S.Pi*Rational(5, 6),
                  (sqrt(3) - 1)/sqrt(2**3): S.Pi*Rational(5, 12),
                  -(sqrt(3) - 1)/sqrt(2**3): S.Pi*Rational(7, 12),
                  sqrt(2 + sqrt(2))/2: S.Pi/8,
                  -sqrt(2 + sqrt(2))/2: S.Pi*Rational(7, 8),
                  sqrt(2 - sqrt(2))/2: S.Pi*Rational(3, 8),
                  -sqrt(2 - sqrt(2))/2: S.Pi*Rational(5, 8),
                  (1 + sqrt(3))/(2*sqrt(2)): S.Pi/12,
                  -(1 + sqrt(3))/(2*sqrt(2)): S.Pi*Rational(11, 12),
                  (sqrt(5) + 1)/4: S.Pi/5,
                  -(sqrt(5) + 1)/4: S.Pi*Rational(4, 5)
              }
  
              if arg in cst_table:
                  if arg.is_extended_real:
                      return cst_table[arg]*S.ImaginaryUnit
                  return cst_table[arg]
  
          if arg is S.ComplexInfinity:
              return S.ComplexInfinity
          if arg == S.ImaginaryUnit*S.Infinity:
              return S.Infinity + S.ImaginaryUnit*S.Pi/2
          if arg == -S.ImaginaryUnit*S.Infinity:
              return S.Infinity - S.ImaginaryUnit*S.Pi/2
  
          if arg.is_zero:
              return S.Pi*S.ImaginaryUnit*S.Half
  
          if isinstance(arg, cosh) and arg.args[0].is_number:
              z = arg.args[0]
              if z.is_real:
                  from sympy.functions.elementary.complexes import Abs
                  return Abs(z)
              r, i = match_real_imag(z)
              if r is not None and i is not None:
                  f = floor(i/pi)
                  m = z - I*pi*f
                  even = f.is_even
                  if even is True:
                      if r.is_nonnegative:
                          return m
                      elif r.is_negative:
                          return -m
                  elif even is False:
                      m -= I*pi
                      if r.is_nonpositive:
                          return -m
                      elif r.is_positive:
                          return m
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          if n == 0:
              return S.Pi*S.ImaginaryUnit / 2
          elif n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
              if len(previous_terms) >= 2 and n > 2:
                  p = previous_terms[-2]
                  return p * (n - 2)**2/(n*(n - 1)) * x**2
              else:
                  k = (n - 1) // 2
                  R = RisingFactorial(S.Half, k)
                  F = factorial(k)
                  return -R / F * S.ImaginaryUnit * x**n / n
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return S.ImaginaryUnit*S.Pi/2
          else:
              return self.func(arg)
  
      def _eval_rewrite_as_log(self, x, **kwargs):
          return log(x + sqrt(x + 1) * sqrt(x - 1))
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return cosh
  
  
  class atanh(InverseHyperbolicFunction):
      """
      The inverse hyperbolic tangent function.
  
      * atanh(x) -> Returns the inverse hyperbolic tangent of x
  
      See Also
      ========
  
      asinh, acosh, tanh
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return 1/(1 - self.args[0]**2)
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          from sympy import atan
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg.is_zero:
                  return S.Zero
              elif arg is S.One:
                  return S.Infinity
              elif arg is S.NegativeOne:
                  return S.NegativeInfinity
              elif arg is S.Infinity:
                  return -S.ImaginaryUnit * atan(arg)
              elif arg is S.NegativeInfinity:
                  return S.ImaginaryUnit * atan(-arg)
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  from sympy.calculus.util import AccumBounds
                  return S.ImaginaryUnit*AccumBounds(-S.Pi/2, S.Pi/2)
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  return S.ImaginaryUnit * atan(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
          if arg.is_zero:
              return S.Zero
  
          if isinstance(arg, tanh) and arg.args[0].is_number:
              z = arg.args[0]
              if z.is_real:
                  return z
              r, i = match_real_imag(z)
              if r is not None and i is not None:
                  f = floor(2*i/pi)
                  even = f.is_even
                  m = z - I*f*pi/2
                  if even is True:
                      return m
                  elif even is False:
                      return m - I*pi/2
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          if n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
              return x**n / n
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return arg
          else:
              return self.func(arg)
  
      def _eval_rewrite_as_log(self, x, **kwargs):
          return (log(1 + x) - log(1 - x)) / 2
  
      def _eval_is_zero(self):
          arg = self.args[0]
          if arg.is_zero:
              return True
  
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return tanh
  
  
  class acoth(InverseHyperbolicFunction):
      """
      The inverse hyperbolic cotangent function.
  
      * acoth(x) -> Returns the inverse hyperbolic cotangent of x
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              return 1/(1 - self.args[0]**2)
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          from sympy import acot
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Zero
              elif arg is S.NegativeInfinity:
                  return S.Zero
              elif arg.is_zero:
                  return S.Pi*S.ImaginaryUnit / 2
              elif arg is S.One:
                  return S.Infinity
              elif arg is S.NegativeOne:
                  return S.NegativeInfinity
              elif arg.is_negative:
                  return -cls(-arg)
          else:
              if arg is S.ComplexInfinity:
                  return S.Zero
  
              i_coeff = arg.as_coefficient(S.ImaginaryUnit)
  
              if i_coeff is not None:
                  return -S.ImaginaryUnit * acot(i_coeff)
              else:
                  if _coeff_isneg(arg):
                      return -cls(-arg)
  
          if arg.is_zero:
              return S.Pi*S.ImaginaryUnit*S.Half
  
      @staticmethod
      @cacheit
      def taylor_term(n, x, *previous_terms):
          if n == 0:
              return S.Pi*S.ImaginaryUnit / 2
          elif n < 0 or n % 2 == 0:
              return S.Zero
          else:
              x = sympify(x)
              return x**n / n
  
      def _eval_as_leading_term(self, x):
          from sympy import Order
          arg = self.args[0].as_leading_term(x)
  
          if x in arg.free_symbols and Order(1, x).contains(arg):
              return S.ImaginaryUnit*S.Pi/2
          else:
              return self.func(arg)
  
      def _eval_rewrite_as_log(self, x, **kwargs):
          return (log(1 + 1/x) - log(1 - 1/x)) / 2
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return coth
  
  
  class asech(InverseHyperbolicFunction):
      """
      The inverse hyperbolic secant function.
  
      * asech(x) -> Returns the inverse hyperbolic secant of x
  
      Examples
      ========
  
      >>> from sympy import asech, sqrt, S
      >>> from sympy.abc import x
      >>> asech(x).diff(x)
      -1/(x*sqrt(1 - x**2))
      >>> asech(1).diff(x)
      0
      >>> asech(1)
      0
      >>> asech(S(2))
      I*pi/3
      >>> asech(-sqrt(2))
      3*I*pi/4
      >>> asech((sqrt(6) - sqrt(2)))
      I*pi/12
  
      See Also
      ========
  
      asinh, atanh, cosh, acoth
  
      References
      ==========
  
      .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
      .. [2] http://dlmf.nist.gov/4.37
      .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSech/
  
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              z = self.args[0]
              return -1/(z*sqrt(1 - z**2))
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Pi*S.ImaginaryUnit / 2
              elif arg is S.NegativeInfinity:
                  return S.Pi*S.ImaginaryUnit / 2
              elif arg.is_zero:
                  return S.Infinity
              elif arg is S.One:
                  return S.Zero
              elif arg is S.NegativeOne:
                  return S.Pi*S.ImaginaryUnit
  
          if arg.is_number:
              cst_table = {
                  S.ImaginaryUnit: - (S.Pi*S.ImaginaryUnit / 2) + log(1 + sqrt(2)),
                  -S.ImaginaryUnit: (S.Pi*S.ImaginaryUnit / 2) + log(1 + sqrt(2)),
                  (sqrt(6) - sqrt(2)): S.Pi / 12,
                  (sqrt(2) - sqrt(6)): 11*S.Pi / 12,
                  sqrt(2 - 2/sqrt(5)): S.Pi / 10,
                  -sqrt(2 - 2/sqrt(5)): 9*S.Pi / 10,
                  2 / sqrt(2 + sqrt(2)): S.Pi / 8,
                  -2 / sqrt(2 + sqrt(2)): 7*S.Pi / 8,
                  2 / sqrt(3): S.Pi / 6,
                  -2 / sqrt(3): 5*S.Pi / 6,
                  (sqrt(5) - 1): S.Pi / 5,
                  (1 - sqrt(5)): 4*S.Pi / 5,
                  sqrt(2): S.Pi / 4,
                  -sqrt(2): 3*S.Pi / 4,
                  sqrt(2 + 2/sqrt(5)): 3*S.Pi / 10,
                  -sqrt(2 + 2/sqrt(5)): 7*S.Pi / 10,
                  S(2): S.Pi / 3,
                  -S(2): 2*S.Pi / 3,
                  sqrt(2*(2 + sqrt(2))): 3*S.Pi / 8,
                  -sqrt(2*(2 + sqrt(2))): 5*S.Pi / 8,
                  (1 + sqrt(5)): 2*S.Pi / 5,
                  (-1 - sqrt(5)): 3*S.Pi / 5,
                  (sqrt(6) + sqrt(2)): 5*S.Pi / 12,
                  (-sqrt(6) - sqrt(2)): 7*S.Pi / 12,
              }
  
              if arg in cst_table:
                  if arg.is_extended_real:
                      return cst_table[arg]*S.ImaginaryUnit
                  return cst_table[arg]
  
          if arg is S.ComplexInfinity:
              from sympy.calculus.util import AccumBounds
              return S.ImaginaryUnit*AccumBounds(-S.Pi/2, S.Pi/2)
  
          if arg.is_zero:
              return S.Infinity
  
      @staticmethod
      @cacheit
      def expansion_term(n, x, *previous_terms):
          if n == 0:
              return log(2 / x)
          elif n < 0 or n % 2 == 1:
              return S.Zero
          else:
              x = sympify(x)
              if len(previous_terms) > 2 and n > 2:
                  p = previous_terms[-2]
                  return p * (n - 1)**2 // (n // 2)**2 * x**2 / 4
              else:
                  k = n // 2
                  R = RisingFactorial(S.Half , k) *  n
                  F = factorial(k) * n // 2 * n // 2
                  return -1 * R / F * x**n / 4
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return sech
  
      def _eval_rewrite_as_log(self, arg, **kwargs):
          return log(1/arg + sqrt(1/arg - 1) * sqrt(1/arg + 1))
  
  
  class acsch(InverseHyperbolicFunction):
      """
      The inverse hyperbolic cosecant function.
  
      * acsch(x) -> Returns the inverse hyperbolic cosecant of x
  
      Examples
      ========
  
      >>> from sympy import acsch, sqrt, S
      >>> from sympy.abc import x
      >>> acsch(x).diff(x)
      -1/(x**2*sqrt(1 + x**(-2)))
      >>> acsch(1).diff(x)
      0
      >>> acsch(1)
      log(1 + sqrt(2))
      >>> acsch(S.ImaginaryUnit)
      -I*pi/2
      >>> acsch(-2*S.ImaginaryUnit)
      I*pi/6
      >>> acsch(S.ImaginaryUnit*(sqrt(6) - sqrt(2)))
      -5*I*pi/12
  
      References
      ==========
  
      .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
      .. [2] http://dlmf.nist.gov/4.37
      .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCsch/
  
      """
  
      def fdiff(self, argindex=1):
          if argindex == 1:
              z = self.args[0]
              return -1/(z**2*sqrt(1 + 1/z**2))
          else:
              raise ArgumentIndexError(self, argindex)
  
      @classmethod
      def eval(cls, arg):
          arg = sympify(arg)
  
          if arg.is_Number:
              if arg is S.NaN:
                  return S.NaN
              elif arg is S.Infinity:
                  return S.Zero
              elif arg is S.NegativeInfinity:
                  return S.Zero
              elif arg.is_zero:
                  return S.ComplexInfinity
              elif arg is S.One:
                  return log(1 + sqrt(2))
              elif arg is S.NegativeOne:
                  return - log(1 + sqrt(2))
  
          if arg.is_number:
              cst_table = {
                  S.ImaginaryUnit: -S.Pi / 2,
                  S.ImaginaryUnit*(sqrt(2) + sqrt(6)): -S.Pi / 12,
                  S.ImaginaryUnit*(1 + sqrt(5)): -S.Pi / 10,
                  S.ImaginaryUnit*2 / sqrt(2 - sqrt(2)): -S.Pi / 8,
                  S.ImaginaryUnit*2: -S.Pi / 6,
                  S.ImaginaryUnit*sqrt(2 + 2/sqrt(5)): -S.Pi / 5,
                  S.ImaginaryUnit*sqrt(2): -S.Pi / 4,
                  S.ImaginaryUnit*(sqrt(5)-1): -3*S.Pi / 10,
                  S.ImaginaryUnit*2 / sqrt(3): -S.Pi / 3,
                  S.ImaginaryUnit*2 / sqrt(2 + sqrt(2)): -3*S.Pi / 8,
                  S.ImaginaryUnit*sqrt(2 - 2/sqrt(5)): -2*S.Pi / 5,
                  S.ImaginaryUnit*(sqrt(6) - sqrt(2)): -5*S.Pi / 12,
                  S(2): -S.ImaginaryUnit*log((1+sqrt(5))/2),
              }
  
              if arg in cst_table:
                  return cst_table[arg]*S.ImaginaryUnit
  
          if arg is S.ComplexInfinity:
              return S.Zero
  
          if arg.is_zero:
              return S.ComplexInfinity
  
          if _coeff_isneg(arg):
              return -cls(-arg)
  
      def inverse(self, argindex=1):
          """
          Returns the inverse of this function.
          """
          return csch
  
      def _eval_rewrite_as_log(self, arg, **kwargs):
          return log(1/arg + sqrt(1/arg**2 + 1))
  