Say I have the following expression which I would like to integrate over the variable z from 0 to L.
import sympy as sp
mdot, D, R, alpha, beta, xi, mu0, q, cp, Tin, L = sp.symbols("\dot{m}, D, R, alpha, beta, xi, mu_0, q, c_p, T_in, L", real=True, positive=True, constant=True)
z = sp.symbols("z", real=True, positive=True)
n = sp.Symbol("n", real=True)
firstexpr = 8 * mdot**2 * R / (sp.pi**2 * D**5) * (alpha + beta * (sp.pi * D * mu0 / (4 * mdot))**xi * (q * z / (mdot * cp) + Tin)**(n * xi)) * (q * z / (mdot * cp) + Tin)
res1 = sp.integrate(firstexpr, (z, 0, L), conds="none")
This will take forever: I had to stop the computation after 10 minutes on my pc without getting an answer.
Situation improves dramatically if I rewrite my expression so that it contains only the minimum number of constant symbols, integrating it, and finally substituting the original symbols:
a = 8 * mdot**2 * R / (sp.pi**2 * D**5)
b = beta * (sp.pi * D * mu0 / (4 * mdot))**xi
c = q / (mdot * cp)
_a, _b, _c = sp.symbols("a, b, c", real=True, positive=True, constant=True)
secondexpr = _a * (alpha + _b * (_c * z + Tin)**(n * xi)) * (_c * z + Tin)
res2 = sp.integrate(secondexpr, (z, 0, L), conds="none")
sp.simplify(res2.subs([(_a, a), (_b, b), (_c, c)]))
Why is sympy taking extremely long time in the first case? Did I miss some assumption in the creation of my symbols?
Related
I am trying to approximate the inverse of the Fourier transform in two dimensions. For the inverse Fourier transform, I use the definition,
$$
F^{-1}[\phi](x, y) = \dfrac{1}{4\pi} \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} e^{-i (ux + wy} \phi(u, w) \text{d}u \text{d}w,
$$
for the inverse of the Fourier transform. The integral will be approximated by use of the trapezoidal integration rule. The grid structure is chosen as $x_j = x_0 + j\Delta_x$, $y_k = y_0 + k\Delta_y$, $u_n = \left(n - \frac{N}{2}\right) \Delta_u$ and $w_m = \left(m - \frac{N}{2}\right) \Delta_u$,
for $j, k, n, m, N \in \mathbb{N}$. By choosing the relations $\Delta_u \Delta_x = \dfrac{2\pi}{N}$ and $\Delta_w \Delta_y = \dfrac{2\pi}{N}$, the approximation of the two dimensional Fourier transform can be written in terms of the fast Fourier transform (FFT).
I implemented the results in Python, and tried to recover the bivariate normal density for different parameters $\sigma$ and $\mu$. As the normal density decays to zero, the grid can be constructed in terms of the mean and the variance.
Below, I have included the approximation in code:
from matplotlib import pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
from scipy.fft import fft, fft2
from scipy.stats import multivariate_normal
i = complex(0.0, 1.0)
def chF(uu, ww, mu, sigma):
return np.exp(
i * (uu * mu[0] + ww * mu[1])
- 0.5 * (
uu**2 * sigma[0,0]
+ ww**2 * sigma[1,1]
+ uu * ww * (sigma[0,1] + sigma[1,0])
)
)
def pdf(xx, yy, mu, sigma):
norm = multivariate_normal(mu, sigma)
return norm.pdf(np.dstack([xx, yy]))
def powerSequence(a, N, offset=0):
# Returns a sequence of a ^ (n + offset) for n in N
return a ** (np.arange(N) + offset)
def powerSequence2d(a, N1, N2, offset=0):
# Returns a sequence of a ^ (n + j + offset) for n,j in N
return a ** (np.array([
j + np.arange(N2) for j in range(0, N1)]) + offset)
def createSimple1dGrid(c1, c2, c4=0, N:int=2**9, L:float=10):
x0 = c1 - L * np.sqrt(c2)
dx = 2 * L * np.sqrt(c2 + np.sqrt(c4)) / N
du = 2 * np.pi / (N * dx)
x = x0 + np.arange(N) * dx
u = (np.arange(N) - N / 2) * du
return x, u, du
def createSimpleGrid(c11, c21, c12, c22, c14=0, c24=0,
N:int=2**9, L1:float=10, L2:float=10):
x, u, du = createSimple1dGrid(c11, c12, c14, N=N, L=L1)
y, w , dw = createSimple1dGrid(c21, c22, c24, N=N, L=L2)
return x, y, u, w, du, dw
def inverseTransform(x, y, u, w, du, dw, phinn, N):
# Compute edges of the trapezoidal integration rule for 2-dimensional integrals.
e1 = np.exp(-i * (u[0] * x + w[0] * y)) * phinn[0, 0]
e2 = np.exp(-i * (u[0] * x + w[N-1] * y)) * phinn[0, N-1]
e3 = np.exp(-i * (u[N-1] * x + w[0] * y)) * phinn[N-1, 0]
e4 = np.exp(-i * (u[N-1] * x + w[N-1] * y)) * phinn[N-1, N-1]
e = 0.25 * (e1 + e2 + e3 + e4)
# Compute boundaries of the trapezoidal integration rule
# for 2-dimensional integrals. These can be written in
# one-dimensional Fourier transforms.
b1 = np.exp(-i * w[0] * y) * powerSequence(-1, N)\
* fft(phinn[:, 0] * np.exp(-i * x[0] * u))
b2 = np.exp(-i * w[N-1] * y) * powerSequence(-1, N)\
* fft(phinn[:, N-1] * np.exp(-i * x[0] * u))
b3 = np.exp(-i * u[0] * x) * powerSequence(-1, N)\
* fft(phinn[0, :] * np.exp(-i * y[0] * w))
b4 = np.exp(-i * u[N-1] * x) * powerSequence(-1, N)\
* fft(phinn[N-1, :] * np.exp(-i * y[0] * w))
b = 0.5 * (b1 + b2 + b3 + b4)
# Compute IFFT-2d
func = phinn * np.exp(-i *(x[0] * u + y[0] * w))
invFour2d = powerSequence2d(-1, N, N)\
* fft2(func)
invTransform = 1 / (4 * np.pi**2) * du * dw * (invFour2d - b + e)
return invTransform
def test_recover_normal_density_off_2d_non_centred():
# Initialize parameters of the two-dimensional normal density
s1, s2 = 4.0, 10.0
mu, sigma = np.array([10, 10]), np.array([
[s1, 0.0],
[0.0, s2]
])
# Create the Fourier grid
N, L = 2**9, 10
x, y, u, w, du, dw = createSimpleGrid(mu[0], mu[1], s1, s2, N=N, L1=L, L2=L)
uu, ww = np.meshgrid(u, w, indexing="ij")
xx, yy = np.meshgrid(x, y, indexing="ij")
phi = chF(uu, ww, mu, sigma)
expected = pdf(xx, yy, mu,sigma)
# Compute the inverse transform
result = inverseTransform(x, y, u, w, du, dw, phi, N)
# Plot results
_, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(xx, yy, result)
ax.plot_wireframe(xx, yy, expected, color="r", rstride=10, cstride=10)
# manually make legend for plot
col1_patch = mpatches.Patch(color="b", label="approximation")
col2_patch = mpatches.Patch(color="r", label="expected")
legends = [col1_patch, col2_patch]
ax.legend(handles=legends)
plt.show()
The resulting plot is given as:
bivariate normal approximation
The approximation is correct, however, misplaced on the grid. I thought this had something to do with the way the fft algorithm places the origin. However, trying different shifts from scipy.fft import fftshift, ifftshift only worsen the results.
Using different values for $\mu$ yielded results that were closer to the approximation or sometimes even further off.
How do I get the approximation result to coincide with the expected plot of the bivariate normal?
I'm doing the CS1301xII course through edX and I'm being asked to calculate Pokemon damage by using one function to calculate the modifier, which I need to call another for the calculation.
There are 9 parameters:
STAB, Type, Critical, Other, Random, Level, Attack, Defense, and Base.
My first function calculates a modifier used in the damage calculation. This is (STAB * Type * Critical * Other * Random) for reference.
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
My second function is to calculate overall damage. This is (((2 * Level + 10) / 250) * (Attack / Defense) * Base + 2) for reference.
def calculate_damage(l, a, d, b):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2)
How do I go about calling the calculate_modifier function within my calculate_damage function? Do I list all 9 of the parameters? Really struggling with how this should look.
The final calculate_damage formula should be dam * mod
I am on this course too, but I've done this question. This is what you should do:
dam = (((2 * l + 10) / 250) * (a / d) * b + 2) * calculate_modifier(STAB * Type * Critical * Other * Random)
If you try to calculate it inside the dam function, the autograder disqualifies you.
You just return the mod value from the first function and pass it to second,
You don't have to pass 9 parameters to second function.
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
return mod
def calculate_damage(l, a, d, b, mod):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2) * mod
return dam
mod = calculate_modifier(s, t, c, o, r)
dam = calculate_damage(l, a, d, b, mod)
or you can return from both function and pass them to the third function to calculate the final value
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
return mod
def calculate_damage(l, a, d, b, mod):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2)
return dam
def calculate_total_damage(mod, dam):
return dam * mod
mod = calculate_modifier(s, t, c, o, r)
dam = calculate_damage(l, a, d, b)
final = calculate_total_damage(mod, dam)
I am trying to compile some Python C extensions for both Windows and Linux. The most time consuming part of my program seems to be a for loop with a significant amount of simple calculations. When running it on Linux, it is about 2x slower than on Windows. Adding -O2 or -O3 seems to help a little bit, but not much. Are there any other optimization methods that would get it to a comparable speed?
The compiler I'm using is GCC: gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Here is the python equivalent. The C code is using a loop instead of numpy operations:
def cf(sigma, kappa, theta, rho, s0, v0, r, ttm, n,
alpha = 1.0, delta = 0.01, lambda_ = 0.002, u = -0.5):
x = np.log(s0)
phi = np.arange(n) * delta - 1j*(alpha + 1)
qq = kappa - 1j * rho * sigma * phi
d = np.sqrt(qq ** 2 + sigma ** 2 * phi ** 2 + 1j * sigma ** 2 * phi)
c = (qq - d) / (qq + d)
cc = 1j * phi * r * ttm + ((kappa * theta) / sigma ** 2) * \
((qq - d) * ttm - 2 * np.log((-c * np.exp(-d * ttm) + 1) / (1 - c)))
dd = ((qq - d) / sigma ** 2) * (1 - np.exp(-d * ttm)) / (-c * np.exp(-d * ttm)+1)
f = np.exp(cc + dd * v0 + 1j * phi * x)
return f
I have an expression for a complex function as follows:
f(z) = 1/jwC + (R1(1+jwC1) + R2(1+jwC2))/(1+jwR1C1)(1+jwR2C2)
where j = sqrt(-1)
How do I compute f(z) in Python, given the values of w, R1, R2, C, C1, C2 and then seperate out the real and imaginary portions of f(z)?
Complex numbers are one of the standard types in Python.
So you could just write:
#!/usr/bin/env python3
def f(w, R1, R2, C, C1, C2):
return 1 / (1j * w * C) + (R1 * (1 + 1j * w * C1) + R2 * (
1 + 1j * w * C2)) / ((1 + 1j * w * R1 * C1) * (1 + 1j * w * R2 * C2))
result = f(w=1000, R1=100, R2=200, C=100.0e-9, C1=100.0e-9, C2=200.0e-9)
print(result)
print(result.real)
print(result.imag)
(NB: please check the math epxression yourself, since I didn't verify if the results are actually correct. I may have misinterpreted your equation or made a typo.)
Apologies for the (maybe misleading) title and the probably confusing question itself, i struggle a lot with wording my problem and especially compressing it into one sentence for the title. I want to find the roots of a function f(w, t, some_other_args) with two variables, w and t, using python. The real function structure is really long and complicated, you can find it on the end of this post. The important thing is that it contains the following line:
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
This means that w can't exceed 1, because that would lead to calculating the square root of a negative number, which, of course, is impossible. I have algorithms for calculating the approximate values of w and t using other values in my function, but they are very inaccurate.
So, i try to calculate the roots with scipy.optimize.fsolve (after trying literally every root finding algorithm i could find online, i found this one to be the best for my function) using these approximate values as starting points, which would look like this:
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
For most values, this works perfectly fine. If w is too close to 1, however, there always comes a point when fsolve tries some value bigger than 1 for w, which, in turn, raises a ValueError(because calculating the root of a negative number is mathematically impossible). This is an example printing out the values that fsolveis using, where w should be somewhere around 0.997:
w_approx: 0.9960090844989311
t_approx: 24.26777844720981
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.267778808827888, w:0.9960090844989311
Values: t:24.26777844720981, w:0.996009099340623
Values: t:16.319554685876746, w:1.0096680915775516
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 148, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 227, in _root_hybr
ml, mu, epsfcn, factor, diag)
File "C:\Users\...\algorithm.py", line 9, in f
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
ValueError: math domain error
So, how can i tell optimize.fsolve that w can't get bigger than 1? Or what are alternative algorithms for doing something like this (i know about brentq and so on, but all of those require giving an interval for both roots, which i don't want to do.)?
Code for testing (What's important to note here: even though func theoretically is supposed to calculate R and T given t and w, i have to use it the other way around. It's a bit clunky, but i simply don't manage to rewrite the function so that it accepts T, R to calculate t, w - it's a bit too much for my mediocre mathematical expertise ;)) :
import math as m
from scipy import optimize
import numpy as np
def func(t, w, r_1, r_2, r_3):
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
k23 = 2 * k / 3
z1 = 1 / (1 + k23)
z2 = 1 / (1 - k23)
z3 = 3 * ((1 / 5 + r_1 - r_2 - 1 / 5 * r_1 * r_2) / (z1 - r_2 * z2)) * m.exp(t * (k - 1))
z4 = -(z2 - r_2 * z1) / (z1 - r_2 * z2) * m.exp(2 * k * t)
z5 = -(z1 - r_2 * z2) / (z2 - r_2 * z1)
z6 = 3 * (1 - r_2 / 5) / (z2 - r_2 * z1)
beta_t = r_3 / (z2 / z1 * m.exp(2 * k * t) + z5) * (z6 - 3 / (5 * z1) * m.exp(t * (k - 1)))
alpha_t = beta_t * z5 - r_3 * z6
beta_r = (z3 - r_1 / 5 / z2 * m.exp(-2 * t) * 3 - 3 / z2) / (z1 / z2 + z4)
alpha_r = -z1 / z2 * beta_r - 3 / z2 - 3 / 5 * r_1 / z2 * m.exp(-2 * t)
It_1 = 1 / 4 * w / (1 - 8 / 5 * w) * (alpha_t * z2 * m.exp(-k * t) + beta_t * z1 * m.exp(k * t) + 3 * r_3 * m.exp(-t))
Ir_1 = (1 / 4 * w / (1 - 8 / 5 * w)) * (z1 * alpha_r + z2 * beta_r + 3 / 5 + 3 * r_1 * m.exp(-2 * t))
T = It_1 + m.exp(-t) * r_3
R = Ir_1 + m.exp(-2 * t) * r_1
return [T, R]
def calc_1(t, w, T, R, r_1, r_2, r_3):
t_begin = float(t[0])
T_new, R_new = func(t_begin, w, r_1, r_2, r_3)
a = abs(-1 + T_new/T)
b = abs(-1 + R_new/R)
return np.array([a, b])
def calc_2(x, T, R, r_1, r_2, r_3):
t = x[0]
w = x[1]
T_new, R_new = func(t, w, r_1, r_2, r_3)
a = abs(T - T_new)
b = abs(R - R_new)
return np.array([a, b])
def approximate_w(R):
k = (1 - R) / (R + 2 / 3)
w_approx = (1 - ((2 / 3 * k) ** 2)) / (1 - ((1 / 3 * k) ** 2))
return w_approx
def approximate_t(w, T, R, r_1, r_2, r_3):
t = optimize.root(calc_1, x0=np.array([10, 0]), args=(w, T, R, r_1, r_2, r_3))
return t.x[0]
def solve(T, R, r_1, r_2, r_3):
w_x = approximate_w(R)
t_x = approximate_t(w_x, T, R, r_1, r_2, r_3)
sol = optimize.fsolve(calc_2, x0=np.array([t_x, w_x]), args=(T, R, r_1, r_2, r_3))
return sol
# Values for testing:
T = 0.09986490557943692
R = 0.8918728343037964
r_1 = 0
r_2 = 0
r_3 = 1
print(solve(T, R, r_1, r_2, r_3))
What about logisticing the argument that you want to constrain? I mean, inside f, you could do
import numpy as np
def f(free_w, ...):
w = 1/(1 + np.exp(-free_w)) # w will always lie between 0 and 1
...
return zeros
And then, you would just have to apply the same logistic-transformation to the solution value of free_w to get w*. See
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
free_w = solution[0]
w = 1/(1 + np.exp(-free_w))
Your reported error occurs as fsolve can not deal with the implicit restrictions in the conversion of w to k. This can be solved radically by inverting that dependence, making func dependent on t and k instead.
def w2k(w): return 3 * m.sqrt((1.0 - w) / (4.0 - w))
#k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
# (k/3)**2 * (4-w)= 1-w
def k2w(k): return 4 - 3/(1-(k/3)**2)
def func(t, k, r_1, r_2, r_3):
w = k2w(k)
print "t=%20.15f, k=%20.15f, w=%20.15f"%(t,k,w)
...
Then remove the absolute values from the function values in calc1 and calc2. This only renders your solutions as non-differentiable points which is bad for any root-finding algorithm. Sign changes and smooth roots are good for Newton-like methods.
def calc_2(x, T, R, r_1, r_2, r_3):
t = x[0]
k = x[1]
T_new, R_new = func(t, k, r_1, r_2, r_3)
a = T - T_new
b = R - R_new
return np.array([a, b])
It makes not much sense to find the value for t by solving the equation keeping w resp. k fixed, it just doubles the computational effort.
def approximate_k(R):
k = (1 - R) / (R + 2 / 3)
return k
def solve(T, R, r_1, r_2, r_3):
k_x = approximate_k(R)
t_x = 10
sol = optimize.fsolve(calc_2, x0=np.array([t_x, k_x]), args=(T, R, r_1, r_2, r_3))
return sol
t,k = solve(T, R, r_1, r_2, r_3)
print "t=%20.15f, k=%20.15f, w=%20.15f"%(t, k, k2w(k))
With these modifications the solution
t= 14.860121342410327, k= 0.026653140486605, w= 0.999763184675043
is found within 15 function evaluations.
You should try defining explicitly your function before optimizing it, that way you can check for domain more easily.
Essentially you have a function of T and R. this worked for me:
def func_to_solve(TR_vector, r_1, r_2, r_3):
T, R = TR_vector # what you are trying to find
w_x = approximate_w(R)
t_x = approximate_t(w_x, T, R, r_1, r_2, r_3)
return (calc_2([t_x, w_x], T, R, r_1, r_2, r_3))
def solve(TR, r_1, r_2, r_3):
sol = optimize.fsolve(func_to_solve, x0=TR, args=(r_1, r_2, r_3))
return sol
Also, replace m.exp by np.exp