Partial derivative notation in Sage

This post will explain the notation used to denote partial derivatives in the output from Sage.  It’s confusing at first, but a simple example will make it clear. Here is the input to Sage:

var('x y')
function('test', x, y)
show(test(x, y))
show(diff(test(x, y), x))
show(diff(test(x, y), x, 2))
show(diff(test(x, y), y))
show(diff(test(x, y), y, 2))

I defined a function of two variables called test.  When you run this in the notebook interface, you get:

test(x,y)
D[0](test)(x,y)
D[0,0](test)(x,y)
D[1](test)(x,y)
D[1,1](test)(x,y)

The capital D denotes a derivative. The numbers in brackets indicate which variable the derivative is with respect to. In this example, 0 denotes x and 1 denotes y. The number of times a number is repeated indicates the order of the derivative. D[0] is the first derivative with respect to x, D[1] is the first derivative with respect to y, D[0,0] is the second derivative with respect to x and D[1,1] is the second derivative with respect to y.  Sage uses the same notation when typesetting equations in LaTeX, so you will have to do some manual typsetting if you want traditional partial derivative notation.
Why does Sage do it this way instead of using traditional notation?  The reason is that test is defined as a function of two variables, but Sage doesn’t know in advance what these variables will be.  test may be a function of two other functions, in which the chain rule would have to be used to display the derivatives correctly.  The extensive discussion that went into this design decision is archived in this thread.
If you’re new to Sage, I suggest you check out my Sage Beginner’s Guide.

5 thoughts on “Partial derivative notation in Sage”

  1. Math should be pretty. I find D[0](test)(x, y) ugly. I don’t mind if computers have to keep things organized for themselves. It is unfortunate that in my initial looking around, there is no pretty_print() option to make it look like a read would expect. I would happily import a module that could transform D notation to partial derivatives. Is there one out there?

  2. The thread you reference appears to uniformly consist of agreement that the D[0]f format should change, and the discussion revolves around what it should change to. Were these changes never implemented?

  3. Here is a klunky example of producing traditional format derivatives including derivatives with respect to functions:
    reset()
    R_w_c(R_w,N) = 1-(1-R_w)^(1/N)
    R_e_c(R_w,E) = E * R_w_c/(E * R_w_c + 1 – R_w_c)
    R_s(R_w,R_a,E) = 1-(1-R_a)*(1-R_e_c)^N
    dSol(R_w,R_a,E,N) = diff(R_s / R_w,R_w)
    html(‘The expanded expression, not very pretty or useful:’)
    html(”)
    dSolStr = str(latex(dSol))
    html(‘$’+dSolStr+’$’)
    reset()
    var(‘R_w, E, a, b’)
    var(‘N’,domain = ‘integer’)
    R_a = function(‘R_a’,R_w)
    R_w_c = function(‘R_w_c’,R_w,N)
    R_e_c = function(‘R_e_c’,R_w_c,E)
    R_s = function(‘R_s’,R_a,R_e_c)
    Sol = R_w/R_s
    dSol = diff(Sol,R_w)
    dSol
    html(”)
    html(”)
    html(‘The Sage representation of the functional form, not very readable:’)
    html(”)
    dSolStr = str(latex(dSol))
    html(‘$’+dSolStr+’$’)
    var(‘dRadRw,dRecdRw,dRwcdRw’)
    dSol2 = dSol
    dSol2 = dSol2.subs(diff(R_a,R_w) == dRadRw)
    dSol2 = dSol2.subs(diff(R_w_c(R_w,N),R_w) == dRwcdRw)
    dSol2 = dSol2.subs(diff(R_e_c,R_w) == dRecdRw)
    var(‘Ra, Rec, Rs, Rwc’)
    dSol2 = dSol2.subs(function(‘R_s’,R_a,R_e_c) == Rs)
    dSol2 = dSol2.subs(function(‘R_a’,R_w) == Ra)
    dSol2 = dSol2.subs(function(‘R_e_c’,R_w_c,E) == Rec)
    dSol2 = dSol2.subs(function(‘R_w_c’,R_w,N) == Rwc)
    var(‘dRecdRwc,dRsdRa,dRsdRec’)
    dSol2 = dSol2.subs(diff(R_e_c(Rwc,E),Rwc) == dRecdRwc)
    dSol2 = dSol2.subs(diff(R_w_c(R_w,N),R_w) == dRwcdRw)
    dSol2 = dSol2.subs(diff(R_s(Ra,Rec),Ra) == dRsdRa)
    dSol2 = dSol2.subs(diff(R_s(Ra,Rec),Rec) == dRsdRec)
    solTexStr = str(latex(dSol2))
    solTexStr = solTexStr.replace(‘\mbox’,”)
    solTexStr = solTexStr.replace(‘dRecdRwc’,'{operatorname{d}!R_{e_c}overoperatorname{d}!R_{w_c}}’)
    solTexStr = solTexStr.replace(‘dRsdRec’,'{operatorname{d}!R_{s}overoperatorname{d}!R_{e_c}}’)
    solTexStr = solTexStr.replace(‘dRwcdRw’,'{operatorname{d}!R_{w_c}overoperatorname{d}!R_{w}}’)
    solTexStr = solTexStr.replace(‘dRadRw’,'{operatorname{d}!R_{a}overoperatorname{d}!R_{w}}’)
    solTexStr = solTexStr.replace(‘dRsdRa’,'{operatorname{d}!R_{s}overoperatorname{d}!R_{a}}’)
    solTexStr = solTexStr.replace(‘Rs’,’R_s’)
    html(”)
    html(”)
    html(‘Traditional format:’)
    html(”)
    html(‘${operatorname{d}!Soveroperatorname{d}!R_{w}}=’+solTexStr+’$’)
    reset()
    var(‘R_w, E, a, b’)
    var(‘N’,domain = ‘integer’)
    html(”)
    html(”)
    html(‘Where:’)
    R_a = a * R_w + b
    dRadRw = diff(R_a,R_w)
    html(‘${operatorname{d}!R_{a}overoperatorname{d}!R_{w}}=’+str(latex(dRadRw))+’$’)
    R_w_c(R_w,N) = 1-(1-R_w)^(1/N)
    dRwcdRw = diff(R_w_c, R_w)
    html(”)
    html(”)
    html(‘${operatorname{d}!R_{w_c}overoperatorname{d}!R_{w}}=operatorname{f}’+str(latex(dRwcdRw))+’$’)
    R_e_c(R_w_c,E) = E * R_w_c/(E * R_w_c + 1 – R_w_c)
    dRecdRwc = diff(R_e_c, R_w_c)
    html(”)
    html(”)
    html(‘${operatorname{d}!R_{e_c}overoperatorname{d}!R_{w_c}}=operatorname{f}’+str(latex(dRecdRwc))+’$’)
    R_s(R_e_c,R_a) = 1-(1-R_a)*(1-R_e_c)^N
    dRsdRa = diff(R_s,R_a)
    html(”)
    html(”)
    html(‘${operatorname{d}!R_{s}overoperatorname{d}!R_{a}}=operatorname{f}’+str(latex(dRsdRa))+’$’)
    dRsdRec = diff(R_s,R_e_c)
    html(”)
    html(”)
    html(‘${operatorname{d}!R_{s}overoperatorname{d}!R_{e_c}}=operatorname{f}’+str(latex(dRsdRec))+’$’)

    1. Unfortunately the website has typeset my code differently from the original, so getting this to work requires some find and replace of ‘ and “.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.