Cannot change value of certain parts of array - python

Im trying to change the rows of an array with new values in a for loop, but cannot get it to work.
Problem is related to propagation of a wave packet in quantum physics.
Ive tried using the numpy.dot() function, but that doesnt work, and i tried making an easier for loop, that works.
import numpy as np
sig = 10**(-8)
x0 = 50*10**(-9)
L = 200*10**(-9)
N = 400
Nx = 1000
x = np.linspace(x0, L, N)
expsig = np.exp(-((1/2)*(x-x0)**2)/(sig**2))
expimg = np.exp(1j*(x-x0))
Phi = (1/(np.pi**(1/4)*np.sqrt(sig))*expsig*expimg)
Boxfunc = np.zeros(shape = (N, Nx))
for i in range(0, N):
SINnpi = np.sin(((i*np.pi)/L)*x)
Boxfunc[i,:] = np.sqrt(2/L)*SINnpi
Y = Boxfunc[i,:]*Phi
I expect the output to be a 400x1000 array with new calculated values from the multiplication between Phi and Boxfunc.
I just get the error message "could not broadcast input array from shape (400) into shape (1000)" when i get to the Boxfunc in the for-loop.

There is a problem with array x, it should be x = np.linspace(x0, L, Nx), then your code works.
Or you can define Boxfunc = np.zeros(shape = (Nx, N)). The problem is from the shape between x and Boxfunc.

Related

Baffled by numpy.unique()

As an extension to my previous project, where the equation X[i+1]=R*X[i](1-X[i]) is used to demonstrate a chaotic system (depending on R). Now I'm trying to construct the bifurcation graph.
About the code, I defined the function to do the actual calculations, and extracting the last 100 calculated values (to ensure the equilibrium reached), in order to plot out the bifurcated R vs x[i], I'm appending each R value to a empty X-data list, and multiple (aka, the returned 100 values) x[i] to a Y-data list (so it is actually a nested list...)
The thing is, depending on the R value, x[i] can be either single value (after equilibrium reached) or multiple values. So I was thinking to "purify" the nested Y-data list by numpy.unique() to remove all the replicated values.
Weirdly, when I don't make the extra "purification" step, the code actually works.
But when I put x = np.unique(logistic_calc(R,N)) it throws me a error says ValueError: setting an array element with a sequence.
Below is the code that works...
import numpy as np
import matplotlib.pyplot as plt
R = 0.2
N = 10_000
x0 = 0.5
def logistic_calc(R,N):
x = np.empty(N)
x[0] = x0
for i in range(1, N):
x[i] = R* x[i-1] * (1 - x[i-1])
return x[-100:]
x_lst = []
y_lst = []
for r in np.linspace(0.1,4,100):
R = r
x = logistic_calc(R,N)
x_lst.append(r)
y_lst.append(x)
plt.figure(figsize=(7, 4))
plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")
plt.ylim(0, 1)
plt.grid(c="lightgray")
plt.xlabel(r"$r$")
plt.ylabel(r"$x_n$")
plt.show()
From matplotlib documentation, paragraph "Plotting multiple sets of data":
"If x and/or y are 2D arrays a separate data set will be drawn for every column. If both x and y are 2D, they must have the same shape. If only one of them is 2D with shape (N, m) the other must have length N and will be used for every data set m."
It is not explicitly written that all sublists must have the same length. But it only refers to 2D arrays and not ragged nested sequences. To understand the behavior of plt.plot, just imagine that x and y will be cast into numpy arrays. In your second case, since y_lst contains lists with different lengths, this conversion cannot be made.
So I would go for something like this:
plt.figure(figize=(7, 4))
for r in np.linspace(1, 4, 100):
x = np.unique(logistic_calc(r, N))
plt.plot([r], [x], '.', ms=.5, c="royalblue") # a little bit tricky!
# OR
# plt.plot([r] * len(x), x, '.', ms=.5, c="royalblue")
...
plt.show()
When I run your example with np.unique, I get ...
...
Traceback (most recent call last):
File "test.py", line 29, in <module>
plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")
... more stack trace
ValueError: setting an array element with a sequence.
So the error is clearly happening at line ...
plt.plot(x_lst, y_lst, ls='', marker='.',ms='0.5', c="royalblue")
because the shapes of x_lst and y_lst no longer match up when you use np.unique.
You can get the code to work by looping over each each index of x_lst and y_lst and plotting them separately ...
import numpy as np
import matplotlib.pyplot as plt
R = 0.2
N = 10_000
x0 = 0.5
def logistic_calc(R,N):
x = np.empty(N)
x[0] = x0
for i in range(1, N):
x[i] = R* x[i-1] * (1 - x[i-1])
return x[-100:]
x_lst = []
y_lst = []
for r in np.linspace(0.1,4,100):
R = r
x = logistic_calc(R,N)
x = x.reshape(100)
x_lst.append(r)
y_lst.append(np.unique(x.round(decimals=4)))
plt.figure(figsize=(7, 4))
for x, y in zip(x_lst, y_lst):
plt.plot([x]*len(y), y, ls='', marker='.',ms='0.5', c="royalblue")
plt.ylim(0, 1)
plt.grid(c="lightgray")
plt.xlabel(r"$r$")
plt.ylabel(r"$x_n$")
plt.show()

