Processing math: 100%

First time here? Check out the FAQ!

Ask Your Question
1

How to simplify dirac_delta?

asked 4 years ago

mforbes gravatar image

updated 4 years ago

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)?

Preview: (hide)

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 ( 4 years ago )

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 ( 4 years ago )

2 Answers

Sort by » oldest newest most voted
2

answered 4 years ago

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)δ(x)+e2xδ(x)+3sin(4x)δ(x)+9e3x. The simplification rules transform this expression into cos(x)δ(x)+2e2xδ(x)+12cos(4x)δ(x)+9e3x=(1+2+12)δ(x)+9e3x=15δ(x)+9e3x. 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

Preview: (hide)
link
2

answered 4 years ago

Florentin Jaffredo gravatar image

updated 4 years ago

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.

Preview: (hide)
link

Comments

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

Juanjo gravatar imageJuanjo ( 4 years ago )

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 ( 4 years ago )

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: 4 years ago

Seen: 497 times

Last updated: Jun 08 '20