Ask Your Question
1

How to simplify dirac_delta?

asked 2020-06-06 08:16:37 +0100

mforbes gravatar image

updated 2020-06-06 10:59:53 +0100

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 flag offensive close merge delete

Comments

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

ortollj gravatar imageortollj ( 2020-06-06 09:12:57 +0100 )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.

mforbes gravatar imagemforbes ( 2020-06-06 10:59:34 +0100 )edit

2 Answers

Sort by ยป oldest newest most voted
2

answered 2020-06-06 15:59:32 +0100

Juanjo gravatar image

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

edit flag offensive delete link more
2

answered 2020-06-08 12:39:56 +0100

Florentin Jaffredo gravatar image

updated 2020-06-08 13:40:20 +0100

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.

edit flag offensive delete link more

Comments

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

Juanjo gravatar imageJuanjo ( 2020-06-08 16:33:19 +0100 )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 ?

Florentin Jaffredo gravatar imageFlorentin Jaffredo ( 2020-06-08 17:15:17 +0100 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2020-06-06 08:16:37 +0100

Seen: 472 times

Last updated: Jun 08 '20