AttributeError: 'Mul' object has no attribute 'eval'

0

I have a problem with this code, which calculates the eigenstates for the quantum harmonic oscillator and evaluates it in a given time. In turn, I try to plot all the state subplots for each value of n. But this error appears:

for i in xx: rePsi.eval(i)
AttributeError: 'Mul' object has no attribute 'eval'*

This is my code:

import numpy as np
import matplotlib.pylab as plt
import sympy as sym
from math import *

w=1
m=1
hbar=1
x = sym.symbols ('x')
a=-1
b=1
phi_n=0
psi=0
plt.ylim(-1,1 )
plt.xlim(-3,3)

print('give me number of states?')
nn = int(input())
if (nn<0):
    print 'must be >=0\n'
if (nn>=0):
    print('time to evaluate')
    t = float(input())
    if (t<0):
        print 'Time must be >=0'

print '   '

mr = float((m*w/(hbar*pi))**0.25)
gaussq = sym.exp(-m*w*x**2/(2*hbar))

fig = [0 for i in range(nn)]
fig1 = plt.figure(1)

xx = np.arange(-3., 3.,0.1)
for n in range (0,nn,2):
    H_root = sym.sqrt(1/(2**n*float(sym.factorial(n))))
    Hermite = (-1)**n*sym.exp(m*w*x**2/hbar)*sym.diff(sym.exp(-m*w*x**2/hbar),x,n)
    Energy = hbar*w*(n+0.5)
    phi_n = sym.simplify(H_root*mr*gaussq*Hermite)
    arg_int = sym.simplify(phi_n*gaussq*mr)
    c_n = sym.simplify(sym.integrate(arg_int, (x,a,b)))
    psi_n = c_n*phi_n*sym.exp(-1j*w*t*(n+0.5))
    psi_n_re = sym.re(psi_n)
    psi_n_im = sym.im(psi_n)
    psi += sym.simplify(psi_n)
    rePsi = sym.re(psi) 
    imPsi = sym.im(psi)
    print type (rePsi)
    print type (imPsi)
    for i in xx: rePsi.eval(i)
    for i in xx: imPsi.eval(i)
    list_rePsi= rePsi
    list_imPsi= imPsi
    plt.subplot(nn, 1, (n+2)/2)
    plt.plot(xx,list_repsi)
    plt.plot(xx,list_impsi)

plt.show()
print '\n'+str(psi)
    
asked by David Barrero González 30.09.2018 в 23:44
source

1 answer

1

Indeed the eval method does not exist for the SymPy expressions, what you should do is replace the variable (symbol x ) in any case. For this the simplest thing is to use the method subs and if you want the numerical value evalf next to subs . This substitution must be done for each value of xx .

The code with some modifications, mainly in the validation of the entry and in the creation of the graphics could look like this:

import numpy as np
import matplotlib.pylab as plt
import sympy as sym
from math import ceil


w = 1
m = 1

hbar = 1
x = sym.symbols ('x')
a = -1
b = 1
phi_n = 0
psi = 0
plt.ylim(-1, 1)
plt.xlim(-3, 3)



try:
    nn = int(raw_input('Give me number of states: '))
except ValueError:
    raise ValueError('Number of states must be integuer')
else:
    if nn < 0:
        raise ValueError('Number of states must be >= 0')

try:
    t = float(input('Time to evaluate: '))
except ValueError:
    raise ValueError('Number of states must be float')
else:
    if nn < 0:
        raise ValueError('Time must be >= 0')


mr = float((m * w / (hbar * sym.pi)) ** 0.25)
gaussq = sym.exp(-m * w * x ** 2 / (2 * hbar))

fig = plt.figure()
fig.subplots_adjust(hspace=0.7)
xx = np.arange(-3.0, 3.0, 0.1)

for n in xrange(0, nn, 2):
    h_root = np.sqrt(1 / (2 ** n * float(sym.factorial(n))))
    hermite = (-1 ** n * sym.exp(m * w * x ** 2 / hbar) *
              sym.diff(sym.exp(-m * w * x ** 2 / hbar), x, n))

    energy = hbar * w * (n + 0.5)
    phi_n = sym.simplify(h_root * mr * gaussq * hermite)
    arg_int = sym.simplify(phi_n * gaussq * mr)
    c_n = sym.simplify(sym.integrate(arg_int, (x, a, b)))
    psi_n = c_n * phi_n * sym.exp(-1j * w * t * (n + 0.5))
    psi_n_re = sym.re(psi_n)
    psi_n_im = sym.im(psi_n)
    psi += sym.simplify(psi_n)
    re_psi = sym.re(psi) 
    im_psi = sym.im(psi)

    list_re_psi= [re_psi.subs(x, i) for i in xx]
    list_im_psi= [im_psi.subs(x, i) for i in xx]

    ax = fig.add_subplot(ceil(nn / 2.0), 1, (n + 2) / 2)
    ax.plot(xx, list_re_psi)
    ax.plot(xx, list_im_psi)
    ax.set_title("n = {}".format(n))


plt.show()
print('\n' + str(psi))

Matplotlib does not need the expression to be explicitly evaluated, but if we want the lists to contain the numerical values and not expressions we can use evalf as was mentioned before:

list_im_psi= [im_psi.evalf(subs={x: i}) for i in xx]

It is necessary to take into account subs + evalf is slow, although in this case the array xx is small and the impact is scarce, taking into account that integration is the most expensive part by far. The optimum is to use sympy.lambdify and apply the function in vectorized form on the array:

re_psi_func = sym.lambdify(x, re_psi, "numpy")
list_re_psi = re_psi_func(xx)

The problem is that unless in my case with SymPy 1.3 and Numpy 1.15.0 fails to convert sympy.im to numpy.imag in the process , in what is apparently a bug.

    
answered by 02.10.2018 в 03:11