I have cython code I'm using to speed up a bottleneck in an otherwise pure python calculation. I have a pair of points in a periodic box of length Lbox (1d case is fine for this question). I need to compute the sign of y-x, and I need to flip this sign when the periodic boundary conditions are operative.
In the absence of PBCs, the following question provides the solution: Is there a standard sign function (signum, sgn) in C/C++?. That solution is what I use to compute the sgn function.
def sgn(x, y):
""" If x > y, returns 1.
If x < y, returns -1.
If x == y, returns 0.
"""
return (y < x) - (x < y)
The sgn_pbc function as written below returns the correct result, but is written inefficiently: the control flow within the sgn_pbc is the culprit for slowing down the PBC version. How can I write sgn_pbc in an analogous way to the sgn function, so that I avoid the clumsy control flow?
def sgn_pbc(x, y, Lbox):
d = abs(x-y)
if d <= Lbox/2.:
return sgn(x, y)
else:
return -1*sgn(x, y)
First,
-1*sgn(x, y) == sgn(y, x)
then,
def sgn_pbc(x, y, Lbox):
d = abs(x-y)
if d <= Lbox/2.:
return sgn(x, y)
else:
return sgn(y, x)
Also in Python, function calls are the most expensive operations. You can inline your sgn.
def sgn_pbc(x, y, Lbox):
d = abs(x-y)
if d <= Lbox/2.:
return (y < x) - (x < y)
else:
return (x < y) - (y < x)
But then the if can be (mostly) rewritten as:
def sgn_pbc(x, y, Lbox):
d = abs(x-y)
w = sgn(Lbox/2., d)
return w * sgn(x, y)
And again, inlining the sgn,
def sgn_pbc(x, y, Lbox):
d = abs(x-y)
w = sgn(Lbox/2., d)
return w * (y < x) - (x < y)
I say mostly because the case where d == Lbox/2. this returns a wrong value.
Haven't timed it, though.
Related
I wrote this program describing an algorithm for the simulation of a partial differential equation. The basic functions I use are defined by
import numpy as np
import math
from scipy import integrate, stats
def shift(func, x, a=0):
return func(x-a)
def scale(func, a=1):
return a*func
def trunc(func, x):
if x <= 0:
return 0
else:
return func(x)
def quad(func, a, b):
return integrate.quad(func, a, b)
def gauss(func, t, x):
def pregau(z):
k = (-t ** (1 / 2)) * z
return shift(func, x, k)*math.exp(-(z**2)/2)
fa = (1 / ((2 * math.pi) ** (1 / 2)) * integrate.quad(pregau, -np.inf, np.inf)[0])
return fa
The program then simulates the solution to the partial differential equation by
def vundl(x, u, l0=0.0, a=a, b=b, c=c):
v = [u(x)]
l = [l0]
f_temp_rec = u
for i in range(10):
def f_temp(x):
y = x - c * dt + B[i + 1] * 2 * a
z = b * dt
return gauss(f_temp_rec, z, y)
li = l[i] + quad(f_temp, 0, np.inf)[0]
l = np.append(l, li)
if x <= 0:
v = np.append(v, 0)
f_temp_rec = 0
else:
f_temp_rec = f_temp
v = np.append(v, f_temp(x))
return [v, l]
def u0(x):
return stats.beta.pdf(x, 2.7, 3.05)
print(vundl(x = 0.5, u0))
If I run this program for N=0 it produces a vector. Running the program for N>0 gives me the following error:
"RecursionError: maximum recursion depth exceeded"
but it actually should give me a vector v and a vector l.
I'm not sure exactly what you're trying to do in vundl with f_temp and f_temp_rec, but in the else: block you assign:
f_temp_rec = f_temp
and then call f_temp which calls gauss(f_temp_rec, z, y). Since at this point f_temp_rec is f_temp the function f_temp calls itself in an infinite recursion.
You should be able to see in in traceback that f_temp is calling itself repeatedly.
How can I implement with numpy:
and its derivative f'(x)? I tried to:
def func (x,y):
if x.all() <= 0:
y = beta (np.exp(x)-1)
return y
elif x>0:
y = x
return y
However they're not working. Note that x and y are arrays.
How about:
def func (x, beta):
y = np.empty_like(x)
mask = x <= 0
y[mask] = beta * (np.exp(x[mask])-1)
y[~mask] = x[~mask]
return y
mask contains the indizes for elements that are <= 0, so that you can seperate the two cases.
I am trying to calculate an integral as a summation of points. This is the important part of my code:
I define an array:
x = np.arange(-3,3,0.0223)
For this array I want to define a function shell_charge that sums the values of the bits inside of a shell that I define as r <= x
def piecew(x):
inside_shell = np.where(r <= x)
shell_charge = np.sum(dq[inside_shell])
^^ this is what I am trying to understand and fix
conds = [x == 0, (x >= -0.5) & (x <= 0.5), (x > 0.5) & (x < -0.5)]
funcs = [lambda x: 0.0, lambda x: k * shell_charge * (x)**-2,
lambda x: k * total_charge * (x+0.5)**-2.]
return np.piecewise(x, conds, funcs)
xx = np.linspace(-3, 3, 1000)
plt.plot(xx,piecew(xx))
plt.title("electric field along the x-axis")
plt.xlabel("x position [m]")
plt.ylabel("mag(E) [N/C]")
plt.show()
I am very new to working with arrays and I am not sure how to do this, I would really appreciate any help.
Can anyone help me in finding a bijective mathematical function from N * N * N → N that takes three parameters x, y, and z and returns a number n?
I would like to know the function f and its inverse f' in a way that if I have n I will be able to determine x, y, z by applying f'(n).
Defining f as a composition of a simpler function g
Suppose g is a bijection from N × N to N and let g-1 be its inverse. Then we can define f in terms of g as follows.
f(x, y, z) = g(g(x, y), z) = n
f-1(n) = (x, y, z) where g-1(n) = (w, z) and g-1(w) = (x, y)
Defining g as a bijection from N × N to N
We now have the much simpler problem of defining g.
g(x, y) = (x + y)(x + y + 1) / 2 + y = n
g-1(n) = (x, y) where m = ⌊(2n)1/2⌋ and exactly one of the following two conditions hold.
x + y = m and y = n - m(m + 1) / 2
x + y = m - 1 and y = n - m(m - 1) / 2
Python implementation
def f(x, y, z):
return g(g(x, y), z)
def f_inv(n):
w, z = g_inv(n)
x, y = g_inv(w)
return (x, y, z)
def g(x, y):
return (x + y) * (x + y + 1) / 2 + y
def g_inv(n):
m = math.floor(math.sqrt(2 * n))
while True:
y = n - m * (m + 1) / 2
if y >= 0:
break
m -= 1
x = m - y
return x, y
your function is not surjective, let p is a prime number, we can't find any x,y,z in N such that p=2^x3^y5^z...
F(x,y,z) = 2^x*3^y*5^z
In fact you can choose any distinct set of prime numbers. And inverse is simply by factorizing to corresponding prime factors.
I'm trying to plot a piecewise fit to my data, but I need to do it with an arbitrary number of line segments. Sometimes there are three segments; sometimes there are two. I'm storing the coefficients of the fit in actable and the bounds on the segments in btable.
Here are example values of my bounds:
btable = [[0.00499999989, 0.0244274978], [0.0244275965, 0.0599999987]]
Here are example values of my coefficients:
actable = [[0.0108687987, -0.673182865, 14.6420775], [0.00410866373, -0.0588355861, 1.07750032]]
Here's what my code looks like:
rfig = plt.figure()
<>various other plot specifications<>
x = np.arange(0.005, 0.06, 0.0001)
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x=x: np.log10(actable[j][0] + actable[j][2] * x + actable[j][2] * x**2) for j in list(range(len(actable)))])
plt.plot(x, y)
The problem is that lambda sets itself to the last instance of the list, so it uses the coefficients for the last segment for all the segments. I don't know how to do a piecewise function without using lambda.
Currently, I'm cheating by doing this:
if len(btable) == 2:
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2)])
else if len(btable) == 3:
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2), lambda x: np.log10(actable[2][0] + actable[2][1] * x + actable[2][2] * x**2)])
else
print('Oh no! You have fewer than 2 or more than 3 segments!')
But this makes me feel icky on the inside. I know there must be a better solution. Can someone help?
This issue is common enough that Python's official documentation has an article Why do lambdas defined in a loop with different values all return the same result? with a suggested solution: create a local variable to be initialized by the loop variable, to capture the changing values of the latter within the function.
That is, in the definition of y it suffices to replace
[lambda x=x: np.log10(actable[j][0] + actable[j][1] * x + actable[j][2] * x**2) for j in range(len(actable))]
by
[lambda x=x, k=j: np.log10(actable[k][0] + actable[k][1] * x + actable[k][2] * x**2) for j in range(len(actable))]
By the way, one can use one-sided inequalities to specify ranges for numpy.piecewise: the last of the conditions that evaluate to True will trigger the corresponding function. (This is a somewhat counterintuitive priority; using the first true condition would be more natural, like SymPy does). If the breakpoints are arranged in increasing order, then one should use "x>=" inequalities:
breaks = np.arange(0, 10) # breakpoints
coeff = np.arange(0, 20, 2) # coefficients to use
x = np.arange(0, 10, 0.1)
y = np.piecewise(x, [x >= b for b in breaks], [lambda x=x, a=c: a*x for c in coeff])
Here each coefficient will be used for the interval that begins with the corresponding breakpoint; e.g., coefficient c=0 is used in the range 0<=x<1, coefficient c=2 in the range 1<=x<2, and so on.