Python: Integrate product of exponential and gaussian function - python

I have a function y which is a product of y1 = exp(-x) and exp(-x^2):
y1 = exp(-x)
y2 = exp(-x**2)
y = y1*y2 = exp(-x)*exp(-x**2) = exp(-x **2-x)
Integrating the functions y1 or y2 works fine using sympy:
>>> import sympy as sy
>>> import numpy as np
>>> x = sy.Symbol('x')
>>> y1 = sy.exp(-x)
>>> sy.integrate(y1, (x, 0, np.inf))
1
and
>>> y2 = sy.exp(-x**2)
>>> sy.integrate(y2, (x, 0, np.inf))
0.5*sqrt(pi)
However, whenever I'm trying to integrate the product y1*y2 = y, the integral is not accepted:
>>> y = y1*y2
>>> sy.integrate(y, (x, 0, np.inf))
Integral(exp(-x)*exp(-x**2), (x, 0, np.inf))
Perhaps I'm blind and missing something obvious.

If sympy cannot evaluate it symbolically, then it just returns an Integral object. You need to either use a more powerful symbolic calculator like maxima or Wolfram|Alpha (link to solution)), or else resort to numerical integration. Here are a few options for numerically integrating it:
import sympy as sy
import numpy as np
import scipy as sp
import scipy.integrate
x = sy.Symbol('x')
y1 = sy.exp(-x)
y2 = sy.exp(-x**2)
y = y1*y2
# Pure scipy without sympy
print(sp.integrate.quad(lambda x: np.exp(-x) * np.exp(-(x**2)), 0, np.inf))
# Mix of scipy and sympy
print(sp.integrate.quad(lambda x_arg: y.subs(x, x_arg).evalf(), 0, np.inf))
# Without using scipy
print(sy.mpmath.quad(sy.lambdify([x], y), [0, np.inf]))

I believe the Integral is being accepted and it is giving you a valid sympy result. I used this site and it indicates (I am not enough of a mathematician to verify it) the answer has the error function (erf) in it:
There is no exact analytical answer, so it is giving you it's internal representation. I used Mathematica years ago and it would do something similar, but it provided a polynomial approximation to the solution. BTW, the answer is approximately 0.5456413607650471.
I used http://www.codecogs.com/latex/eqneditor.php to generate the equation image.

Related

Outputting results of loop of a loop

I am iteratively solving this implicit equation
using fsolve within a for loop over a range of values of the independent variable, V.
I also want to vary I_L and run the for loop over each value and generate an individual text files.
I know how to use the open and write text files, what I'm struggling with is setting loops up correctly to output what I want.
I have coded a simpler example below to allow for ease of understanding since it's just the loops I'm stuck on.
import numpy as np
from scipy.optimize import fsolve
import scipy.constants as sc
x = np.linspace(-1, 1, 1001)
C_vary = [0, 1, 2, 3]
def equation(y, x, C):
return C - np.exp(x+y) - y
for C in C_vary:
y = []
Solve equation at each value of C_vary and output y values to new list of
results
I have introduced an initial guess for the function y(x), but you can check the details further. The output y is a list, with each element corresponding to a value of the C_vary parameters, for each x.
import numpy as np
from scipy.optimize import fsolve
import scipy.constants as sc
x = np.linspace(-1, 1, 1001)
C_vary = [0, 1, 2, 3]
def equation(y, x, C):
return C - np.exp(x+y) - y
y0 = np.exp( 0.5*x ) #initial guess
y = [ fsolve( equation, y0, (x,ci) ) for ci in C_vary ]
If you are after I as a function of V and other parameters, you can solve the equation by means of the Lambert W function.
It has the form
z = e^(a z + b)
where z is linear in I, and this is
- a z e^(- a z) = - a e^b
or
z = - W(-a e^b) / a.

Evaluate numerically an equation with sympy

