How to pass a differentiable function explicitly to T.grad? - theano

Can you please tell, how can I pass various differentiable function to T.grad? I want something like this:
x = T.dscalar('x')
ellipic_paraboloid = x ** 2 + y ** 2
hyperbolic_paraboloid = x ** 2 - y ** 2
gradients = theano.function([function_of_xy, x, y], T.grad(function_of_xy, gx, gy))
gradients(ellipic_paraboloid, 1, 1)
gradients(hyperbolic_paraboloid, 1, 1)

Related

Numpy Vectorization for Nested 'for' loop

I was trying to write a program which plots level set for any given function.
rmin = -5.0
rmax = 5.0
c = 4.0
x = np.arange(rmin,rmax,0.1)
y = np.arange(rmin,rmax,0.1)
x,y = np.meshgrid(x,y)
f = lambda x,y: y**2.0 - 4*x
realplots = []
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if abs(f(x[i,j],y[i,j])-c)< 1e-4:
realplots.append([x[i,j],y[i,j]])`
But it being a nested for loop, is taking lot of time. Any help in vectorizing the above code/new method of plotting level set is highly appreciated.(Note: The function 'f' will be changed at the time of running.So, the vectorization must be done without considering the function's properties)
I tried vectorizing through
ans = np.where(abs(f(x,y)-c)<1e-4,np.array([x,y]),[0,0])
but it was giving me operands could not be broadcast together with shapes (100,100) (2,100,100) (2,)
I was adding [0,0] as an escape from else condition in np.where which is indeed wrong.
Since you get the values rather than the indexes, you don't really need np.where.
You can directly use the mask to index x and y, look at the "Boolean array indexing" section of the documentation.
It is straightforward:
def vectorized(x, y, c, f, threshold):
mask = np.abs(f(x, y) - c) < threshold
x, y = x[mask], y[mask]
return np.stack([x, y], axis=-1)
Your function for reference:
def op(x, y, c, f, threshold):
res = []
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if abs(f(x[i, j], y[i, j]) - c) < threshold:
res.append([x[i, j], y[i, j]])
return res
Tests:
rmin, rmax = -5.0, +5.0
c = 4.0
threshold = 1e-4
x = np.arange(rmin, rmax, 0.1)
y = np.arange(rmin, rmax, 0.1)
x, y = np.meshgrid(x, y)
f = lambda x, y: y**2 - 4 * x
res_op = op(x, y, c, f, threshold)
res_vec = vectorized(x, y, c, f, threshold)
assert np.allclose(res_op, res_vec)

Hyperbolic CORDIC in rotation (Z -> 0) to calculate sinh and cosh?

I implemented both circular and hyperbolic CORDIC algorithm in rotation mode:Z -> 0
In case of sin and cos which using circular implementation, the results are accurate. In case of sinh and cosh which is the hyperbolic algorithm, they are not.
The output of the code below (*_calc is the CORDIC version, *_good is the math.* version) is the following:
sin_good(20): 0.3420201433256687
sin_calc(20): 0.34202014332566866
sinh_good(20): 242582597.70489514
sinh_calc(20): 0.3555015499407712
cos_good(20): 0.9396926207859084
cos_calc(20): 0.9396926207859082
cosh_good(20): 242582597.70489514
cosh_calc(20): 1.0594692478629741
What am I doing wrong?
def lookup_circular(iteration):
return math.degrees(math.atan(2 ** -iteration))
def lookup_linear(iteration):
return 2 ** -iteration
def lookup_hyperbolic(iteration):
return math.degrees(math.atanh(2 ** -iteration))
def sin(angle):
x, y, z = cordic_circular_rotation_zto0(
x=1 / circular_scaling_factor(),
y=0,
z=float(angle)
)
return y
def cos(angle):
x, y, z = cordic_circular_rotation_zto0(
x=1 / circular_scaling_factor(),
y=0,
z=float(angle)
)
return x
def sinh(angle):
x, y, z = cordic_hyperbolic_rotation_zto0(
x=1 / hyperbolic_scaling_factor(),
y=0,
z=angle
)
return y
def cosh(angle):
x, y, z = cordic_hyperbolic_rotation_zto0(
x=1 / hyperbolic_scaling_factor(),
y=0,
z=angle
)
return x
def cordic_circular_rotation_zto0(x, y, z, n=64):
i = 0
while i <= n:
if z < 0:
newx = x + (y * 2.0 ** (-i))
newy = y - (x * 2.0 ** (-i))
z = z + lookup_circular(i)
else:
newx = x - (y * 2.0 ** (-i))
newy = y + (x * 2.0 ** (-i))
z = z - lookup_circular(i)
x = newx
y = newy
i += 1
return x, y, z
def cordic_hyperbolic_rotation_zto0(x, y, z, n=64):
i = 1
repeat = 4
while i <= n:
if z < 0:
newx = x - (y * 2.0 ** (-i))
newy = y - (x * 2.0 ** (-i))
z = z + lookup_hyperbolic(i)
else:
newx = x + (y * 2.0 ** (-i))
newy = y + (x * 2.0 ** (-i))
z = z - lookup_hyperbolic(i)
x = newx
y = newy
if i == repeat:
repeat = (i * 3) + 1
else:
i += 1
return x, y, z
def circular_scaling_factor(n=64):
e = 1
for i in range(0, n):
e = e * math.sqrt(1 + 2 ** (-2 * i))
return e
def hyperbolic_scaling_factor(n=64):
e = 1
for i in range(1, n):
e = e * math.sqrt(1 - 2 ** (-2 * i))
return e
if __name__ == '__main__':
angle = 20
sin_res = sin(angle)
print("sin_good({}): {}".format(angle, math.sin(math.radians(angle))))
print("sin_calc({}): {}".format(angle, sin_res))
print()
sinh_res = sinh(angle)
print("sinh_good({}): {}".format(angle, math.sinh(angle)))
print("sinh_calc({}): {}".format(angle, sinh_res))
print()
cos_res = cos(angle)
print("cos_good({}): {}".format(angle, math.cos(math.radians(angle))))
print("cos_calc({}): {}".format(angle, cos_res))
print()
cosh_res = cosh(angle)
print("cosh_good({}): {}".format(angle, math.cosh(angle)))
print("cosh_calc({}): {}".format(angle, cosh_res))
By removing the math.degrees of the inverse hyperbolic tan of lookup_hyperbolic, I find the following result for cosh:
both functions match until x~1.1, and then the cordic function stays constant.
Which is what can be found in Digital Arithmetic - Ercegovac/Lang 2003 chapter 11
max angle = 1.11817
Same for sinh:
There is an extended cordic alogrithm that you could try to implement:
Expanding the Range of Convergence of the CORDIC Algorithm
X. Hu, R. Harber, S. Bass
Published 1991
Computer Science
IEEE Trans. Computers

Determening begin parameters 2D gaussian fit

I'm working on some code which needs to be able to preform a 2d gaussian fitting. I mostly based my code on following question: Fitting a 2D Gaussian function using scipy.optimize.curve_fit - ValueError and minpack.error . Now is problem that I don't really have an initial guess about the different parameters that need to be used.
I've tried this:
def twoD_Gaussian(x_data_tuple, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
(x,y) = x_data_tuple
xo = float(xo)
yo = float(yo)
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)
g = offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo)
+ c*((y-yo)**2)))
return g.ravel()
The data.reshape(201,201) is just something I took from the aformentioned question.
mean_gauss_x = sum(x * data.reshape(201,201)) / sum(data.reshape(201,201))
sigma_gauss_x = np.sqrt(sum(data.reshape(201,201) * (x - mean_gauss_x)**2) / sum(data.reshape(201,201)))
mean_gauss_y = sum(y * data.reshape(201,201)) / sum(data.reshape(201,201))
sigma_gauss_y = np.sqrt(sum(data.reshape(201,201) * (y - mean_gauss_y)**2) / sum(data.reshape(201,201)))
initial_guess = (np.max(data), mean_gauss_x, mean_gauss_y, sigma_gauss_x, sigma_gauss_y,0,10)
popt, pcov = curve_fit(twoD_Gaussian, (x, y), data, p0=initial_guess)
data_fitted = twoD_Gaussian((x, y), *popt)
If I try this, I get following error message: ValueError: setting an array element with a sequence.
Is the reasoning about the begin parameters correct?
And why do I get this error?
If I use the runnable code from the linked question and substitute your definition of initial_guess:
mean_gauss_x = sum(x * data.reshape(201,201)) / sum(data.reshape(201,201))
sigma_gauss_x = np.sqrt(sum(data.reshape(201,201) * (x - mean_gauss_x)**2) / sum(data.reshape(201,201)))
mean_gauss_y = sum(y * data.reshape(201,201)) / sum(data.reshape(201,201))
sigma_gauss_y = np.sqrt(sum(data.reshape(201,201) * (y - mean_gauss_y)**2) / sum(data.reshape(201,201)))
initial_guess = (np.max(data), mean_gauss_x, mean_gauss_y, sigma_gauss_x, sigma_gauss_y,0,10)
Then
print(inital_guess)
yields
(13.0, array([...]), array([...]), array([...]), array([...]), 0, 10)
Notice that some of the values in initial_guess are arrays. The optimize.curve_fit function expects initial_guess to be a tuple of scalars. This is the source of the problem.
The error message
ValueError: setting an array element with a sequence
often arises when an array-like is supplied when a scalar value is expected. It is a hint that the source of the problem may have to do with an array having the wrong number of dimensions. For example, it might arise if you pass a 1D array to a function that expects a scalar.
Let's look at this piece of code taken from the linked question:
x = np.linspace(0, 200, 201)
y = np.linspace(0, 200, 201)
X, Y = np.meshgrid(x, y)
x and y are 1D arrays, while X and Y are 2D arrays. (I've capitalized all 2D arrays to help distinguish them from 1D arrays).
Now notice that Python sum and NumPy's sum method behave differently when applied to 2D arrays:
In [146]: sum(X)
Out[146]:
array([ 0., 201., 402., 603., 804., 1005., 1206., 1407.,
1608., 1809., 2010., 2211., 2412., 2613., 2814., 3015.,
...
38592., 38793., 38994., 39195., 39396., 39597., 39798., 39999.,
40200.])
In [147]: X.sum()
Out[147]: 4040100.0
The Python sum function is equivalent to
total = 0
for item in X:
total += item
Since X is a 2D array, the loop for item in X is iterating over the rows of X. Each item is therefore a 1D array representing a row of X. Thus, total ends up being a 1D array.
In contrast, X.sum() sums all the elements in X and returns a scalar.
Since initial_guess should be a tuple of scalars,
everywhere you use sum you should instead use the NumPy sum method. For example, replace
mean_gauss_x = sum(x * data) / sum(data)
with
mean_gauss_x = (X * DATA).sum() / (DATA.sum())
import numpy as np
import scipy.optimize as optimize
import matplotlib.pyplot as plt
# define model function and pass independant variables x and y as a list
def twoD_Gaussian(data, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
X, Y = data
xo = float(xo)
yo = float(yo)
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
)
g = offset + amplitude * np.exp(
-(a * ((X - xo) ** 2) + 2 * b * (X - xo) * (Y - yo) + c * ((Y - yo) ** 2))
)
return g.ravel()
# Create x and y indices
x = np.linspace(0, 200, 201)
y = np.linspace(0, 200, 201)
X, Y = np.meshgrid(x, y)
# create data
data = twoD_Gaussian((X, Y), 3, 100, 100, 20, 40, 0, 10)
data_noisy = data + 0.2 * np.random.normal(size=data.shape)
DATA = data.reshape(201, 201)
# add some noise to the data and try to fit the data generated beforehand
mean_gauss_x = (X * DATA).sum() / (DATA.sum())
sigma_gauss_x = np.sqrt((DATA * (X - mean_gauss_x) ** 2).sum() / (DATA.sum()))
mean_gauss_y = (Y * DATA).sum() / (DATA.sum())
sigma_gauss_y = np.sqrt((DATA * (Y - mean_gauss_y) ** 2).sum() / (DATA.sum()))
initial_guess = (
np.max(data),
mean_gauss_x,
mean_gauss_y,
sigma_gauss_x,
sigma_gauss_y,
0,
10,
)
print(initial_guess)
# (13.0, 100.00000000000001, 100.00000000000001, 57.106515650488404, 57.43620227324201, 0, 10)
# initial_guess = (3,100,100,20,40,0,10)
popt, pcov = optimize.curve_fit(twoD_Gaussian, (X, Y), data_noisy, p0=initial_guess)
data_fitted = twoD_Gaussian((X, Y), *popt)
fig, ax = plt.subplots(1, 1)
ax.imshow(
data_noisy.reshape(201, 201),
cmap=plt.cm.jet,
origin="bottom",
extent=(X.min(), X.max(), Y.min(), Y.max()),
)
ax.contour(X, Y, data_fitted.reshape(201, 201), 8, colors="w")
plt.show()

PyMC3 variable dependent on result of another

I am implementing a MCMC simulation for the first time and I have a variable that is defined based on the result of a previous variable. For instance if my bernoulli variable returns a 0, there will be a different value that gets fed into a deterministic variable than if it returns a 1.
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
if x == 1:
y = 1
elif x == 0:
y = 2
z = pm.Deterministic('z', y * 1000)
My issue is that neither of these if statements will get entered because x is not an integer, it is a distribution. Is there a way to get the sampled values of x? Or am I just thinking about this wrong?
You are right, you should use Theano's function switch
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
y = pm.math.switch(x, 1, 0)
z = pm.Deterministic('z', y * 1000)
or a little bit more verbose
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
y = pm.math.switch(pm.math.eq(x, 1), 1, 0)
z = pm.Deterministic('z', y * 1000)
switch evaluates the first argument, if true returns the second argument, otherwise the third one.
You can also use more than one switch if you have more than two conditions.
with pm.Model() as model:
x = pm.DiscreteUniform('x', 0, 2)
y_ = pm.math.switch(pm.math.eq(x, 1), 1, 0)
y = pm.math.switch(pm.math.eq(x, 2), 2, y_)
z = pm.Deterministic('z', y * 1000)

Lambdas and sums Python

def summation(calc_termo, linf, prox, lsup):
soma = 0
while linf <= lsup:
soma = soma + calc_termo(linf)
linf = prox(linf)
return soma
summation(lambda x: summation(lambda x: x, 1, lambda x: x + 1, x),1, lambda x: x + 1, 5)
I'm having trouble to understand how this code works. I got this as an exercise from my university and I'm having some trouble understanding the code.
It seems to be the sum of the numbers between 1 to 5, but can't understand what summation(lambda x: x, 1, lambda x: x + 1, x) does.
I'd start by taking those arguments apart:
lambda x: summation(lambda x: x, 1, lambda x: x + 1, x)
Substitute those variables back into the the original functions and simplify it:
def inner_function(x):
soma = 0
linf = 1
while linf <= x:
soma += linf + 1
linf += 1
return soma
Simplify that a little more:
def inner_function(x):
soma = 0
for linf in range(1, x + 1):
soma += linf
return soma
And a little more:
inner_function = lambda x: sum(range(1, x + 1))
And some more:
inner_function = lambda x: x * (x + 1) / 2
Now your original function becomes:
def summation(calc_termo, linf, prox, lsup):
soma = 0
while linf <= lsup:
soma = soma + calc_termo(linf)
linf = prox(linf)
return soma
summation(inner_function, 1, lambda x: x + 1, 5)
Or:
def summation(linf, prox, lsup):
soma = 0
while linf <= lsup:
soma = soma + linf * (linf + 1) / 2
linf = prox(linf)
return soma
summation(1, lambda x: x + 1, 5)
You can take it from there. I got:
summation = lambda: sum(n * (n + 1) / 2 for n in range(6))
Which is equal to:
sum(sum(range(n + 1)) for n in range(6))
The last line that you had trouble with could better be stated as:
summation(lambda x: summation(lambda y: y, 1, lambda z: z + 1, x),1, lambda w: w + 1, 5)
The lambdas don't all interfere with each other, if that's what you were confused about.

Resources