Source code for diofant.functions.special.delta_functions

from ...core import Eq, Function, Integer, Rational, diff, sympify
from ...core.function import ArgumentIndexError
from ...polys.polyerrors import PolynomialError
from ..elementary.complexes import im, sign
from ..elementary.piecewise import Piecewise

###############################################################################
# ############################## DELTA FUNCTION ############################# #
###############################################################################

[docs]class DiracDelta(Function):
"""
The DiracDelta function and its derivatives.

DiracDelta function has the following properties:

1) diff(Heaviside(x),x) = DiracDelta(x)
2) integrate(DiracDelta(x-a)*f(x),(x,-oo,oo)) = f(a) and
integrate(DiracDelta(x-a)*f(x),(x,a-e,a+e)) = f(a)
3) DiracDelta(x) = 0 for all x != 0
4) DiracDelta(g(x)) = Sum_i(DiracDelta(x-x_i)/abs(g'(x_i)))
Where x_i-s are the roots of g

Derivatives of k-th order of DiracDelta have the following property:

5) DiracDelta(x,k) = 0, for all x != 0

========

diofant.functions.special.delta_functions.Heaviside
diofant.simplify.simplify.simplify
diofant.functions.special.delta_functions.DiracDelta.is_simple
diofant.functions.special.tensor_functions.KroneckerDelta

References
==========

* http://mathworld.wolfram.com/DeltaFunction.html

"""

is_commutative = True

def fdiff(self, argindex=1):
if argindex == 1:
# I didn't know if there is a better way to handle default arguments
k = 0
if len(self.args) > 1:
k = self.args[1]
return self.func(self.args[0], k + 1)
else:
raise ArgumentIndexError(self, argindex)

@classmethod
def eval(cls, arg, k=0):
k = sympify(k)
if not k.is_Integer or k.is_negative:
raise ValueError("Error: the second argument of DiracDelta must be \
a non-negative integer, %s given instead." % (k,))
arg = sympify(arg)
if arg.is_nonzero:
return Integer(0)

[docs]    def simplify(self, x):
"""simplify(self, x)

Compute a simplified representation of the function using
property number 4.

x can be:

- a symbol

Examples
========

>>> DiracDelta(x*y).simplify(x)
DiracDelta(x)/Abs(y)
>>> DiracDelta(x*y).simplify(y)
DiracDelta(y)/Abs(x)

>>> DiracDelta(x**2 + x - 2).simplify(x)
DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3

========

diofant.functions.special.delta_functions.DiracDelta.is_simple
diofant.functions.special.delta_functions.DiracDelta

"""
from ...polys import roots

if not self.args[0].has(x) or (len(self.args) > 1 and self.args[1] != 0 ):
return self
try:
argroots = roots(self.args[0], x)
result = 0
valid = True
darg = abs(diff(self.args[0], x))
for r, m in argroots.items():
if r.is_extended_real is not False and m == 1:
result += self.func(x - r)/darg.subs({x: r})
else:
# don't handle non-real and if m != 1 then
# a polynomial will have a zero in the derivative (darg)
# at r
valid = False
break
if valid:
return result
except PolynomialError:
pass
return self

[docs]    def is_simple(self, x):
"""is_simple(self, x)

Tells whether the argument(args[0]) of DiracDelta is a linear
expression in x.

x can be:

- a symbol

Examples
========

>>> DiracDelta(x*y).is_simple(x)
True
>>> DiracDelta(x*y).is_simple(y)
True

>>> DiracDelta(x**2+x-2).is_simple(x)
False

>>> DiracDelta(cos(x)).is_simple(x)
False

========

diofant.simplify.simplify.simplify
diofant.functions.special.delta_functions.DiracDelta

"""
p = self.args[0].as_poly(x)
if p:
return p.degree() == 1
return False

@staticmethod
def _latex_no_arg(printer):
return r'\delta'

return self

def _eval_conjugate(self):
return self

def _eval_transpose(self):
return self

###############################################################################
# ############################ HEAVISIDE FUNCTION ########################### #
###############################################################################

[docs]class Heaviside(Function):
r"""Heaviside step function

.. math ::
H(x) = \left\{\begin{matrix}0, x < 0\\
1/2, x = 0\\ 1, x > 0 \end{matrix}\right.

========

diofant.functions.special.delta_functions.DiracDelta

References
==========

* https://en.wikipedia.org/wiki/Heaviside_step_function

"""

def fdiff(self, argindex=1):
if argindex == 1:
return DiracDelta(self.args[0])
else:
raise ArgumentIndexError(self, argindex)

@classmethod
def eval(cls, arg):
arg = sympify(arg)
if im(arg).is_nonzero:
raise ValueError("Function defined only for Real Values. Complex part: %s  found in %s ." % (repr(im(arg)), repr(arg)) )
elif arg.is_negative:
return Integer(0)
elif arg.is_zero:
return Rational(1, 2)
elif arg.is_positive:
return Integer(1)

def _eval_rewrite_as_Piecewise(self, arg):
if arg.is_extended_real:
return Piecewise((1, arg > 0), (Rational(1, 2), Eq(arg, 0)), (0, True))

def _eval_rewrite_as_sign(self, arg):
if arg.is_extended_real:
return (sign(arg)+1)/2

def _eval_is_real(self):
if self.args[0].is_extended_real:
return True