I'm coding an algorithm that takes the inverse of a Laplace transform, iterates it until it converges and live-plots the graph. I've dealt with a bunch of errors so far and solved them all but on this one, I'm stumped. Here's the function f_p() that I'm getting the error from. For context, it contains 6 Laplace transforms that I painstakingly derived by hand to eliminate the imaginary component:
def f_p(u, omega, m):
a = gamma
b = (omega + k * math.pi) / u
if m == 1:
f = a * (1 / (a ** 2 + (b + 1) ** 2) + 1 / (a ** 2 + (b - 1) ** 2))
return f * math.cos(omega)
elif m == 2:
f = a / (a ** 2 + b ** 2)
return f * math.cos(omega)
elif m == 3:
f = math.e ** (-a / (a ** 2 + b ** 2)) * (a ** 2 + b ** 2) ** (1 / 4) * math.cos(
(math.atan2(b, a) + 2 * n * math.pi) / 2) * math.cos(b / (a ** 2 + b ** 2)) / (
math.sqrt(a ** 2 + b ** 2) * (math.cos((math.atan2(b, a) + 2 * n * math.pi) / 2) ** 2 + math.sin(
(math.atan2(b, a) + 2 * n * math.pi) / 2)))
return f * math.cos(omega)
elif m == 4:
a = math.e
f = -(a * math.log(a ** 2 + b ** 2) + a ** 2) / (a ** 2 + b ** 2)
return f * math.cos(omega)
elif m == 5:
f = a * (math.e ** (-a) * math.cos(b) - math.e ** (-2 * a) * math.cos(2 * b)) / (a ** 2 + b ** 2)
return f * math.cos(omega)
elif m == 6:
f = math.sqrt((a ** 2 - b ** 2 + 1) ** 2 + (2 * a * b) ** 2) * math.cos(
(math.atan2(2 * a * b, a ** 2 - b ** 2 + 1) + 2 * n * math.pi) / 2) / (
((a ** 2 - b ** 2 + 1) ** 2 + (2 * a * b) ** 2) * (
math.cos((math.atan2(2 * a * b, a ** 2 - b ** 2 + 1) + 2 * n * math.pi) / 2) ** 2 + math.sin(
(math.atan2(2 * a * b, a ** 2 - b ** 2 + 1) + 2 * n * math.pi) / 2) ** 2))
return f * math.cos(omega)
else:
return 0
This function feeds into another function f_u(), which contains the algorithm itself, which integrates over omega, removing it as a variable. The remaining variable is u, which I need to iterate until the function converges. Here's the execution of the algorithm:
u = np.linspace(0.000001, 100, 100000)
if __name__ == '__main__':
pool = Pool(processes=4)
for m in range(1, 7):
if m == 4:
gamma = math.e
else:
gamma = 10
pool.map(f_u, u)
Maybe it could be a syntax problem? I don't know. Any help would be much appreciated.
I am intending to take a list of random variables and alter a previous list in each column by said random variables. However, for the purpose of my function, each variable must be used in a Gamma function as well as integrated.
x[t] = c * (1 / (2 ** (v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
x[ t ] is an np.zeros((x , y)) list, and test[t - 1] is an np.zeros((x - 1, y)) list
I have filled test[ ] with the appropriate random variables, but I am unable to pass them through this equation to complete the columns of row [ t ] in x
When I try to run my current code, I receive:
File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_64\lib\site-packages\scipy\integrate\quadpack.py", line 450, in _quad
return _quadpack._qagie(func,bound,infbounds,args,full_output,epsabs,epsrel,limit)
TypeError: only size-1 arrays can be converted to Python scalars
Is there a different special function which allows me to use each column's variable to solve for my desired x[ t ]?
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import stats
import mpmath as mp
import scipy.integrate as integrate
from scipy.special import gamma
T = 1
beta = 0.5
x0 = 0.05
q = 0
mu = x0 - q
alpha = - (2 - beta) * mu
sigma0 = 0.1
sigma = (2 - beta) * sigma0
b = - ((1 - beta) / (2 * mu) * (sigma0 ** 2))
simulations = 100
M = 50
dt = T / M
def srd_sampled_nxc2():
x = np.zeros((M + 1, simulations))
x[0] = x0
test = np.zeros((M, simulations))
for t in range(1, M + 1):
v = 4 * b * alpha / sigma ** 2
c = (sigma ** 2 * (1 - np.exp(-alpha * dt))) / (4 * alpha)
nc = np.exp(-alpha * dt) / c * x[t - 1]
if v > 1:
x[t] = c * ((np.random.standard_normal(simulations) + nc ** 0.5) ** 2 + mp.nsum(
lambda i: np.random.standard_normal(simulations) ** 2, [0, v - 1]))
else:
max_array = []
nc_over_2 = [l / 2 for l in nc]
for p in range(simulations):
sump = []
poisson_start = 0
while poisson_start <= 1:
x_i = sum(-np.log(np.random.uniform(0, 1, simulations)) / nc_over_2)
sump.append(
x_i
)
poisson_start += x_i
x_n = max(sump)
max_array.append(
x_n
)
sump = []
test[t - 1] = max_array
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1])) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
max_array = []
return x
Ultimately ended up finding a workaround which is simple to implement:
else:
max_array = []
for p in range(simulations):
k = nc[t - 1, p]
lam = k / 2
poisson_samp = 0
while poisson_samp <= 1:
x_i = -math.log(np.random.uniform(0, 1)) / lam
max_array.append(
x_i
)
poisson_samp += x_i
test[t - 1, p] = len(max_array) - 1
max_array.clear()
for f in range(simulations):
n = test[t - 1, f]
z = integrate.quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + n - 1), 0, 1)
new[t - 1, f] = z[0]
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * new[0])
The only real problem is the shrinkage of x[t] which leads to dividing by zero--just a formula problem.
So for this internship I am doing, I need to use the integral of (x^(9/2))/((1-x)^2) as part of an equation I am graphing. However, the variable that I am graphing along the x axis appears in both limits of integration. Since I am a complete and total novice at python, my code is atrocious, but I ended up copy+pasting the indefinite integral twice, plugging in the limits of integration, and subtracting. How can I make the code better?
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
x = np.arange(0,2.5,0.00001)
zs = 8
zr = 6
rbub = 5
sig = 2.5
XHI = 0.5
sigma = 10**-sig
L = 10**-3
zb = zs - (((1 + zs)/8)**(3/2)) * (0.0275) * (rbub/10)
a = (1+zr)/((1+zs)*(x+1))
b = (1+zb)/((1+zs)*(x+1))
def f(x):
ans = 0.000140092
ans = ans * ((1+zs)**(3/2))
ans = ans * ((x+1)**(3/2))
ans = ans * XHI
return ans * ((9/2)*(np.log(1-np.sqrt(b)) - np.log(np.sqrt(b)+1)) + (1/35 * (1/(b-1)) * (10*(b**(9/2)) + 18*(b**(7/2)) + 42*(b**(5/2)) + 210*(b**(3/2)) - 315*(b**(1/2))) - ((9/2)*(np.log(1-np.sqrt(a)) - np.log(np.sqrt(a)+1)) + (1/35 * (1/(a-1)) * (10*(a**(9/2)) + 18*(a**(7/2)) + 42*(a**(5/2)) + 210*(a**(3/2)) - 315*(a**(1/2)))))))
Here is one take. Of course, I have no idea what this is doing. You should be in a much better position to add comments / sensible variable names, as others have pointed out. Still, here is what you could do.
First, run a code formatter to make the code more human-friendly.
def f(x):
ans = 0.000140092
ans = ans * ((1 + zs) ** (3 / 2))
ans = ans * ((x + 1) ** (3 / 2))
ans = ans * XHI
return ans * (
(9 / 2) * (np.log(1 - np.sqrt(b)) - np.log(np.sqrt(b) + 1))
+ (
1
/ 35
* (1 / (b - 1))
* (
10 * (b ** (9 / 2))
+ 18 * (b ** (7 / 2))
+ 42 * (b ** (5 / 2))
+ 210 * (b ** (3 / 2))
- 315 * (b ** (1 / 2))
)
- (
(9 / 2) * (np.log(1 - np.sqrt(a)) - np.log(np.sqrt(a) + 1))
+ (
1
/ 35
* (1 / (a - 1))
* (
10 * (a ** (9 / 2))
+ 18 * (a ** (7 / 2))
+ 42 * (a ** (5 / 2))
+ 210 * (a ** (3 / 2))
- 315 * (a ** (1 / 2))
)
)
)
)
)
Right away you see some symemtry. This chunk
10 * (b ** (9 / 2))
+ 18 * (b ** (7 / 2))
+ 42 * (b ** (5 / 2))
+ 210 * (b ** (3 / 2))
- 315 * (b ** (1 / 2))
is a dot product of some weights and a b raised to a vector of powers. If b were scalar, we could write it as np.dot(weights, np.sqrt(b) ** powers). Maybe we would even score some optimization points from using integral powers.
Putting thigs together, we can get something like this:
weights = np.array([10, 18, 42, 210, -315])
powers = np.array([9, 7, 5, 3, 1])
def log_term(x):
return (9 / 2) * (np.log(1 - np.sqrt(x)) - np.log(np.sqrt(x) + 1))
def dot_term(x):
return (1 / 35) * 1 / (x - 1) * np.dot(np.sqrt(x)[..., None] ** powers, weights)
def integrate(x):
return log_term(x) + dot_term(x)
factor1 = integrate(b) - integrate(a)
factor2 = 0.000140092 * ((1 + zs) ** (3 / 2)) * XHI
factor = factor1 * factor2
def f(x):
return factor * ((x + 1) ** (3 / 2))
With better variable names and comments this could almost be readable.
Side comment. Both in your original code and in this version, you define x in the body of your script. You also define several variables as a function of x, such as a and b.
Python scoping rules mean that these variables will not change if you pass a different x to f. If you want all of your variables to change with x, you should move the definitions inside the function.
Using good variable names will help a lot for who gonna read the code or even for you, and comments will help too.
For the rest, it is a equation, there is no good way of putting it.
I'm going to do 2D Gaussian fit in Python 3 by:
def gaussian_fit_2_d(data, amplitude, x0, y0, sigma_x, sigma_y, theta, offset):
x0 = np.float64(x0)
y0 = np.float64(y0)
a = (np.cos(theta) ** 2) / (2 * sigma_x ** 2) + (np.sin(theta) ** 2) / (2 * sigma_y ** 2)
b = -np.sin(2 * theta) / (4 * sigma_x ** 2) + np.sin(2 * theta) / (4 * sigma_y ** 2)
c = (np.sin(theta) ** 2) / (2 * sigma_x ** 2) + (np.cos(theta) ** 2) / (2 * sigma_y ** 2)
x = data["x"]
y = data["y"]
f = offset + amplitude * np.exp(-((a * (x - x0)) ** 2 + 2 * b * (x - x0) * (y - y0) + c * (y - y0) ** 2))
return f.ravel()
image = sio.loadmat("File Name")
intensity = np.float64(np. array(image["p1"]))
data_size = intensity.shape
x = np.arange(0, data_size[1])
y = np.arange(0, data_size[0])
# print(data_size)
# print(x)
[X, Y] = np.meshgrid(x, y)
data = {"x": X, "y": Y}
popt, pcov = opt.curve_fit(gaussian_fit_2_d, data, intensity)
,but in the last line I got the following error:
ValueError: operands could not be broadcast together with shapes
(1558,) (41,38)
any idea?
I'm trying to write a simple Python program which calculates the interference pattern from 2 incoming laser beams. Everything is working as it should but it's quite slow. I'm using a 400x400 array and it takes about 1.3 seconds to recalculate the intensity after I change a parameter. However, running the code with C++ takes about 0.18 seconds. So I'm wondering if I could improve something to speed things up?
My code so far:
def calculate_intensity_array():
laser1 = zeros((400, 400), dtype=complex)
laser2 = zeros((400, 400), dtype=complex)
data = zeros((400, 400), dtype=complex)
onoff_1 = laser1_onoff_var.get()
A_1 = laser1_intensity_var.get()
sigma_1 = laser1_sigma_var.get()
sin_phi_1 = sin((laser1_phi_var.get() / 180) * pi)
cos_phi_1 = cos((laser1_phi_var.get() / 180) * pi)
sin_theta_1 = sin((laser1_theta_var.get() / 180) * pi)
cos_theta_1 = cos((laser1_theta_var.get() / 180) * pi)
mu_x_1 = laser1_xpos_var.get()
mu_y_1 = laser1_ypos_var.get()
onoff_2 = laser2_onoff_var.get()
A_2 = laser2_intensity_var.get()
sigma_2 = laser2_sigma_var.get()
sin_phi_2 = sin((laser2_phi_var.get() / 180) * pi)
sin_theta_2 = sin((laser2_theta_var.get() / 180) * pi)
cos_phi_2 = cos((laser2_phi_var.get() / 180) * pi)
cos_theta_2 = cos((laser2_theta_var.get() / 180) * pi)
mu_x_2 = laser2_xpos_var.get()
mu_y_2 = laser2_ypos_var.get()
if onoff_1 == 0:
laser1 = zeros((400, 400), dtype=complex)
elif onoff_1 == 1:
for i in range(400):
for k in range(400):
laser1[i][k] = calculate_amplitude(
(k - 200) * 10,
(i - 200) * 10,
A_1,
sigma_1,
sin_phi_1,
cos_phi_1,
sin_theta_1,
cos_theta_1,
mu_x_1,
mu_y_1)
if onoff_2 == 0:
laser2 = zeros((400, 400), dtype=complex)
elif onoff_2 == 1:
for i in range(400):
for k in range(400):
laser2[i][k] = calculate_amplitude(
(k - 200) * 10,
(i - 200) * 10,
A_2,
sigma_2,
sin_phi_2,
cos_phi_2,
sin_theta_2,
cos_theta_2,
mu_x_2,
mu_y_2)
data = abs(laser1 + laser2) ** 2
return data
def calculate_amplitude(x, y, A, sigma, sin_phi, cos_phi,
sin_theta, cos_theta, mu_x, mu_y):
amplitude = A * (1 / (sqrt(2 * pi * (sigma ** 2 / cos_theta ** 2)))) *
exp(-((cos_phi *(x - mu_x) + sin_phi *(y - mu_y)) ** 2 * cos_theta ** 2) /
(2 * sigma ** 2)) *
(1 / (sqrt(2 * pi * sigma ** 2))) *
exp(-((-sin_phi * (x - mu_x) + cos_phi * (y - mu_y)) ** 2) /
(2 * sigma ** 2)) *
cmath.exp(1j *(2 * pi / 0.650) * sin_theta *
(cos_phi * (x - mu_x) + sin_phi * (y - mu_y)))
return amplitude
start = time.clock()
draw_data = calculate_intensity_array()
print time.clock()-start
Perhaps there is something that catches your eye that should be done different? The main calculation happens in calculate_amplitude, but I tried to input only sin, cos values, such that they don't have to be evaluated each time again.
The C++ equivalent looks like:
void calculate_intensity_array()
{
double intensity_array[400][400];
static complex<double> laser1[400][400];
static complex<double> laser2[400][400];
double A1 = 1;
double sigma1 = 2000;
double cos_theta1 = 0.9999619;
double sin_theta1 = 0.00872654;
double cos_phi1 = 1;
double sin_phi1 = 0;
double mu_x1 = 0.0;
double mu_y1 = 0.0;
double A2 = 1;
double sigma2 = 2000;
double cos_theta2 = 0.9999619;
double sin_theta2 = 0.00872654;
double cos_phi2 = 1;
double sin_phi2 = 0;
double mu_x2 = 0.0;
double mu_y2 = 0.0;
for (int i=0; i<400; i++)
{
for (int j=0; j<400; j++)
{
laser1[i][j] = calculate_amplitude((i-200)*10, (j-200)*10, A1,
sigma1, sin_phi1, cos_phi1,
sin_theta1, cos_theta1,
mu_x1, mu_y1);
laser2[i][j]=calculate_amplitude((i-200)*10, (j-200)*10, A2,
sigma2, sin_phi2, cos_phi2,
sin_theta2, cos_theta2,
mu_x2, mu_y2);
intensity_array[i][j] = pow(abs(laser1[i][j] + laser2[i][j]), 2);
}
}
}
complex<double> calculate_amplitude(double x, double y, double A,
double sigma, double sin_phi,
double cos_phi, double sin_theta,
double cos_theta, double mu_x,
double mu_y)
{
complex<double> output;
output = A * (1 / (sqrt(2 * M_PI * pow(sigma / cos_theta, 2)))) *
exp(-(pow(cos_phi * (x - 200 - mu_x) + sin_phi * (y - 200 - mu_y), 2) *
pow(cos_theta, 2)) / (2 * pow(sigma, 2))) *
(1 / (sqrt(2 * M_PI * pow(sigma, 2)))) *
exp(-(pow(-sin_phi * (x - 200 - mu_x) + cos_phi *
(y - 200 - mu_y), 2)) / (2 * pow(sigma, 2))) *
exp(complex<double>(0, (2 * M_PI / 0.650) * sin_theta *
(cos_phi * (x - 200 - mu_x) + sin_phi * (y - 200 - mu_y))));
return output;
}
Turn your code into C++ automagically!
The following python code looks like yours:
#pythran export loop(int, float, float, float, float, float, float, float, float)
from math import exp, sqrt, pi
import cmath
from numpy import empty
def loop(n,A, sigma, sin_phi, cos_phi,
sin_theta, cos_theta, mu_x, mu_y):
out = empty((n,n), dtype=complex)
for x in range(n):
for y in range(n):
out[x,y] = calculate_amplitude(x,y,A, sigma, sin_phi, cos_phi,
sin_theta, cos_theta, mu_x, mu_y)
return out
def calculate_amplitude(x, y, A, sigma, sin_phi, cos_phi,
sin_theta, cos_theta, mu_x, mu_y):
amplitude = (A * (1 / (sqrt(2 * pi * (sigma ** 2 / cos_theta ** 2)))) *
exp(-((cos_phi *(x - mu_x) + sin_phi *(y - mu_y)) ** 2 * cos_theta ** 2) /
(2 * sigma ** 2)) *
(1 / (sqrt(2 * pi * sigma ** 2))) *
exp(-((-sin_phi * (x - mu_x) + cos_phi * (y - mu_y)) ** 2) /
(2 * sigma ** 2)) *
cmath.exp(1j *(2 * pi / 0.650) * sin_theta *
(cos_phi * (x - mu_x) + sin_phi * (y - mu_y))))
return amplitude
Then compiling it with pythran:
$ pythran laser.py
And run it through timeit:
$ python -m timeit -s 'import laser' 'laser.loop(20,1,200,0.9,0.08,1,.5,.5,2)'
10000 loops, best of 3: 84.7 usec per loop
While the original code ran in:
$ python -m timeit -s 'import laser' 'laser.loop(20,1,200,0.9,0.08,1,.5,.5,2)'
100 loops, best of 3: 2.65 msec per loop
You can probably achieve a similar result with numba or cython :-)