# How to simplify dirac_delta?

Various manipulations are possible with dirac_delta and its derivatives. How can I teach sage to simplify these? For example, the following Green's function for a free particle in 1D could simplify to simply dirac_delta(x):

sage: var('x,k')
sage: G = heaviside(x)*sin(k*x)/k
sage: simplify(k**2*G + diff(G, x, x))
2*cos(k*x)*dirac_delta(x) + sin(k*x)*diff(dirac_delta(x), x)/k


How can I teach sage to perform the following simplifications

f(x)*dirac_delta(x)
-> f(0)*dirac_delta(x)
f(x)*diff(dirac_delta(x),x)
-> diff(f(x), x)*dirac_delta(x)
-> diff(f(x), x).subs(x=0)*dirac_delta(x)


which would bring the answer into the desired form dirac_delta(x)?

edit retag close merge delete

just out of curiosity: can someone tell me what it means to use this %var x, k syntax instead of var('x,k') ?

( 2020-06-06 02:12:57 -0500 )edit

Ah, sorry, that is a feature of https://doc.cocalc.com/sagews.html (Sage worksheets) on CoCalc. It is the same thing. I will remove it.

( 2020-06-06 03:59:34 -0500 )edit

Sort by ยป oldest newest most voted

Consider the following code:

def simplify_dirac_delta(linear_combination, t):
r"""
Simplify a linear combination of the form

a_0(t) + a_1(t)*d_1(t) + a_2(t)*d_2(t) + ... + a_n(t)*d_n(t)

where each a_i(t) is a symbolic expression depending
on the symbolic variable t and each d_i(t) is
either dirac_delta(t) or diff(dirac_delta(t), t).

Simplification is done by applying the following
substitution rules:

(Rule 1)   f(t) * diff(dirac_delta(t), t)
--> diff(f(t), t) * dirac_delta(t)
(Rule 2)   f(t) * dirac_delta(t)
--> f(0) * dirac_delta(t)
"""
# Write the linear combination in the form
#         c_0(t) + c_1(t) * diff(dirac_delta(t),t)
# and apply Rule 1
var("dd")
expression = linear_combination.collect(diff(dirac_delta(t),t))
expr = expression.subs({diff(dirac_delta(t),t): dd})
c_0 = expr.coefficient(dd,0)
c_1 = expr.coefficient(dd,1)
dc_1 = diff(c_1,t)
expression = c_0 + dc_1*dirac_delta(t)
# Write now the resulting linear combination in the form
#         c_0(t) + c_1(t) * dirac_delta(t),t)
# and apply Rule 2
expression = expression.collect(dirac_delta(t))
expr = expression.subs({dirac_delta(t): dd})
c_0 = expr.coefficient(dd,0)
c_1 = expr.coefficient(dd,1)
return c_0 + c_1.subs({t:0})*dirac_delta(t)


The docstring and comments explain quite explicitly what simplify_dirac_delta does. Let us test this function. To this end, let us consider $$\cos(x)\, \delta(x)+e^{2x}\,\delta'(x)+3\sin(4x)\,\delta'(x)+9e^{3x}.$$ The simplification rules transform this expression into \begin{aligned} &\cos(x)\,\delta(x)+2e^{2x}\delta(x)+12\cos(4x)\,\delta(x)+9e^{3x} \\ &\qquad=(1+2+12)\delta(x)+9e^{3x}=15\delta(x)+9e^{3x}. \end{aligned} Now we apply simplify_dirac_delta:

sage: DD = dirac_delta(x)
sage: dDD = diff(dirac_delta(x),x)
sage: expr = cos(x)*DD + exp(2*x)*dDD + 3*sin(4*x)*dDD + 9*exp(3*x)
sage: simplify_dirac_delta(expr,x)
15*dirac_delta(x) + 9*e^(3*x)


We get the expected result. Now, let us consider your example:

sage: var('x,k')
(x, k)
sage: G = heaviside(x)*sin(k*x)/k
sage: expr = simplify(k**2*G + diff(G, x, x)); expr
2*cos(k*x)*dirac_delta(x) + sin(k*x)*diff(dirac_delta(x), x)/k
sage: simplify_dirac_delta(expr,x)
3*dirac_delta(x)


Once again we obtain the expected result.

The above code and the examples can be run in this SageMath Cell

more

Here is a more generic code, making use of wildcards. It should work in many more cases than just linear combinations. It also makes it easier to add new rules.

def simplify_dirac_delta(E, t):
"""
Apply some rules on expression E as long as it changes. The rules depend on a parameter t.
"""
w = SR.wild(0)

rules = {w*dirac_delta(t): lambda f: f.subs({t: 0})*dirac_delta(t),
w*diff(dirac_delta(t), t): lambda f: diff(f, t)*dirac_delta(t)}

def apply_rules():
nonlocal E
for r in rules:
for e in E.find(r):
f = e.match(r)[w]
E = E.substitute({e: rules[r](f)})
return E

while(E!=apply_rules()):
pass

return E


it can be used like this:

sage: simplify_dirac_delta(k**2*G + diff(G, x, x), x)
3*dirac_delta(x)


Simplifications rules are given as a dictionary. The function will try to apply these rules as long as the result changes, so you have to make sure that your rules can't loop back (alternatively you can delete the loop, and only apply the rules a fixed number of times).

Unfortunately, diff is not a symbolic function and does not accept wildcards, so I don't know how to match a derivative, and it is necessary to pass x as an argument.

more

Very interesting answer. I've learn a lot from it.

( 2020-06-08 09:33:19 -0500 )edit

I'm glad it was useful. I use this kind of custom simplification all the time. Perhaps there should be an option in simplify_full to add user-defined rules ?

( 2020-06-08 10:15:17 -0500 )edit