Explicitly calculate convolution in Python - python

I want to calculate a convolution in Python by explicitly evaluating the integral
and comparing the result with what I get from fftconvolve. The integral would be calculated using quad:
import numpy as np
from scipy.integrate import quad
from scipy.signal import fftconvolve
import matplotlib.pyplot as plt
from sympy import symbols
def f(x,a,b):
return np.exp(-(x-a)**2/b)
def g(x,a,b):
return np.exp(-(x-np.pi*a)**2/(2.9*b))
x = symbols('x')
a = 1.2
b = 4.7
t = np.linspace(-100,100,int(1e4))
dt = t[1] - t[0]
h1 = fftconvolve(f(t,a,b),g(t,a,b),mode='same')*dt
h2,_ = quad(f(t,a,b)*g(x-t,a,b),-np.inf,np.inf,epsabs=0,epsrel=1e-6,args=(a,b))
x = np.linspace(-100,100,int(1e4))
plt.figure()
plt.plot(t,h1,label='fftconvolve')
plt.plot(x,h2,label='brute force')
plt.legend()
plt.show()
I keep getting the error AttributeError: 'Mul' object has no attribute 'exp' which refers to the line h2,_ = quad(... when it is called by quad.
What does this error mean and is this an appropriate way to use quad to evaluate the integral?

Related

ValueError: Residuals are not finite in the initial point. with scipy least square

import originpro as op
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def circle(ReZ,R1,R2):
nImZ=(ReZ-R1)*np.sqrt(R2/(ReZ-R1)-1)
return nImZ
def Fit(func,used_x,used_y,bound,yerror):
fit_para,fit_cov=curve_fit(func,used_x,used_y,bounds=bound,sigma=yerror,absolute_sigma=True)
print(fit_para)
return fit_para
def yerror(ydata, p):
output=[]
for i in ydata:
data=i*p
output.append(data)
return output
def PrePlot(exp_x,exp_y,fit_x,fit_y):
fig,ax=plt.subplots()
fitline=ax.plot(fit_x,fit_y,marker='.',color='blue')
expline=ax.scatter(exp_x,exp_y,s=20,marker='.',color='red')
ax.legend(['Experimental','Fitted line'])
plt.show()
wkslist=range(83,109)
for wksnum in wkslist:
wks=op.find_sheet('w','Book'+str(wksnum))
xdata=wks.to_list(1)
ydata=wks.to_list(2)
bound=([3000,1*10**8],[6000,1*10**9])
error=yerror(ydata, 0.1)
fitRes=Fit(circle,xdata,ydata,bound,error)
fit_x=xdata
fit_y=[circle(x,fitRes[0],fitRes[1]) for x in fit_x]
PrePlot(xdata,ydata,fit_x,fit_y)
I get the error for the second worksheet(wks)
for the function used (circle), the condition is: when ReZ>R1, R1+R2>=ReZ; when ReZ<R1, R1+R2<=ReZ
The maximum ReZ in the xdata is 1.35e8, the minimum is 4353, which fits that condition with the given boundary.
So I'm really confused here

Constructing a ContinuousRV from an implemented_function or rv_continuous

I would like to construct a ContinuousRV given a python-implemented probability density function (pdf). The following is a minimal working example whose last statement yields a ValueError
import numpy as np
from scipy.stats import gaussian_kde, norm
from sympy import Interval, oo, symbols
from sympy.stats import ContinuousRV
from sympy.utilities.lambdify import implemented_function
# Example Data
measures = np.concatenate([norm.rvs(loc=-2, size=64), norm.rvs(loc=3, size=32)])
# Definition of the PDF
pdf_kde = gaussian_kde(measures)
pdf_sym = implemented_function("pdf", pdf_kde)
# Create the symbolic variable
XName, x = symbols('X x')
X = ContinuousRV(XName, pdf_sym(x), set=Interval(-oo, oo))
The example fails with the following error:
.../lib/python3.8/site-packages/sympy/stats/crv_types.py in check(pdf, set)
149 x = Dummy('x')
150 val = integrate(pdf(x), (x, set))
--> 151 _value_check(val == S.One, "The pdf on the given set is incorrect.")
152
153
.../lib/python3.8/site-packages/sympy/stats/rv.py in _value_check(condition, message)
1450 truth = fuzzy_and(condition)
1451 if truth == False:
-> 1452 raise ValueError(message)
1453 return truth == True
1454
ValueError: The pdf on the given set is incorrect.
I have confirmed that the pdf is a good approximation.
from scipy import integrate
value, err = integrate.quad(pdf_kde, -np.inf, np.inf)
print(value, err)
>>> 0.9999999999999996 2.318795975521764e-09
I am currently using Python 3.8.0, Sympy 1.6, Scipy 1.4.1, and Numpy 1.18.5 if that is relevant.
The ContinuousRV method constructs an instance of ContinuousDistributionHandmade and, in doing so, invokes a check method that fails because Sympy does not automatically perform numeric computation. It is possible to construct a wrapper that yields the desired distribution and performs said check numerically.
from sympy.stats.crv import SingleContinuousDistribution
def _check_dist(pdf, set):
from sympy import Dummy, integrate, N
x = Dummy('x')
integrand = pdf(x)
integral = integrate(integrand, (x, set.start, set.end))
v = float(N(integral))
assert np.isclose(float(v), 1.0)
def EmpiricalRV(name: str, m: np.ndarray) -> SingleContinuousDistribution:
from scipy.stats import gaussian_kde
from sympy import Interval, oo
from sympy.stats import ContinuousDistributionHandmade
from sympy.stats.crv import SingleContinuousPSpace
from sympy.utilities.lambdify import implemented_function
pdf_kde = gaussian_kde(m)
pdf_sym = implemented_function(f"f_{name}", lambda y: pdf_kde(float(y)))
domain = Interval(-oo, oo)
_check_dist(pdf_sym, domain)
dist = ContinuousDistributionHandmade(pdf_sym, domain)
pspace = SingleContinuousPSpace(name, dist)
return pspace.value
The following test code demonstrates the random variable in action.
from scipy.stats import norm
data = np.concatenate([norm.rvs(loc=-2, size=64), norm.rvs(loc=3, size=32)])
from sympy import N
from sympy.stats import density, Normal, E, P, median
Y = EmpiricalRV('Y',data)
ev = E(Y)
evfloat = float(N(ev))
print("Y :", Y)
print("density(Y) :", density(Y))
print("E(Y) :", ev)
print(f"N(E(Y)) : {evfloat:.4f}")
print(f"data.mean(): {data.mean():.4f}")
>>> Y : Y
>>> density(Y) : ContinuousDistributionHandmade(f_Y, Interval(-oo, oo))
>>> E(Y) : Integral(Y*f_Y(Y), (Y, -oo, oo))
>>> N(E(Y)) : -0.3882
>>> data.mean(): -0.3882
There may be further value in subclassing ContinuousDistributionHandmade or SingleContinuousDistribution

Plotting a symbolic function with multiple variables in Python

First code cell:
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
from ipywidgets.widgets import interact
sym.init_printing(use_latex="mathjax")
x, y, z, t = sym.symbols('x y z t')
I am required to plot the following function which I have defined as:
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(z-sym.exp(-t))**2/(1-sym.exp(-2*t)))
Obviously t and z are both variables and I am to plot the function for t = 0.1,1, and 10, using z as my x-axis and p_w(z) as the y-axis.
I tried defining 3 functions j,k,l with the values subbed in for t like so:
j=p_w.evalf(subs={t:0.1})
k=p_w.evalf(subs={t:1})
l=p_w.evalf(subs={t:10})
then changing these to numpy arrays with the sym.lambdify() function:
j_np=sym.lambdify(z,j)
k_np=sym.lambdify(z,k)
l_np=sym.lambdify(z,l)
I defined my x-axis using:
myz = np.linspace(0,10,1000)
(The 1000 divisions was fairly arbitrary as I wasn't sure how many I'd need for an accurate graph)
Then I tried plotting just j to begin with as follows:
plt.plot(myz, j_np(myz))
and got the following error message:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-41-d743a8a00bcf> in <module>()
----> 1 plt.plot(myz,j_np(myz))
/anaconda3/lib/python3.6/site-packages/numpy/__init__.py in <lambda>. (_Dummy_164)
AttributeError: 'Mul' object has no attribute 'exp'
I am guessing the problem is that numpy does not understand 'exp' in the same way that sympy does, but I am unsure as to how to rectify it, or even if this is the problem at all. Any help would be much appreciated.
You can get this to work if you skip the evalf step:
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
from ipywidgets.widgets import interact
sym.init_printing(use_latex="mathjax")
# x, y, z, t = sym.symbols('x y z t')
from sympy.abc import x,y,z,t
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(z - sym.exp(-t))**2/(1-sym.exp(-2*t)))
myz = np.linspace(0,10,1000)
lam=sym.lambdify((z,t), p_w)
myz = np.linspace(0,10,1000)
times = [.01, 1, 10]
for time in times:
plt.plot(myz, lam(myz, time))
Output:
It seems the underlying issue was that setting the time using p_w.evalf(subs={t:0.1}) doesn't really work:
print(p_w.evalf(subs={t:0.1}))
0.564189583547756*(1.0 - exp(-2*t))**(-0.5)*exp(-(z - exp(-t))**2/(1 - exp(-2*t)))
It works right if z is removed from p_w:
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(- sym.exp(-t))**2/(1-sym.exp(-2*t)))
print(p_w.evalf(subs={t:0.1}))
0.0144778612224441
So apparently having the undetermined variable z in p_w prevents p_w.evalf from expanding the t terms correctly.

