图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
8.1 KiB

  1. from sympy.core import S, sympify, oo, diff
  2. from sympy.core.function import Function, ArgumentIndexError
  3. from sympy.core.logic import fuzzy_not
  4. from sympy.core.relational import Eq
  5. from sympy.functions.elementary.complexes import im
  6. from sympy.functions.elementary.piecewise import Piecewise
  7. from sympy.functions.special.delta_functions import Heaviside
  8. ###############################################################################
  9. ############################# SINGULARITY FUNCTION ############################
  10. ###############################################################################
  11. class SingularityFunction(Function):
  12. r"""
  13. Singularity functions are a class of discontinuous functions.
  14. Explanation
  15. ===========
  16. Singularity functions take a variable, an offset, and an exponent as
  17. arguments. These functions are represented using Macaulay brackets as:
  18. SingularityFunction(x, a, n) := <x - a>^n
  19. The singularity function will automatically evaluate to
  20. ``Derivative(DiracDelta(x - a), x, -n - 1)`` if ``n < 0``
  21. and ``(x - a)**n*Heaviside(x - a)`` if ``n >= 0``.
  22. Examples
  23. ========
  24. >>> from sympy import SingularityFunction, diff, Piecewise, DiracDelta, Heaviside, Symbol
  25. >>> from sympy.abc import x, a, n
  26. >>> SingularityFunction(x, a, n)
  27. SingularityFunction(x, a, n)
  28. >>> y = Symbol('y', positive=True)
  29. >>> n = Symbol('n', nonnegative=True)
  30. >>> SingularityFunction(y, -10, n)
  31. (y + 10)**n
  32. >>> y = Symbol('y', negative=True)
  33. >>> SingularityFunction(y, 10, n)
  34. 0
  35. >>> SingularityFunction(x, 4, -1).subs(x, 4)
  36. oo
  37. >>> SingularityFunction(x, 10, -2).subs(x, 10)
  38. oo
  39. >>> SingularityFunction(4, 1, 5)
  40. 243
  41. >>> diff(SingularityFunction(x, 1, 5) + SingularityFunction(x, 1, 4), x)
  42. 4*SingularityFunction(x, 1, 3) + 5*SingularityFunction(x, 1, 4)
  43. >>> diff(SingularityFunction(x, 4, 0), x, 2)
  44. SingularityFunction(x, 4, -2)
  45. >>> SingularityFunction(x, 4, 5).rewrite(Piecewise)
  46. Piecewise(((x - 4)**5, x > 4), (0, True))
  47. >>> expr = SingularityFunction(x, a, n)
  48. >>> y = Symbol('y', positive=True)
  49. >>> n = Symbol('n', nonnegative=True)
  50. >>> expr.subs({x: y, a: -10, n: n})
  51. (y + 10)**n
  52. The methods ``rewrite(DiracDelta)``, ``rewrite(Heaviside)``, and
  53. ``rewrite('HeavisideDiracDelta')`` returns the same output. One can use any
  54. of these methods according to their choice.
  55. >>> expr = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2)
  56. >>> expr.rewrite(Heaviside)
  57. (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1)
  58. >>> expr.rewrite(DiracDelta)
  59. (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1)
  60. >>> expr.rewrite('HeavisideDiracDelta')
  61. (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1)
  62. See Also
  63. ========
  64. DiracDelta, Heaviside
  65. References
  66. ==========
  67. .. [1] https://en.wikipedia.org/wiki/Singularity_function
  68. """
  69. is_real = True
  70. def fdiff(self, argindex=1):
  71. """
  72. Returns the first derivative of a DiracDelta Function.
  73. Explanation
  74. ===========
  75. The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
  76. user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
  77. a convenience method available in the ``Function`` class. It returns
  78. the derivative of the function without considering the chain rule.
  79. ``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
  80. calls ``fdiff()`` internally to compute the derivative of the function.
  81. """
  82. if argindex == 1:
  83. x = sympify(self.args[0])
  84. a = sympify(self.args[1])
  85. n = sympify(self.args[2])
  86. if n in (S.Zero, S.NegativeOne):
  87. return self.func(x, a, n-1)
  88. elif n.is_positive:
  89. return n*self.func(x, a, n-1)
  90. else:
  91. raise ArgumentIndexError(self, argindex)
  92. @classmethod
  93. def eval(cls, variable, offset, exponent):
  94. """
  95. Returns a simplified form or a value of Singularity Function depending
  96. on the argument passed by the object.
  97. Explanation
  98. ===========
  99. The ``eval()`` method is automatically called when the
  100. ``SingularityFunction`` class is about to be instantiated and it
  101. returns either some simplified instance or the unevaluated instance
  102. depending on the argument passed. In other words, ``eval()`` method is
  103. not needed to be called explicitly, it is being called and evaluated
  104. once the object is called.
  105. Examples
  106. ========
  107. >>> from sympy import SingularityFunction, Symbol, nan
  108. >>> from sympy.abc import x, a, n
  109. >>> SingularityFunction(x, a, n)
  110. SingularityFunction(x, a, n)
  111. >>> SingularityFunction(5, 3, 2)
  112. 4
  113. >>> SingularityFunction(x, a, nan)
  114. nan
  115. >>> SingularityFunction(x, 3, 0).subs(x, 3)
  116. 1
  117. >>> SingularityFunction(x, a, n).eval(3, 5, 1)
  118. 0
  119. >>> SingularityFunction(x, a, n).eval(4, 1, 5)
  120. 243
  121. >>> x = Symbol('x', positive = True)
  122. >>> a = Symbol('a', negative = True)
  123. >>> n = Symbol('n', nonnegative = True)
  124. >>> SingularityFunction(x, a, n)
  125. (-a + x)**n
  126. >>> x = Symbol('x', negative = True)
  127. >>> a = Symbol('a', positive = True)
  128. >>> SingularityFunction(x, a, n)
  129. 0
  130. """
  131. x = sympify(variable)
  132. a = sympify(offset)
  133. n = sympify(exponent)
  134. shift = (x - a)
  135. if fuzzy_not(im(shift).is_zero):
  136. raise ValueError("Singularity Functions are defined only for Real Numbers.")
  137. if fuzzy_not(im(n).is_zero):
  138. raise ValueError("Singularity Functions are not defined for imaginary exponents.")
  139. if shift is S.NaN or n is S.NaN:
  140. return S.NaN
  141. if (n + 2).is_negative:
  142. raise ValueError("Singularity Functions are not defined for exponents less than -2.")
  143. if shift.is_extended_negative:
  144. return S.Zero
  145. if n.is_nonnegative and shift.is_extended_nonnegative:
  146. return (x - a)**n
  147. if n in (S.NegativeOne, -2):
  148. if shift.is_negative or shift.is_extended_positive:
  149. return S.Zero
  150. if shift.is_zero:
  151. return S.Infinity
  152. def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
  153. '''
  154. Converts a Singularity Function expression into its Piecewise form.
  155. '''
  156. x = self.args[0]
  157. a = self.args[1]
  158. n = sympify(self.args[2])
  159. if n in (S.NegativeOne, -2):
  160. return Piecewise((oo, Eq((x - a), 0)), (0, True))
  161. elif n.is_nonnegative:
  162. return Piecewise(((x - a)**n, (x - a) > 0), (0, True))
  163. def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
  164. '''
  165. Rewrites a Singularity Function expression using Heavisides and DiracDeltas.
  166. '''
  167. x = self.args[0]
  168. a = self.args[1]
  169. n = sympify(self.args[2])
  170. if n == -2:
  171. return diff(Heaviside(x - a), x.free_symbols.pop(), 2)
  172. if n == -1:
  173. return diff(Heaviside(x - a), x.free_symbols.pop(), 1)
  174. if n.is_nonnegative:
  175. return (x - a)**n*Heaviside(x - a)
  176. def _eval_as_leading_term(self, x, logx=None, cdir=0):
  177. z, a, n = self.args
  178. shift = (z - a).subs(x, 0)
  179. if n < 0:
  180. return S.Zero
  181. elif n.is_zero and shift.is_zero:
  182. return S.Zero if cdir == -1 else S.One
  183. elif shift.is_positive:
  184. return shift**n
  185. return S.Zero
  186. def _eval_nseries(self, x, n, logx=None, cdir=0):
  187. z, a, n = self.args
  188. shift = (z - a).subs(x, 0)
  189. if n < 0:
  190. return S.Zero
  191. elif n.is_zero and shift.is_zero:
  192. return S.Zero if cdir == -1 else S.One
  193. elif shift.is_positive:
  194. return ((z - a)**n)._eval_nseries(x, n, logx=logx, cdir=cdir)
  195. return S.Zero
  196. _eval_rewrite_as_DiracDelta = _eval_rewrite_as_Heaviside
  197. _eval_rewrite_as_HeavisideDiracDelta = _eval_rewrite_as_Heaviside