Plotting x_n = A**n * x0 in python

I'm trying to plot a matrix multiplication in python.
I have the matrix A = [[0,-1],[1,1.6]], and x0 = [[5],[-1]].
The task is to plot xn, when I know that xn = A**n * x0, for n = 1, ... ,30
This is my code so far:
import numpy as np
import matplotlib.pyplot as plt
n = 30
A = np.matrix([[0,-1],[1,1.6]])
xn = np.zeros(n)
x0 = np.matrix([[5],[-1]])
for i in range(n):
xn[i]= A**i*x0
plt.plot(xn)
plt.show()
I keep getting the value error: setting an array element with a sequence, and when it works I get a really strange plot, which is probably wrong. Any ideas on how to do it?
I'm not sure if you want to take the matrix to a power by multiplying it by itself or by exponentiating the numbers inside of it. In any case, the reason why your code is throwing a ValueError: setting an array element with a sequence. is because the matrix vector multiplication A**i * x0 returns an array of length two - i.e. a vector.
Maybe you want to plot the vectors that result from the matrix-vector product. In that case, this code should do the trick:
import numpy as np
import matplotlib.pyplot as plt
n = 30
A = np.matrix([[0,-1],[1,1.6]])
xn = np.zeros((n, 2))
x0 = np.matrix([[5],[-1]])
fig, ax = plt.subplots()
for i in range(n):
A = A # A
xn[i, :] = np.squeeze(np.dot(A, x0))
ax.plot([0, xn[i, 0]], [0, xn[i, 1]])
label = r"$A^{%i}$" % (i+1)
ax.annotate(label, xy=(xn[i, 0], xn[i, 1]))
plt.show()
Notice I changed the shape of xn - it's now (nx2) compared to n as in your code. This means the result of the matrix-vector product will fit into xn. The # notation indicates matrix multiply in python3. I also labeled the line in the resulting plot with the power the matrix was taken to. You can see the output vector changing direction as the matrix changes. I think this is a nice example of how matrices (especially 2x2) can be thought of as linear transformations when applied to vectors. This video explains that concept nicely: https://www.youtube.com/watch?v=kYB8IZa5AuE.

How can I avoid using a loop in this specific snippet of python code?

I have a specific python issue, that desperately needs to be sped up by avoiding the use of a loop, yet, I am at a loss as to how to do this. I need to read in a fits image, convert this to a numpy array (roughly, 2000 x 2000 elements in size), then for each element compute the statistics of a ring of elements around it.
As I have my code now, the statistics of the ring around the element is computed with a function using masks. This is fast but, of course, I call this function 2000x2000 times (the slow part).
I am relatively new to python. I think that using the mask function is clever, but I cannot find a way around individually addressing each element. Best of thanks for any help you can provide.
# First, the function computing the statistics within a ring
around the central pixel:<br/>
# flux = image intensity at pixel (i,j)<br/>
# rad1, rad2 = inner and outer radii<br/>
# array = image array<br/>_
def snr(flux, i, j, rad1, rad2, array):
a, b = i, j
nx, ny = array.shape
y, x = np.ogrid[-a:nx-a, -b:ny-b]
mask = (x*x + y*y >= rad1*rad1) & (x*x + y*y <= rad2*rad2)
Nmask = np.count_nonzero(mask)
noise = 0.6052697 * abs(Nmask * flux - sum(array[mask]))
return noise
# Now, the call to snr for each pixel in the array data1:<br/>_
frame1 = fits.open(in_frame, mode='readonly') # read in fits file
data1 = frame1[ext].data # convert to np array
ny, nx = data1.shape # array dimensions
noise1 = zeros((ny, nx), float) # empty array
r1 = 5 # inner radius (pixels)
r2 = 7 # outer radius (pixels)
# The function is fast, but calling it 2k x 2k times is not:
for j in range(ny):
for i in range(nx):
noise1[i,j] = der_snr(data1[i,j], i, j, r1, r2, data1)
The operation that you are trying to do can be expressed as an image convolution. Try something like this:
import numpy as np
import scipy.ndimage
from astropy.io import fits
def make_kernel(inner_radius, outer_radius):
if inner_radius > outer_radius:
raise ValueError
x, y = np.ogrid[-outer_radius:outer_radius + 1, -outer_radius:outer_radius + 1]
r2 = x * x + y * y
kernel = (r2 >= inner_radius * inner_radius) & (r2 <= outer_radius * outer_radius)
return kernel
in_frame = '<file path>'
ext = '...'
frame1 = fits.open(in_frame, mode='readonly')
data1 = frame1[ext].data
inner_radius = 5
outer_radius = 7
kernel = make_kernel(inner_radius, outer_radius)
n_kernel = np.count_nonzero(kernel)
conv = scipy.ndimage.convolve(data1, kernel, mode='constant')
noise1 = 0.6052697 * np.abs(n_kernel * data1 - conv)