Solving nonlinear differential first order equations using Python

I would like to solve a nonlinear first order differential equation using Python.
For instance,
df/dt = f**4
I wrote the following program, but I have an issue with matplotlib, so I don't know if the method I used with scipy is correct.
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
derivate=lambda f,t: f**4
f0=10
t=np.linspace(0,2,100)
f_numeric=scipy.integrate.odeint(derivate,f0,t)
print(f_numeric)
plt.plot(t,f_numeric)
plt.show()
Which results in the following error:
AttributeError: 'float' object has no attribute 'rint'
In this case, you might be better of using Sympy, which allows you to obtain the closed form solutions:
from IPython.display import display
import sympy as sy
from sympy.solvers.ode import dsolve
import matplotlib.pyplot as plt
import numpy as np
sy.init_printing() # LaTeX like pretty printing for IPython
t = sy.symbols("t", real=True)
f = sy.symbols("f", function=True)
eq1 = sy.Eq(f(t).diff(t), f(t)**4) # the equation
sls = dsolve(eq1) # solvde ODE
# print solutions:
print("For ode")
display(eq1)
print("the solutions are:")
for s in sls:
display(s)
# plot solutions:
x = np.linspace(0, 2, 100)
fg, axx = plt.subplots(2, 1)
axx[0].set_title("Real part of solution of $\\frac{d}{dt}f(t)= (f(t))^4$")
axx[1].set_title("Imag. part of solution of $\\frac{d}{dt}f(t)= (f(t))^4$")
fg.suptitle("$C_1=0.1$")
for i, s in enumerate(sls, start=1):
fn1 = s.rhs.subs("C1", .1) # C_1 -> 1
fn2 = sy.lambdify(t, fn1, modules="numpy") # make numpy function
y = fn2(x+0j) # needs to be called with complex number
axx[0].plot(x, np.real(y), label="Sol. %d" % i)
axx[1].plot(x, np.imag(y), label="Sol. %d" % i)
for ax in axx:
ax.legend(loc="best")
ax.grid(True)
axx[0].set_ylabel("Re$\\{f(t)\\}$")
axx[1].set_ylabel("Im$\\{f(t)\\}$")
axx[-1].set_xlabel("$t$")
fg.canvas.draw()
plt.show()
In an IPython shell, you should see the following:

