1

currently I'm struggeling a little bit with the output from SymPy. By default, by executing the following (assuming using Jupyter Notebook):

from sympy import *

t, x = symbols('t x')
u    = Function('u')(t, x)

display(Eq(I*u.diff(t) + u.diff(x,x) + abs(u)**2*u))

it prints

Default output

I want to have it like this, however

Desired output

in order to increase readability. Has anyone a clue how to achieve this? I'm rather new to SymPy and really would like to get this output.

Looking forward to your answers!

EDIT1:

I took the suggestions from @smichr, tweaked it a little and wrote it into a function. Hopefully I covered everything important. Here is the function

# Assuming that symbols and functions with greek letters are defined like this
# omega = Function('\\omega')(t, x)

def show(expr):
    functions = expr.atoms(Function)
    reps = {}

    for fun in functions:
        # Consider the case that some functions won't have the name
        # attribute e.g. Abs of an elementary function
        try:            
            reps[fun] = Symbol(fun.name) # Otherwise functions with greek symbols aren't replaced
        except AttributeError:
            continue

    dreps = [(deriv, Symbol(deriv.expr.subs(reps).name + "_{," + 
                            ''.join(par.name for par in deriv.variables) + "}"))  \
             for deriv in expr.atoms(Derivative)]

    # Ensure that higher order derivatives are replaced first, then lower ones. 
    # Otherwise you get d/dr w_r instead of w_rr
    dreps.sort(key=lambda x: len(x[0].variables), reverse=True)
    output = expr.subs(dreps).subs(reps)

    display(output)

zeta, eta = symbols('\\zeta \\eta')
psi       = Function('\\psi')(zeta, eta)

eq = Eq(I*psi.diff(zeta) + psi.diff(eta, eta) + abs(psi)**2*psi, 0)
show(eq)

which shows Edited functiuons output

fwillo
  • 77
  • 1
  • 8

1 Answers1

1

The Derivative (like all SymPy objects) has arguments -- sometimes named -- and you can do with those whatever is useful to you. In this case it looks like replacing the function with a letter and the derivative variables as a composite symbol is what you want. Here is an attempt at that that can be tweaked as necessary:

>>> reps={u:'u'}
>>> dreps = [(i,i.expr.subs(reps).name+"_"+''.join(v.name for v in i.variables)
    for i in eq.atoms(Derivative)]
>>> eq.subs(dreps).subs(reps)
u*Abs(u)**2 + I*u_t + u_xx

Getting them is a certain order, however, requires changing the associated Printer. See, for example, here.

smichr
  • 16,948
  • 2
  • 27
  • 34
  • Thank you for your response! I did examine your procedure and tested around. Something I wanted to have aswell were commatas, indicating partial derivatives (because I might work with tensors). I modified your lines such that dreps outputs in this case `(Derivative(u(t, x), t), 'u_{,t}')` instead of `(Derivative(u(t, x), t), 'u_t')`. SymPy now prints the equation with a total differentiation, however. I assume I can somehow disable this behaviour? – fwillo Apr 23 '20 at 11:48
  • Sorry, I'm not sure what you mean by "disable". What are you seeing and what don't you want to see? – smichr Apr 23 '20 at 12:36
  • My idea was to have a comma as subscript to indicate partial differentiation. Nevertheless my problem was that the `dreps` was not sorted, and that `sympify` did not support comma characters subsript. I solved the issue. Please take a look at the edit of my main post. I wrote a function based on your idea, which should cover most cases. Nevertheless, thank you very much for the inspiration! – fwillo Apr 23 '20 at 14:54
  • 1
    :-) looks good. And I was going to suggest using Symbo rather than pure string. (I hardly ever use strings but took my cue from your post.) I hope others find yout function useful. – smichr Apr 23 '20 at 15:09