I am receiving the error stated in the title. Full error:
MaxD = Cone*np.sqrt(SymsX/np.pi)*np.exp((-SymsX/(k*T))) #Define Maxwellian distribution function
AttributeError: 'Mul' object has no attribute 'sqrt'
Here is the code:
from sympy.interactive import printing
printing.init_printing(use_latex = True)
import numpy as np
from sympy import Eq, dsolve, Function, Symbol, symbols
import sympy as sp
EpNaut = 8.854187E-12
u0 = 1.256E-6
k = 1/(4*np.pi*EpNaut)
NumGen = 1000 #How many solution points user wants to generate between 0 and maxen (Higher # the more accurate)
T = 1000 #Temperature in (K)
MaxEn = 7*T*k #Max energy in system
Cone = 2/((k*T)**(3/2)) #Constant infront of the Maxwellian distribution function
SymsX = sp.Symbol('SymsX')
MaxD = Function('MaxD')
PFunction = Function('PFunction')
MaxD = Cone*np.sqrt(SymsX/np.pi)*np.exp((-SymsX/(k*T))) #Define Maxwellian distribution function
PFunction = sp.integrate(MaxD) #Integrate function to get probability-error function
print(PFunction)
I also have an additional question. I sometimes see examples use "from ... import ...". Why is this? Shouldn't just importing the entire library be enough? Is it because using the import command doesn't actually import the entire library but really just the most basic functions?
In an isympy session:
In [1]: import numpy as np
In [3]: SymsX = Symbol('SymsX')
In [5]: SymsX/np.pi # symbol * float
Out[5]: 0.318309886183791⋅SymsX
In [6]: SymsX/pi # symbol * symbol
Out[6]:
SymsX
─────
π
In [7]: sqrt(SymsX/pi) # sympy sqrt
Out[7]:
_______
╲╱ SymsX
─────────
√π
In [8]: np.sqrt(SymsX/pi) # numeric sqrt
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
AttributeError: 'Mul' object has no attribute 'sqrt'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
<ipython-input-8-27f855f6b3e2> in <module>
----> 1 np.sqrt(SymsX/pi)
TypeError: loop of ufunc does not support argument 0 of type Mul which has no callable sqrt method
np.sqrt has to first convert its input into a numpy array:
In [10]: np.array(SymsX/np.pi)
Out[10]: array(0.318309886183791*SymsX, dtype=object)
This is an object dtype array, not a normal numeric one. Given such an array, q numpy ufunc tries to delegate the action to a element method. e.g. (0.31*SymsX).sqrt()
Multiply and addition do work with this object array:
In [11]: 2*_
Out[11]: 0.636619772367581⋅SymsX
In [12]: _ + __
Out[12]: 0.954929658551372⋅SymsX
These work because the sympy object has the right add and multiply methods:
In [14]: Out[5].__add__
Out[14]: <bound method Expr.__add__ of 0.318309886183791*SymsX>
In [15]: Out[5]+2*Out[5]
Out[15]: 0.954929658551372⋅SymsX
===
The sympy.lambdify is the best tool for using sympy and numpy together. Look up its docs.
In this case the SymsX/pi expression can be converted into a numpy expression with:
In [18]: lambdify(SymsX, Out[5],'numpy')
Out[18]: <function _lambdifygenerated(SymsX)>
In [19]: _(23) # evaluate with `SymsX=23`:
Out[19]: 7.321127382227194
In [20]: 23/np.pi
Out[20]: 7.321127382227186
In [21]: np.sqrt(_19) # np.sqrt now works on the number
Out[21]: 2.7057581899030065
====
The same evaluation in sympy:
In [23]: expr = sqrt(SymsX/pi)
In [24]: expr
Out[24]:
_______
╲╱ SymsX
─────────
√π
In [25]: expr.subs(SymsX, 23)
Out[25]:
√23
───
√π
In [27]: _.evalf()
Out[27]: 2.70575818990300
In a fresh isympy session:
These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()
Documentation can be found at https://docs.sympy.org/1.4/
In [1]: EpNaut = 8.854187E-12
...: u0 = 1.256E-6
...: k = 1/(4*pi*EpNaut)
...: NumGen = 1000
...: T = 1000
...: MaxEn = 7*T*k
...: Cone = 2/((k*T)**(3/2))
...:
...: SymsX = Symbol('SymsX')
...: MaxD = Function('MaxD')
...: PFunction = Function('PFunction')
...: MaxD = Cone*sqrt(SymsX/pi)*exp((-SymsX/(k*T))) #Define Maxwellian distri
...: bution function
...: PFunction = integrate(MaxD) #Integrate function to get probability-error
...: function
...:
The result:
In [2]: PFunction
Out[2]:
⎛ _______ -3.5416748e-14⋅π⋅Syms
1.0 ⎜ 28235229276273.5⋅╲╱ SymsX ⋅ℯ
1.33303949775482e-20⋅π ⋅⎜- ─────────────────────────────────────────────────
⎝ π
X ⎛ _______⎞⎞
7.50165318945357e+19⋅erf⎝1.88193379267178e-7⋅√π⋅╲╱ SymsX ⎠⎟
─ + ──────────────────────────────────────────────────────────⎟
π ⎠
In [3]: MaxD
Out[3]:
1.0 _______ -3.5416748e-14⋅π⋅SymsX
1.33303949775482e-20⋅π ⋅╲╱ SymsX ⋅ℯ
SymsX is still a symbol, so these are sympy expressions, not numbers.
Related
How can I convert a sympy expression to numpy code? For example, say I this was the code for the expression:
expression = 2 * x/y + 10 * sympy.exp(x) # Assuming that x and y are predefined from sympy.symbols
I would want to go from expression to this:
np_expression = "np.dot(2, np.dot(x, np.linalg.pinv(y))) + np.dot(10, np.exp(x))"
Note that x and y are matrices, but we can assume the shapes will match
An example with real numbers would go like this:
a = np.array([1,2],[3,4])
b = np.array([5,6],[7,8])
expression = 2 * a/b + 10 # These would be sympy symbols rather than numbers
and the result would be this:
np_expression = "np.dot(2, np.dot(5, np.linalg.pinv(9))) + 10"
In [1]: expr = 2 *x/y + 10 * exp(x)
In [3]: f = lambdify((x,y), expr)
In [4]: help(f)
_lambdifygenerated(x, y)
Created with lambdify. Signature:
func(x, y)
Expression:
2*x/y + 10*exp(x)
Source code:
def _lambdifygenerated(x, y):
return 2*x/y + 10*exp(x)
Which for specific inputs, array or otherwise:
In [5]: f(np.arange(1,5)[:,None], np.arange(1,4))
Out[5]:
array([[ 29.18281828, 28.18281828, 27.84948495],
[ 77.89056099, 75.89056099, 75.22389432],
[206.85536923, 203.85536923, 202.85536923],
[553.98150033, 549.98150033, 548.648167 ]])
In [6]: f(1,1)
Out[6]: 29.18281828459045
In [7]: f(2,3)
Out[7]: 75.22389432263984
In [8]: f(np.arange(1,4),np.arange(1,4))
Out[8]: array([ 29.18281828, 75.89056099, 202.85536923])
Normal array broadcasting rules apply. Note that x/y is element-wise. I'm not sure what lambdify will translate into dot and inv code.
trying your numpy code:
In [9]: np.dot(2, np.dot(2,np.linalg.pinv(3)))+10*np.exp(2)
---------------------------------------------------------------------------
LinAlgError Traceback (most recent call last)
<ipython-input-9-6cae91f0e0f8> in <module>
----> 1 np.dot(2, np.dot(2,np.linalg.pinv(3)))+10*np.exp(2)
....
LinAlgError: 0-dimensional array given. Array must be at least two-dimensional
We have to change the y into a 2d array, e.g. [[3]]:
In [10]: np.dot(2, np.dot(2,np.linalg.pinv([[3]])))+10*np.exp(2)
Out[10]: array([[75.22389432]])
I created a very simple MWE to illustrate my problem. When I type y**(2), the program works. But when I type sin(y) or cos(y), it results in the error TypeError: can't convert expression to float. I discuss attempts to fix this error below.
from vpython import *
from scipy.optimize import fsolve
import math
import numpy as np
import sympy as sp
from sympy import Eq, Symbol, solve
import matplotlib.pyplot as plt
y = Symbol('y')
i = input()
i = ''.join(i).split(',')
for x in range(0, len(i)):
i[x] = i[x].strip()
userMediums = i
def refIndexSize(medium):
def refractiveProfile(y):
return eval(medium, {'y': y, 'np': np})
lowerProfile = Eq(eval(medium), 1)
upperProfile = Eq(eval(medium), 1.6)
bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
abs(round(float(solve(upperProfile)[0]),5))]
lowerBound = np.amin(bounds)
upperBound = np.amax(bounds)
return lowerProfile
refIndexSize(userMediums[0])
Error:
sin(y)+1
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_48/825631216.py in <module>
29 return lowerProfile
30
---> 31 refIndexSize(userMediums[0])
/tmp/ipykernel_48/825631216.py in refIndexSize(medium)
20 return eval(medium, {'y': y, 'np': np})
21
---> 22 lowerProfile = eval(medium)
23 upperProfile = Eq(eval(medium), 1.6)
24 bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
<string> in <module>
/srv/conda/envs/notebook/lib/python3.7/site-packages/sympy/core/expr.py in __float__(self)
357 if result.is_number and result.as_real_imag()[1]:
358 raise TypeError("can't convert complex to float")
--> 359 raise TypeError("can't convert expression to float")
360
361 def __complex__(self):
TypeError: can't convert expression to float
I've looked at other questions regarding TypeError: can't convert expression to float, such as this and this. As a result, I have tried changing the order of my imports, although I can do nothing to change the wildcard from vpython import *, as it is the only way to import vpython (to my understanding), but this did not work. I've also tried inputting sp.sin(y) after looking at a different SO answer, but this did not help either. Once again, any tips or assistance is appreciated.
Your problem lies in this line:
bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
abs(round(float(solve(upperProfile)[0]),5))]
Specifically this part:
abs(round(float(solve(upperProfile)[0]),5))
Here the solve() function returns complex solutions in a list.
See this:
[1.5707963267949 - 1.04696791500319*I, 1.5707963267949 + 1.04696791500319*I]
So, when you pick the 0 index it will be a complex result like this one:
1.5707963267949 - 1.04696791500319*I
So, you are trying to cast float() to this solution which results in error. Instead you can remove the bounds for solutions having complex results by using try-except block like this:
try:
bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
abs(round(float(solve(upperProfile)[0]),5))]
lowerBound = np.amin(bounds)
upperBound = np.amax(bounds)
except:
print("The solutions are complex. Cant find a result")
Also import like this:
from vpython import *
from scipy.optimize import fsolve
import math
import numpy as np
import sympy as sp
from sympy import *
import matplotlib.pyplot as plt
In an ipython session, with the most relevant imports:
In [1]: import numpy as np
...: import sympy as sp
...: from sympy import Eq, Symbol, solve
Modify your function to return the bounds as well.
In [2]: def refIndexSize(medium):
...:
...: def refractiveProfile(y):
...: return eval(medium, {'y': y, 'np': np})
...:
...: lowerProfile = Eq(eval(medium), 1)
...: upperProfile = Eq(eval(medium), 1.6)
...: bounds = [abs(round(float(solve(lowerProfile)[0]),5)),
...: abs(round(float(solve(upperProfile)[0]),5))]
...: lowerBound = np.amin(bounds)
...: upperBound = np.amax(bounds)
...:
...: return lowerProfile, bounds
...:
Define the symbol, and call the function with a string. In the interactive session I don't need to go through the input complications.
In [3]: y = sp.Symbol('y')
y**2 gives the bounds that you claim in a comment:
In [4]: refIndexSize("y**(2)")
Out[4]: (Eq(y**2, 1), [1.0, 1.26491])
Errors due to sin definition
Using a sin expression gives a NameError. sin hasn't been imported or defined.
In [5]: refIndexSize("sin(y)+1")
Traceback (most recent call last):
File "<ipython-input-5-30c99485bce7>", line 1, in <module>
refIndexSize("sin(y)+1")
File "<ipython-input-2-6fea36c332b7>", line 6, in refIndexSize
lowerProfile = Eq(eval(medium), 1)
File "<string>", line 1, in <module>
NameError: name 'sin' is not defined
Import sin from math gives your error:
In [6]: from math import sin
In [7]: refIndexSize("sin(y)+1")
Traceback (most recent call last):
File "<ipython-input-7-30c99485bce7>", line 1, in <module>
refIndexSize("sin(y)+1")
File "<ipython-input-2-6fea36c332b7>", line 6, in refIndexSize
lowerProfile = Eq(eval(medium), 1)
File "<string>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/sympy/core/expr.py", line 359, in __float__
raise TypeError("can't convert expression to float")
TypeError: can't convert expression to float
math.sin expects a float value, so does not work with symbol y.
But import sin from sympy, and it works:
In [8]: from sympy import sin
In [9]: refIndexSize("sin(y)+1")
Out[9]: (Eq(sin(y) + 1, 1), [0.0, 0.6435])
Errors due to complex values
Originally your question showed the use of sin(y), which gives the complex error that #Prakash discusses
In [10]: refIndexSize("sin(y)")
Traceback (most recent call last):
File "<ipython-input-10-d470e7448a68>", line 1, in <module>
refIndexSize("sin(y)")
File "<ipython-input-2-6fea36c332b7>", line 9, in refIndexSize
abs(round(float(solve(upperProfile)[0]),5))]
File "/usr/local/lib/python3.8/dist-packages/sympy/core/expr.py", line 358, in __float__
raise TypeError("can't convert complex to float")
TypeError: can't convert complex to float
Let's simplify your function to get rid float call that seems to be giving problems
In [11]: def refIndexSize(medium):
...: lowerProfile = Eq(eval(medium), 1)
...: upperProfile = Eq(eval(medium), 1.6)
...: bounds = [solve(lowerProfile),
...: solve(upperProfile)]
...: return lowerProfile, bounds
...:
Run on sin(y)+1), we get the [0.0, 0.6435] values as before:
In [12]: refIndexSize("sin(y)+1")
Out[12]: (Eq(sin(y) + 1, 1), [[0, pi], [0.643501108793284, 2.49809154479651]])
Run on sin(y), we see that the 'raw' bounds includes complex values:
In [13]: refIndexSize("sin(y)")
Out[13]:
(Eq(sin(y), 1),
[[pi/2],
[1.5707963267949 - 1.04696791500319*I,
1.5707963267949 + 1.04696791500319*I]])
If you really need a rounded float from such an answer, you need to either extract the real part first, or use abs first:
In [15]: bounds = _[1][1]
In [17]: abs(bounds[0])
Out[17]: 1.88773486361789
In Jupyter Notebook i would like to define a equation, differentiate and plot the equation.
import sympy as sp
from IPython.display import display
sp.init_printing()
import matplotlib.pyplot as plt
import numpy as np
x = sp.symbols('x')
def func(x):
a= sp.sympify("4/5")
return (x**3+a*x**2)
display(func(x))
def dfunc(x):
a = sp.diff(func(x),x)
return a
display(dfunc(x))
x = np.linspace(-10,10,20)
plt.plot(x,func(x))
plt.plot(x,dfunc(x)) # doesn't work
display(dfunc(x)) shows the wanted function but plt.plot(x,dfunc(x)) returns the error message ValueError: cannot derive by this array
Does anyone know how to get the plot?
(It also doesn't work with sp.integrate(func(x),x) instead of sp.diff(func(x),x). Just another error message is returned ValueError: Invalid limits given: ...)
Many thanks in advance.
Matthias
You can use the SymPy plot function rather than the matplotlib one. The matplotlib plot function expects arrays as inputs whereas the sympy one accepts sympy expressions (and then calculates values to make the arrays for matplotlib):
In [36]: import sympy as sym
In [37]: a = sym.Rational(4, 5)
In [38]: x = sym.Symbol('x')
In [39]: f = x**3 + a*x**2
In [40]: f
Out[40]:
2
3 4⋅x
x + ────
5
In [41]: f.diff(x)
Out[41]:
2 8⋅x
3⋅x + ───
5
In [42]: sym.plot(f.diff(x))
As I know, if the parameters in the equation are scalars, solving the equation above is implemented as:
from sympy.solvers import solve
from sympy import Symbol
from math import sin, cos, sqrt
# ep, t, a are in short for epsilon, theta and alpha, respectively
ep = Symbol('ep')
a = 0.4798212489019141
t = 39.603733
solve(abs(a)-abs((ep-1)(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2)), ep)
The question is, if these parameters are numpy.ndarray in 3 dimensions, how to implement this calculation?
In my case, the shape of theta and alpha is (5,277,232). So the output, ep, should also have the same shape.
When I pick the problem expression apart, the minimal segment that gives your error is:
In [13]: sqrt(ep-sin(t)**2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-1d595e0b7cc7> in <module>
----> 1 sqrt(ep-sin(t)**2)
/usr/local/lib/python3.6/dist-packages/sympy/core/expr.py in __float__(self)
323 if result.is_number and result.as_real_imag()[1]:
324 raise TypeError("can't convert complex to float")
--> 325 raise TypeError("can't convert expression to float")
326
327 def __complex__(self):
TypeError: can't convert expression to float
The argument to sqrt is a sympy expression (because ep is a symbol):
In [14]: ep-sin(t)**2
Out[14]: ep - 0.892639513815489
math.sqrt requires a float input; it can't do symbolic sqrt.
If I replace it with the sympy sqrt:
In [16]: from sympy import sqrt
In [17]: sqrt(ep-sin(t)**2)
Out[17]:
________________________
╲╱ ep - 0.892639513815489
Now if I try the whole expression:
In [18]: abs(a)-abs((ep-1)(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-18-7d1c0e01daaf> in <module>
----> 1 abs(a)-abs((ep-1)(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2))
TypeError: 'Add' object is not callable
(ep-1) is a sympy Add expression. Due to python syntax rules you can't do (...)(...) implying multiplication. You have to be explicit:
In [19]: abs(a)-abs((ep-1)*(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2))
Out[19]:
│ ⎛ 1.89263951381549⋅ep
0.479821248901914 - │(ep - 1)⋅⎜──────────────────────────────────────────────────── - 0.89263
│ ⎜ 2
│ ⎜⎛ ________________________⎞
│ ⎝⎝0.327659100567207⋅ep - ╲╱ ep - 0.892639513815489 ⎠
⎞│
9513815489⎟│
⎟│
⎟│
⎠│
In [20]: solve(abs(a)-abs((ep-1)*(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**
...: 2)), ep)
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-20-944cce37e63b> in <module>
----> 1 solve(abs(a)-abs((ep-1)*(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2)), ep)
/usr/local/lib/python3.6/dist-packages/sympy/solvers/solvers.py in solve(f, *symbols, **flags)
1032 if e.has(*symbols):
1033 raise NotImplementedError('solving %s when the argument '
-> 1034 'is not real or imaginary.' % e)
1035
1036 # arg
NotImplementedError: solving Abs((ep - 1)*(1.89263951381549*ep/(0.327659100567207*ep - sqrt(ep - 0.892639513815489))**2 - 0.892639513815489)) when the argument is not real or imaginary.
Looks like you need to assign some constraints to the variable ep. (I'm not enough of an sympy expert to do that without reading the docs.)
===
If I remove the abs from the expression, and refine ep, I get a numeric solution:
In [57]: expr =a-(ep-1)*(sin(t)**2 - ep*(1+sin(t)**2)/(ep*cos(t)+sqrt(ep-sin(t)**2))**2)
In [58]: ep = Symbol('ep', real=True)
In [59]: solve(expr, ep)
Out[59]: [56.1511793662046]
In [60]: expr.subs(ep, _[0])
Out[60]: -1.65423230669148e-13
presumably that could be repeated for other values of a and t. The iteration method shouldn't matter, since the solve step will dominate that time.
If you want to solve the above equation for pairs of a and t, you can vectorize your function. This allows you put in arrays with arbitrary shapes and get the function evaluated for all pairs and sorted into the right shape.
Example:
import numpy as np
def eps_solve(a, t):
return a + t
eps_solve_vec = np.vectorize(eps_solve)
a = np.array([[[1, 1], [2, 2]], [[3, 4], [7, 8]]])
t = np.array([[[1, 2], [3, 4]], [[7, 0], [3, 1]]])
res = eps_solve_vec(a, t)
print(res, res.shape)
I am using medfilt to filter a 3 dimensional array (a,b,c)
import scipy as sp
import numpy as np
a = np.random.rand(180000)
b = np.random.rand(180000)
c = np.random.rand(180000)
if I filter the 3 components separatly like this
x = sp.signal.medfilt(a,3)
y = sp.signal.medfilt(b, 3)
z = sp.signal.medfilt(c, 3)
and then combine them into a numpy array
out1 = np.array([x,y,z]).T
I get a different result than when I filter the 3 components at the same time...
sigIn = np.array([a,b,c]).T
out2 = sp.signal.medfilt(sigIn,3)
Could you please explain me why?
For the 2D stacked array, we need to use 2D version of median filter, with the list of kernel sizes along each dimension.
Thus, we would have -
from scipy.signal import medfilt2d
out2 = medfilt2d(sigIn,[3,1])
Sample run -
In [49]: n = 4
...: a = np.random.rand(n)
...: b = np.random.rand(n)
...: c = np.random.rand(n)
...:
...: x = medfilt(a,3)
...: y = medfilt(b, 3)
...: z = medfilt(c, 3)
...:
...: out1 = np.array([x,y,z]).T
...:
In [53]: from scipy.signal import medfilt2d
In [54]: sigIn = np.array([a,b,c]).T
In [55]: out2 = medfilt2d(sigIn,[3,1])
In [56]: np.allclose(out1, out2)
Out[56]: True
As a sidenote, we can use np.column_stack for the stacking operation and thus avoid that transpose, like so -
sigIn = np.column_stack((a,b,c))