How to solve equation using sympy? - python

I need to write a code to solve the McLachlan model equation.
to find value for c after substituting with different parameters (x and h ) from for-loops
how to do that ??!
I have the code written in matlab that makes what I exactly need .. but the same idea is not working for python I am getting errors !!
Traceback (most recent call last):
File "func.py", line 18, in <module>
(x * f ** (1 / h) - x * c ** (1 / h))
NameError: name 'c' is not defined
here is my code in python
import numpy
from sympy import Symbol, solve
v_p = input("Enter perculion threshold:")
sigma_P = input("Enter MOFs conductivity:")
sigma_F = input("Enter filler conductivity:")
p = float(sigma_P)
f = float(sigma_F)
x = Symbol('c')
A = (1 - float(v_p) / float(v_p))
for h in numpy.arange(1, 1.5, 0.1):
for x in numpy.arange(0, 1, 0.1):
print(solve([
(
(x * f ** (1 / h) - x * c ** (1 / h))
/
(f ** (1 / h) + A * c ** (1 / h))
)
/
(
(p ** (1 / h) - c ** (1 / h) - x * p ** (1 / h) + x * c ** (1 / h))
/
(p ** (1 / h) + A * c ** (1 / h))
)
], [c]))
and this is the code written in matlab
syms sigma_c
A=4.777
sigma_f = 550
sigma_p = 1.7 * 10 ^ (-11)
for h = 2:10
for j = 1:10
v_f = 0.1 * j;
ans = solve([(((v_f) * (((sigma_f) ^ (1 / h)) - ((sigma_c) ^ (1 / h))))/(((sigma_f) ^ (1 / h)) + ((A) * ((sigma_c) ^ (1 / h))))) + (((1 - v_f) * (((sigma_p) ^ (1 / h)) - ((sigma_c) ^ (1 / h))))/(((sigma_p) ^ (1 / h)) + ((A) * ((sigma_c) ^ (1 / h))))) == 0], [sigma_c]);
answer = double(ans)
arr(h,j) = answer;
end
end
disp(arr)

You receive the "SyntaxError: invalid syntax" because not all parentheses are closed. The code below suggests are formatting to give more overview in the computation. I expect the ')' should be added on line 25, however this is obviously ambigious and you should verify this with your own idea.
Note that 'c' is still undefined, your code won't work without it.
import numpy
from sympy import Symbol, solve
v_p = input("Enter perculion threshold:")
sigma_P = input("Enter MOFs conductivity:")
sigma_F = input("Enter filler conductivity:")
p = float(sigma_P)
f = float(sigma_F)
x = Symbol('c')
A = (1 - float(v_p) / float(v_p))
for h in numpy.arange(1, 1.5, 0.1):
for x in numpy.arange(0, 1, 0.1):
print(solve([
(
(x * f ** (1 / h) - x * c ** (1 / h))
/
(f ** (1 / h) + A * c ** (1 / h))
)
/
(
(p ** (1 / h) - c ** (1 / h) - x * p ** (1 / h) + x * c ** (1 / h))
/
(p ** (1 / h) + A * c ** (1 / h))
)
], [c]))

SymPy can help a lot with the symbolic part. If you copy and paste your working equation and then replace it with the symbols you are trying to use in the Python version you will get an expression that is not the same as the one you entered in the Python version:
>>> eq2=S('''(((v_f) * (((sigma_f) ^ (1 / h)) - ((sigma_c) ^ (1 / h)))
)/(((sigma_f) ^ (1 / h)) + ((A) * ((sigma_c) ^ (1 / h))))) + ((
(1 - v_f) * (((sigma_p) ^ (1 / h)) - ((sigma_c) ^ (1 / h))))/((
(sigma_p) ^ (1 / h)) + ((A) * ((sigma_c) ^ (1 / h)))))'''.replace('^','**'))
>>> eq2 = eq2.subs(
'v_f','x').subs(
'sigma_f','f').subs(
'sigma_c','c').subs(
'sigma_p','p')
>>> factor_terms(eq2)
x*(-c**(1/h) + f**(1/h))/(A*c**(1/h) + f**(1/h)) + (1 - x)*(-c**(1/h) + p**(1/h))/(
A*c**(1/h) + p**(1/h))
But the good news is that either equation can be solved symbolically for c**(1/h), since it is quadratic in that expression, so you can then substitute values for x and h into the solutions after you compute them. A convenient way to do this is, for example, is
>>> soln = Tuple(*solve(x**2 - y, x))
>>> for yi in (2, 3):
... print(soln.subs(y, yi).n()) # the .n() to evaluate the values

Related

TypeError: f_p() argument after * must be an iterable, not numpy.float64

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.

Integrate Over Multiple Columns in 1 List to Fill Additional List With Same Number Of Columns

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.

Python3: How do I make this equation readable?

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.

Python error: operands could not be broadcast together with shapes

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?

Python simulation shows slow performance, how to speed array calculation up

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 :-)

Categories

Resources