I want to ask something that provably is extremly easy but I didn't find how to do it... The point is that I want to define some function in python in a symbolic way using sympy in order to make its derivative and then use this expresion numerically.
Here an example is showed:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
#How can I evaluate numerically this array "x" with the function deriv???
Do you know how to do it? Thanks!
You can use lambdify with the numpy backend:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
d = lambdify(z, deriv, "numpy")
d(x)
# array([ 8.15484549e+00, 1.14689175e+01, 1.63762998e+01,
# 2.37373255e+01, 3.49286892e+01, 5.21825471e+01,
# 7.91672020e+01, 1.21994639e+02, 1.90992239e+02,
# 3.03860954e+02, 4.91383350e+02, 8.07886132e+02,
# 1.35069268e+03, 2.29681687e+03, 3.97320108e+03,
# 6.99317313e+03, 1.25255647e+04, 2.28335915e+04,
# 4.23706166e+04, 8.00431723e+04])

How do I convert the x and y values in polar form from these coupled ODEs to to cartesian form and graph them?

I have written this code to model the motion of a spring pendulum
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2=(0.415+x)*(dydt)**2-50/1.006*x+9.81*cos(y)
dy2dt2=(-9.81*1.006*sin(y)-2*(dxdt)*(dydt))/(0.415+x)
return np.array([x,y, dx2dt2, dy2dt2])
init = array([0,pi/18,0,0])
time = np.linspace(0.0,10.0,1000)
sol = odeint(deriv,init,time)
def plot(h,t):
n,u,x,y=h
n=(0.4+x)*sin(y)
u=(0.4+x)*cos(y)
return np.array([n,u,x,y])
init2 = array([0.069459271,0.393923101,0,pi/18])
time2 = np.linspace(0.0,10.0,1000)
sol2 = odeint(plot,init2,time2)
plt.xlabel("x")
plt.ylabel("y")
plt.plot(sol2[:,0], sol2[:, 1], label = 'hi')
plt.legend()
plt.show()
where x and y are two variables, and I'm trying to convert x and y to the polar coordinates n (x-axis) and u (y-axis) and then graph n and u on a graph where n is on the x-axis and u is on the y-axis. However, when I graph the code above it gives me:
Instead, I should be getting an image somewhat similar to this:
The first part of the code - from "def deriv(z,t): to sol:odeint(deriv..." is where the values of x and y are generated, and using that I can then turn them into rectangular coordinates and graph them. How do I change my code to do this? I'm new to Python, so I might not understand some of the terminology. Thank you!
The first solution should give you the expected result, but there is a mistake in the implementation of the ode.
The function you pass to odeint should return an array containing the solutions of a 1st-order differential equations system.
In your case what you are solving is
While instead you should be solving
In order to do so change your code to this
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2 = (0.415 + x) * (dydt)**2 - 50 / 1.006 * x + 9.81 * cos(y)
dy2dt2 = (-9.81 * 1.006 * sin(y) - 2 * (dxdt) * (dydt)) / (0.415 + x)
return np.array([dxdt, dydt, dx2dt2, dy2dt2])
init = array([0, pi / 18, 0, 0])
time = np.linspace(0.0, 10.0, 1000)
sol = odeint(deriv, init, time)
plt.plot(sol[:, 0], sol[:, 1], label='hi')
plt.show()
The second part of the code looks like you are trying to do a change of coordinate.
I'm not sure why you try to solve the ode again instead of just doing this.
x = sol[:,0]
y = sol[:,1]
def plot(h):
x, y = h
n = (0.4 + x) * sin(y)
u = (0.4 + x) * cos(y)
return np.array([n, u])
n,u = plot( (x,y))
As of now, what you are doing there is solving this system:
Which leads to x=e^t and y=e^t and n' = (0.4 + e^t) * sin(e^t) u' = (0.4 + e^t) * cos(e^t).
Without going too much into the details, with some intuition you could see that this will lead to an attractor as the derivative of n and u will start to switch sign faster and with greater magnitude at an exponential rate, leading to n and u collapsing onto an attractor as shown by your plot.
If you are actually trying to solve another differential equation I would need to see it in order to help you further
This is what happen if you do the transformation and set the time to 1000:

How to Integrate Arc Lengths using python, numpy, and scipy?