Numpy roots function and pyplot plot

I want to plot the two solutions of quadratic equation as a function of a parameter ( function coeff(t) ). I am using function numpy.roots (I am sure that all roots are real in this case), and I am trying to invoke it from within pyplot.plot as below:
import numpy as np
import matplotlib.pyplot as plt
r = 3.74
def coeff(pp):
return np.array([pp-1,r+1-0.5*pp,-r])
def sroot(t):
return np.roots(coeff(t))
a = np.linspace(0,0.9,100)
fig = plt.figure()
plt.plot(a,sroot(a)[0,:])
plt.plot(a,sroot(a)[1,:])
plt.show()
I get error message:
File "quest.py", line 18, in <module>
plt.plot(a,sroot(a)[0,:])
File "quest.py", line 10, in sroot
return np.roots(coeff(t))
File "/usr/lib64/python2.7/site-packages/numpy/lib/polynomial.py", line 218, in roots
p = p.astype(float)
I understand that the numpy.roots takes only list of parameters and is unable to recognize a row in array 3xlen(a). Is there a way to do it in one line, preferably inside the pyplot.plot? I would like to avoid using loop.
This is because you transform all of your coefficient at once and try to call the numpy roots solver on all of them. np.roots only accept 1-d array and solves a single polynomial. Here is a script that does what you want:
import numpy as np
import matplotlib.pyplot as plt
# Parameters
r = 3.74
T = np.linspace(0.0,0.9,100)
# Coefficients
C = np.zeros((len(T),3))
C[:,0] = T-1
C[:,1] = r + 1 - 0.5*T
C[:,2] = r
# Roots
R = np.zeros((len(T),2))
for i in range(len(T)):
R[i] = np.roots(C[i])
# Plot
fig = plt.figure()
plt.plot(T,R[:,0])
plt.plot(T,R[:,1])
plt.show()

Categories

Resources