Vecrtorized evluation of function defined by matrix over grid

I'm looking to plot the value of a function defined by a matrix over a grid of values.
Let S be an invertable 2x2 matrix and let x be a 2-dimensional vector. How can vectorize the evaluation of x#S#x over a two dimensional grid?
Here is how I currently do it. It works, but takes a beat to perform the computation since the grid is so fine.
#Initialize Matrix
S = np.zeros(shape = (2,2))
while np.linalg.matrix_rank(S)<S.shape[1]:
S = np.random.randint(-5,5+1, size = (2,2))
X,Y = [j.ravel() for j in np.meshgrid(np.linspace(-2,2,1001),np.linspace(-2,2,1001))]
Z = np.zeros_like(X)
for i,v in enumerate(zip(X,Y)):
v = np.array(v)
Z[i] = v#S#v
n = int(np.sqrt(X.size))
Z = Z.reshape(n,n)
X = X.reshape(n,n)
Y = Y.reshape(n,n)
plt.contour(X,Y,Z)
Simplest would be with stacking those X,Y into a 2-column 2D array and then using np.einsum to replace the loopy matrix-multiplications -
p = np.column_stack((X,Y)) # or np.stack((X,Y)).T
Zout = np.einsum('ij,jk,ik->i',p,S,p,optimize=True)

Storing intermediate values in a numpy array

I'm trying to simulate a 2-d random walk, with direction 0 < θ < 2π and T=1000 steps.
a=np.zeros((1000,1000))
def randwalk(x,y):
theta=2*math.pi*rd.rand()
x+=math.cos(theta);
y+=math.sin(theta);
return (x,y)
How can I store all the intermediate coordinates in a? I was initially trying something of the form:
for i in range(1000):
for j in range(1000):
a[i,j] = randwalk(x,y)
But this doesn't seem to work at all.
The main obvious problem is that you want a 2D array of 1000 points, not a 1000x1000 array. For example, you say you want to take 1000 steps, but your nested loop takes 1,000,000.
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import math
a=np.zeros((1000,2), dtype=np.float)
def randwalk(x,y):
theta=2*math.pi*rd.random()
x+=math.cos(theta);
y+=math.sin(theta);
return (x,y)
x, y = 0., 0.
for i in range(1000):
x, y = randwalk(x,y)
a[i,:] = x, y
plt.figure()
plt.plot(a[:,0], a[:,1])
plt.show()
You probably want something like
T = 1000
a = [(0,0)] * T
for i in range(1, len(a)):
a[i] = randwalk(*a[i - 1])
No need for numpy here.
You've got a type error. randwalk is returning a 2-tuple, and you're trying to set an array element where a float is expected.
First of all, you don't want a 1000 by 1000 array. This would give a million data points, and you only need 2000. I think what you want is something like this:
xs = np.zeros((1000))
ys = np.zeros((1000))
x = 0
y = 0
for i in range(1000):
xs[i], ys[i] = randwalk()
Also, should change the definition of randwalk to take no parameters, and to make x and y global variables:
def randwalk():
global x, y
As you have it, you're modifying the values of the parameters, but they aren't accumulated from call to call.

Categories

Resources