On another thread, I saw someone manage to integrate the length of a arc using mathematica.They wrote:
In[1]:= ArcTan[3.05*Tan[5Pi/18]/2.23]
Out[1]= 1.02051
In[2]:= x=3.05 Cos[t];
In[3]:= y=2.23 Sin[t];
In[4]:= NIntegrate[Sqrt[D[x,t]^2+D[y,t]^2],{t,0,1.02051}]
Out[4]= 2.53143
How exactly could this be transferred to python using the imports of numpy and scipy? In particular, I am stuck on line 4 in his code with the "NIntegrate" function. Thanks for the help!
Also, if I already have the arc length and the vertical axis length, how would I be able to reverse the program to spit out the original paremeters from the known values? Thanks!
To my knowledge scipy cannot perform symbolic computations (such as symbolic differentiation). You may want to have a look at http://www.sympy.org for a symbolic computation package. Therefore, in the example below, I compute derivatives analytically (the Dx(t) and Dy(t) functions).
>>> from scipy.integrate import quad
>>> import numpy as np
>>> Dx = lambda t: -3.05 * np.sin(t)
>>> Dy = lambda t: 2.23 * np.cos(t)
>>> quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, 1.02051)
(2.531432761012828, 2.810454936566873e-14)
EDIT: Second part of the question - inverting the problem
From the fact that you know the value of the integral (arc) you can now solve for one of the parameters that determine the arc (semi-axes, angle, etc.) Let's assume you want to solve for the angle. Then you can use one of the non-linear solvers in scipy, to revert the equation quad(theta) - arcval == 0. You can do it like this:
>>> from scipy.integrate import quad
>>> from scipy.optimize import broyden1
>>> import numpy as np
>>> a = 3.05
>>> b = 2.23
>>> Dx = lambda t: -a * np.sin(t)
>>> Dy = lambda t: b * np.cos(t)
>>> arc = lambda theta: quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, np.arctan((a / b) * np.tan(np.deg2rad(theta))))[0]
>>> invert = lambda arcval: float(broyden1(lambda x: arc(x) - arcval, np.rad2deg(arcval / np.sqrt((a**2 + b**2) / 2.0))))
Then:
>>> arc(50)
2.531419526553662
>>> invert(arc(50))
50.000031008458365
If you prefer a pure numerical approach, you could use the following barebones solution. This worked well for me given that I had two input numpy.ndarrays, x and y with no functional form available.
import numpy as np
def arclength(x, y, a, b):
"""
Computes the arclength of the given curve
defined by (x0, y0), (x1, y1) ... (xn, yn)
over the provided bounds, `a` and `b`.
Parameters
----------
x: numpy.ndarray
The array of x values
y: numpy.ndarray
The array of y values corresponding to each value of x
a: int
The lower limit to integrate from
b: int
The upper limit to integrate to
Returns
-------
numpy.float64
The arclength of the curve
"""
bounds = (x >= a) & (y <= b)
return np.trapz(
np.sqrt(
1 + np.gradient(y[bounds], x[bounds])
) ** 2),
x[bounds]
)
Note: I spaced the return variables out that way just to make it more readable and clear to understand the operations taking place.
As an aside, recall that the arc-length of a curve is given by:

partial integration of a two dimensional gaussian function

I want to carry out the following partial integration of a 2-D gaussian function of four variables (x, y, alpha and beta), with respect to only x and y, as follows. In the end I want the answer to be a function of alpha and beta only.
I wrote the following code in python to execute the above mentioned integral.
from sympy import Symbol
from sympy import integrate
from math import e
alpha = Symbol('alpha')
beta = Symbol('beta')
x = Symbol('x')
y = Symbol('y')
n = 2
value = integrate( e**( -(x - alpha)**n - (y - beta)**n ), (x, -1, 1), (y, -1, 1) )
However I get the following error:
sympy.polys.polyerrors.DomainError: there is no ring associated with RR
The above mentioned integrate function works fine for n=1. However it breaks down for n>1.
Am I doing something wrong?
Welcome to SO!
Interestingly it works when you substitute alpha and beta into the integral bounds. Try:
from IPython.display import display
import sympy as sy
sy.init_printing() # LaTeX like pretty printing forIPython
alpha, beta, x, y = sy.symbols("alpha, beta, x, y", real=True)
f = sy.exp(-x**2 - y**2) # sy.exp() is better than the numeric constant
val = sy.integrate(f, (x, -1+alpha, 1+alpha), (y, -1+beta, 1+beta))
display(val)

Categories