Apologies for the simplicity of this question.
I would like to implement an equation in Python. In this equation, K_0 is the zeroth-order modifed Bessel function.
What is the best way of implementing K_0 in Python?
No need to implement it; it's included. See the docs for the scipy.special module, in particular the optimized common ones here:
>>> import scipy.special
>>> print scipy.special.k0.__doc__
k0(x[, out])
y=k0(x) returns the modified Bessel function of the second kind (sometimes called the third kind) of
order 0 at x.
>>> scipy.special.k0(1)
0.42102443824070823
or more generally:
>>> print scipy.special.kn.__doc__
kn(x1, x2[, out])
y=kn(n,x) returns the modified Bessel function of the second kind (sometimes called the third kind) for
integer order n at x.
>>> scipy.special.kn(0, 1)
0.42102443824070834
Related
I have some SymPy expressions of the form: 2*x1**2+7*cos(8*x2)+2*Pi (mine are longer and more complicated, but this should be enough for my question). How can I turn all the numbers appearing in this expression into parameters, something like this: a*x1**2+b*cos(c*x2)+d. Basically, I have a program which is able to give me an approximate function able to fit some data, but the parameters are integers or some well known numbers, such as pi or e (this is the first expression I provided). Then, I want to take that expression and fine tune these numbers (using gradient descent), such that to obtain the actual parameters (one can assume that the functional form is right, just the parameters need to be adjusted). For example, in the end, the right equation could be: 2.87*x1**2+6.95*cos(8.05*x2)+6.27. Is there a way to do this? Thank you!
It's a little tricky because you say "all numbers" but you are ignoring exponents. In your example you are only replacing numerical factors in a term with new symbols. To do that (and to get you on your way with a possible solution) try using replace, telling it you are looking for a Mul and then telling it what you want to do with the Mul when you have it:
from sympy import *
from sympy.abc import x,y
eq=2*x**2+7*cos(8*y)+2*pi
def nfact2dum(m):
assert m.is_Mul
nonnum = sift(m.args, lambda i:i.is_number, binary=True)[1]
return Mul(*([Dummy()] + nonnum))
deq = eq.replace(
lambda x:x.is_Mul,
lambda x: nfact2dum(x))
print(
deq.subs(list(zip(deq.atoms(Dummy),numbered_symbols('c')))))
output: c0*x**2 + c2*cos(c1*y) + c3
A MATLAB code contains the use of the function sgolay as:
[b,g] = sgolay(k, f)
Using this, I need to find the smoothness, first derivative, and second derivative. for finding the above, I need the value of g.
These have to be performed in Python instead of MATLAB.
Python's savgol_filter(arr, k, f) works the same as MATLAB's sgolay(arr, k, f), however, there is no alternative to sgolay(k, f) which designs the filter and returns g.
What would be a Python equivalent to the sgolay() function?
I understand your problem now. (You had a typo, you meant sgolayfilt(arr, k, f) instead of sgolay(arr, k, f).)
So,
MATLAB's sgolayfilt is related to python's savgol_filter
MATLAB's sgolay is related to python's savgol_coeffs
Note that, in python's function, the order of the parameters is:
smoothingfilter = savgol_coeffs(window_length, polyorder)
while in MATLAB is the other way around:
[smoothingfilter,g] = sgolay(ORDER,FRAMELEN)
If you now want the differentiation filters, which in matlab are in g you will need to pass that optional parameter to the python function:
smoothingfilter_deriv = savgol_coeffs(window_length, polyorder, deriv)
which will be derived deriv times. In your particular case, you want:
smoothingfilter1 = savgol_coeffs(window_length, polyorder, 1)
smoothingfilter2 = savgol_coeffs(window_length, polyorder, 2)
that are the python's equivalent to:
g(:,1) (for smoothingfilter1)
and
g(:,2) (for smoothingfilter2)
where g was obtained doing:
[b,g] = sgolay(polyorder,window_length)
I came across this problem by Jake VanderPlas and I am not sure if my understanding of why the result differs after importing the numpy module is entirely correct.
>>print(sum(range(5),-1)
>> 9
>> from numpy import *
>> print(sum(range(5),-1))
>> 10
It seems like in the first scenario the sum function calculates the sum over the iterable and then subtracts the second args value from the sum.
In the second scenario, after importing numpy, the behavior of the function seems to have modified as the second arg is used to specify the axis along which the sum should be performed.
Exercise number (24)
Source - http://www.labri.fr/perso/nrougier/teaching/numpy.100/index.html
"the behavior of the function seems to have modified as the second arg is used to specify the axis along which the sum should be performed."
You have basically answered your own question!
It is not technically correct to say that the behavior of the function has been modified. from numpy import * results in "shadowing" the builtin sum function with the numpy sum function, so when you use the name sum, Python finds the numpy version instead of the builtin version (see #godaygo's answer for more details). These are different functions, with different arguments. It is generally a bad idea to use from somelib import *, for exactly this reason. Instead, use import numpy as np, and then use np.sum when you want the numpy function, and plain sum when you want the Python builtin function.
Only to add my 5 pedantic coins to #Warren Weckesser answer. Really from numpy import * does not overwrite the builtins sum function, it only shadows __builtins__.sum, because from ... import * statement binds all names defined in the imported module, except those beginning with an underscore, to your current global namespace. And according to Python's name resolution rule (unofficialy LEGB rule), the global namespace is looked up before __builtins__ namespace. So if Python finds desired name, in your case sum, it returns you the binded object and does not look further.
EDIT:
To show you what is going on:
In[1]: print(sum, ' from ', sum.__module__) # here you see the standard `sum` function
Out[1]: <built-in function sum> from builtins
In[2]: from numpy import * # from here it is shadowed
print(sum, ' from ', sum.__module__)
Out[2]: <function sum at 0x00000229B30E2730> from numpy.core.fromnumeric
In[3]: del sum # here you restore things back
print(sum, ' from ', sum.__module__)
Out[3]: <built-in function sum> from builtins
First note: del does not delete objects, it is a task of garbage collector, it only "dereference" the name-bindings and delete names from current namespace.
Second note: the signature of built-in sum function is sum(iterable[, start]):
Sums start and the items of an iterable from left to right and returns the total. start defaults to 0. The iterable‘s items are normally numbers, and the start value is not allowed to be a string.
I your case print(sum(range(5),-1) for built-in sum summation starts with -1. So technically, your phrase the sum over the iterable and then subtracts the second args value from the sum isn't correct. For numbers it's really does not matter to start with or add/subtract later. But for lists it does (silly example only to show the idea):
In[1]: sum([[1], [2], [3]], [4])
Out[1]: [4, 1, 2, 3] # not [1, 2, 3, 4]
Hope this will clarify your thoughts :)
I am writing a script to calculate the definite integral of an equation. I'm writing a helper function that would take in coefficients as parameters and return a function of x.
def eqn(x, k, c, a):
return ((k*x + c**(1-a))
Next, I define a function that calculates the definite integral, using quad imported from scipy:
from scipy.integrate import quad
def integral(eqn, c_i, y_i):
integral_i, integral_err = quad(eqn, c_i, y_i)
print integral_i
Then I call the function by passing in parameters
k = calc_k(7511675,1282474,0,38,2)
eqn = carbon_path_eqn(x, k, 7511675, 2)
carbon_path_def_int(eqn,0,38)
However, I get an error saying that 'name x is not defined'. I understand that x isn't defined globally, but I'm wondering how I can write a helper function, that takes in parameters, and still returns a function of x that can be used in quad?
Thank you!
PS -
#bpachev, this is a follow up from the other post
The mistake here is that the function 'eqn' does not return a function, it returns the value of a function at some point x, given parameters k,c,a.
quad should be passed a function (in your case, eqn) where the first argument (in your case, x) is assumed to be the variable over which the function is integrated. You also need to pass quad a tuple of the remaining parameters (in your case (k,c,a)) and two limits (in your case, c_i,y_i). In other words, call quad like this:
quad(eqn,c_i,y_i,args=(k,c,a))
This is all explained in the scipy documentation http://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html.
This is not what you asked. However, as someone else has mentioned, sympy would probably make your life much easier. For instance, suppose you need to be able to evaluate integrals of functions of x such as f in the code below, where a and b are arbitrary constants. Here's how you can use sympy to do that.
Define the function, integrate it with respect to x and save the result, then evaluate the result for values of a, b and x.
I want to integrate a function using python, where the output is a new function rather than a numerical value. For example, I have the equation (from Arnett 1982 -- analytical description of a supernova):
def A(z,tm,tni):
y=tm/(2*tni)
tm=8.8 # diffusion parameter
tni=8.77 # efolding time of Ni56
return 2*z*np.exp((-2*z*y)+(z**2))
I want to then find the integral of A, and then plot the results. First, I naively tried scipy.quad:
def Arnett(t,z,tm,tni,tco,Mni,Eni,Eco):
x=t/tm
Eni=3.90e+10 # Heating from Ni56 decay
Eco=6.78e+09 # Heating from Co56 decay
tni=8.77 # efolding time of Ni56
tco=111.3 # efolding time of Co56
tm=8.8 # diffusion parameter
f=integrate.quad(A(z,tm,tni),0,x) #integral of A
h=integrate.quad(B(z,tm,tni,tco),0,x) #integral of B
g=np.exp((-(x/tm)**2))
return Mni*g*((Eni-Eco)*f+Eco*h)
Where B is also a pre-defined function (not presented here). Both A and B are functions of z, however the final equation is a function of time, t. (I believe that it is herein I am causing my code to fail.)
The integrals of A and B run from zero to x, where x is a function of time t. Attempting to run the code as it stands gives me an error: "ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()".
So after a short search I thought that maybe sympy would be the way to go. However I am failing with this as well.
I wonder if anyone has a helpful suggestion how to complete this task please?
Many thanks,
Zach
You can integrate A analytically. Assuming I'm not missing something silly due to being up way too late, does the following help?
import sympy as sy
sys.displayhook = sy.pprint
A, y, z, tm, t, tni = sy.symbols('A, y, z, tm, t, tni')
A = 2*z*sy.exp(-2*z*y + z**2)
expr = sy.integrate(A, (z,0,t)) # patience - this takes a while
expr
# check:
(sy.diff(expr,t).simplify() - A.replace(z,t)).simplify()
# thus, the result:
expr.replace(y,tm/(2*tni)).replace(t,t/tm)
The last line yields the integral of your A function in analytic form, though it does require evaluating the imaginary error function (which you can do with scipy.special.erfi()).
I think what you are looking for are lambda expression (if i understood correctly what you said.. see here for extra information and some examples on lambda functions).
What they allow you to do is define an anonymous function in A and return it so that you get your B function, should work something like this:
def A(parameters):
return lambda x: x * parameters # for simplicity i applied a multiplication
# but you can apply anything you want to x
B = A(args)
x = B(2)
Hope I could provide you with a decent response!
I think the error you get comes from an incorrect call to scipy.integrate.quad:
The first argument needs to be just the function name, integration is then performed over the first variable of this function. The values of the other variables can be passed to the function via the args keyword.
The output of scipy.integrate.quad contains not only the value of the integral, but also an error estimate. So a tuple of 2 values is returned!
In the end the following function should work:
def Arnett(t, z, Mni, tm=8.8, tni=8.77, tco=111.3, Eni=3.90e+10,
Eco=6.78e+09):
x=t/tm
f,err=integrate.quad(A,0,x,args=(tm,tni)) #integral of A
h,err=integrate.quad(B,0,x,args=(tm,tni,tco)) #integral of B
g=np.exp((-(x/tm)**2))
return Mni*g*((Eni-Eco)*f+Eco*h)
But an even better solution would probably be integrating A and B analytically and then evaluating the expression as murison suggested.