How to re-write script of matrix 3D matlab in python - python

I newbie in python. I have matlab script like below. I want to re-write matrix 3D in matlab script in to python 3.x language. How can I fix it?
nl=length(res);
ndat=length(per);
phi=atan(1)*4;
amu=phi*4e-7;
for i=1:ndat
for j=1:nl
z=sqrt(phi*amu*res(j)/per(i));
zz(j)=complex(z,z);
exp0=exp((-2)*zz(j)/res(j)*thi(j));
exp1=complex(1,0)+exp0;
exp2=complex(1,0)-exp0;
%matrix 3D
ldi(1,1,j)=exp1;
ldi(1,2,j)=zz(j)*exp2
ldi(2,1,j)=exp2/zz(j);
ldi(2,2,j)=exp1;`
end
end

You'll find a self-contained implementation of your code (below), with a few key differences:
Python indexing starts from 0 instead of one
Python indexing uses square brackets instead of round ones
Mathematic functions must be imported from libraries (here math and cmath)
Good luck!
import math
import cmath
# Data
res = [1, 4, 1, 2, 3]
per = [5, 5, 1, 1, 0.5, 0.6]
thi = [1, 2, 3, 4, 5, 6]
nl = len(res)
ldi = [[[0 for x in range(nl)],[0 for x in range(nl)]], [[0 for x in range(nl)],[0 for x in range(nl)]]]
zz = [0]*nl
nl = len(res)
ndat = len(per)
phi = math.atan(1)*4
amu = phi*4e-7
for i in range(ndat):
for j in range(nl):
z = math.sqrt(phi*amu*res[j]/per[i])
zz[j] = complex(z,z)
exp0=cmath.exp((-2)*zz[j]/res[j]*thi[j]);
exp1=complex(1,0)+exp0;
exp2=complex(1,0)-exp0;
#- matrix 3D
ldi[0][0][j]=exp1;
ldi[0][1][j]=zz[j]*exp2
ldi[1][0][j]=exp2/zz[j]
ldi[1][1][j]=exp1

Related

Python syntax question - colon preceding a variable name

I'm in the process of learning some ML concepts using OpenCV, and I have a piece of python code that I was given to translate into c++. I have a very basic knowledge of python, and I've run into some syntax that I can't seem to find the meaning for.
I have a variable being passed into a method (whole method not shown) that is coming from the result of cv2.imread(), so an image. In c++, it's of type Mat:
def preprocess_image(img, side = 96):
min_side = min(img.shape[0], img.shape[1])
img = img[:min_side, :min_side * 2]
I have a couple questions:
What does the syntax ":min_side" do?
What is that line doing in terms of the image?
I am assuming the input of the image is a Matrix. In Python the image is generally read as numpy matrix
1.What does the syntax ":min_side" do?
It "Slice" the List/Array or basically in this case, a Matrix.
2.What is that line doing in terms of the image?
It "crops" the 2D Array(Basically a Matrix/Image)
A simple example of slicing:
x = np.array([[0, 1, 2],[3, 4, 5], [6, 7, 8]])
print(x)
out:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
Performing Slicing on this Matrix(Image):
x[:2, :3]
output after Slicing:
array([[0, 1, 2],
[3, 4, 5]])
A good source to read more about it would be straight from the source: https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html
The line:
img = img[:min_side, :min_side * 2]
is cropping the image so that the resulting image is min_side in height and min_side * 2 in width. The colon preceding a variable name is python's slicing syntax. Observe:
arr = [1, 2, 3, 4, 5, 6]
length = 4
print(arr[:length])
Output:
[1, 2, 3, 4]
:min_side is a shorthand for 0:min_side i.e it produces a slice the object from the start to min_side. For example:
f = [2, 4, 5, 6, 8, 9]
f[:3] # returns [2,4,5]
img = img[:min_side, :min_side *2] produces a crop of the image (which is a numpy array) from 0 to min_side along the height and from 0 to min_side * 2 along the width. Therefore the resulting image would be one of width min_side * 2 and height min_side .

parallelize zonal computation on numpy array

I try to compute mode on all cells of the same zone (same value) on a numpy array. I give you an example of code below. In this example sequential approach works fine but multiprocessed approach does nothing. I do not find my mistake.
Does someone see my error ?
I would like to parallelize the computation because my real array is a 10k * 10k array with 1M zones.
import numpy as np
import scipy.stats as ss
import multiprocessing as mp
def zone_mode(i, a, b, output):
to_extract = np.where(a == i)
val = b[to_extract]
output[to_extract] = ss.mode(val)[0][0]
return output
def zone_mode0(i, a, b):
to_extract = np.where(a == i)
val = b[to_extract]
output = ss.mode(val)[0][0]
return output
np.random.seed(1)
zone = np.array([[1, 1, 1, 2, 3],
[1, 1, 2, 2, 3],
[4, 2, 2, 3, 3],
[4, 4, 5, 5, 3],
[4, 6, 6, 5, 5],
[6, 6, 6, 5, 5]])
values = np.random.randint(8, size=zone.shape)
output = np.zeros_like(zone).astype(np.float)
for i in np.unique(zone):
output = zone_mode(i, zone, values, output)
# for multiprocessing
zone0 = zone - 1
pool = mp.Pool(mp.cpu_count() - 1)
results = [pool.apply(zone_mode0, args=(u, zone0, values)) for u in np.unique(zone0)]
pool.close()
output = results[zone0]
For positve integers in the arrays - zone and values, we can use np.bincount. The basic idea is that we will consider zone and values as row and cols on a 2D grid. So, can map those to their linear index equivalent numbers. Those would be used as bins for binned summation with np.bincount. Their argmax IDs would be the mode numbers. They are mapped back to zone-grid with indexing into zone.
Hence, the solution would be -
m = zone.max()+1
n = values.max()+1
ids = zone*n + values
c = np.bincount(ids.ravel(),minlength=m*n).reshape(-1,n).argmax(1)
out = c[zone]
For sparsey data (well spread integers in the input arrays), we can look into sparse-matrix to get the argmax IDs c. Hence, with SciPy's sparse-matrix -
from scipy.sparse import coo_matrix
data = np.ones(zone.size,dtype=int)
r,c = zone.ravel(),values.ravel()
c = coo_matrix((data,(r,c))).argmax(1).A1
For slight perf. boost, specify the shape -
c = coo_matrix((data,(r,c)),shape=(m,n)).argmax(1).A1
Solving for generic values
We will make use of pandas.factorize, like so -
import pandas as pd
ids,unq = pd.factorize(values.flat)
v = ids.reshape(values.shape)
# .. same steps as earlier with bincount, using v in place of values
out = unq[c[zone]]
Note that for tie-cases, it would pick random element off values. If you want to pick the first one, use pd.factorize(values.flat, sort=True).

Python NumPy: How to fill a matrix using an equation

I wish to initialise a matrix A, using the equation A_i,j = f(i,j) for some f (It's not important what this is).
How can I do so concisely avoiding a situation where I have two for loops?
numpy.fromfunction fits the bill here.
Example from doc:
>>> import numpy as np
>>> np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
One could also get the indexes of your array with numpy.indices and then apply the function f in a vectorized fashion,
import numpy as np
shape = 1000, 1000
Xi, Yj = np.indices(shape)
A = (2*Xi + 3*Yj).astype(np.int) # or any other function f(Xi, Yj)

Setting ranges to zero using numpy

I began independently learning numpy using the numpy cookbook. I reviewed and executed the following code:
import scipy.misc
import matplotlib.pyplot
#This script demonstates fancy indexing by setting values
#On the diagnols to 0
#Load lena array
lena = scipy.misc.lena()
xmax = lena.shape[0]
ymax = lena.shape[1]
#Fancy indexing
#can set ranges of points to zero, all at once instead of using loop
lena[range(xmax), range(ymax)] = 0
lena[range(xmax-1,-1,-1), range(ymax)] = 0
matplotlib.pyplot.imshow(lena)
matplotlib.pyplot.show()
I understand everything in this code except:
lena[range(xmax), range(ymax)] = 0
lena[range(xmax-1,-1,-1), range(ymax)] = 0
I read the documentation on indexing and slicing but still cannot make sense of the above code. Here is are my points of confusion:
1)range(xmax) and range(ymax) encompass the entire x,y axes. Wouldn't setting them to zero make the entire image black?
2)What does range(xmax-1,-1,-1) mean?
Thanks guys!
The first bit of code is actually misleading, and relies on the fact that lena is a square image: what happens is equivalent to calling zip(range(xmax), range(ymax)), and then setting each of the resulting tuples to 0. You can see what could go wrong here: if xmax != ymax, then things won't work:
>>> test = lena[:,:-3]
>>> test.shape
(512, 509)
>>> xmax, ymax = test.shape
>>> test[range(xmax), range(ymax)] = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
It would probably be better to define diag_max = min(xmax, ymax), and then set lena[range(diag_max), range(diag_max)] = 0.
The answer to your second question is easier: range(from, to, step) is the general call to range:
>>> range(1, 10, 2)
[1, 3, 5, 7, 9]
>>> range(1, 10, -2)
[]
>>> range(10, 1, -2)
[10, 8, 6, 4, 2]
>>> range(10, 0, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
In particular, this reverses the previous list, and so grabs the diagonal from right to left instead of left to right.
'range' will give you a list. Try it in your REPL and see what happens:
r = range(5)
# r is no [0,1,2,3,4]
So doing 'lena[range(xmax), range(ymax)] = 0' will set the diagonal of the 'lena' matrix to zero since you're stepping through the x and y coordinates incrementally at the same time.
'range' is quite simple. The answer from #JLLagrange answers it perfectly.

Efficiently Doing Diffusion on a 2d map in Python

I'm pretty new to Python, so I'm doing a project in it. Part of it includes a diffusion across a map. I'm implementing it by going through and making the current tile equal to .2 * the sum of its neighbors n,w,s,e. If I was doing this in C, I'd just do a double for loop that loops through an array doing arr[i*width + j] = arr of j+1, j-1, i+i, i-1 the neighbors) and have several different arrays that I'd do the same thing for (different qualities of the map I'd be changing). However, I'm not sure if this is really the fastest way in Python. Some people I have asked suggest stuff like numPy, but the width probably won't be more than ~200 (so 40-50k elements max) and I wasn't sure if the overhead is worth it. I don't really know any builtin functions to do what I want. Any advice?
edit: This will be very dense i.e. every spot is going to have a non-trivial calculation
This is quite simple to arrange with NumPy. The function np.roll returns a copy of the array, "rolled" in a specified direction.
For example, given the array x,
x=np.arange(9).reshape(3,3)
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])
you can roll the columns to the right with
np.roll(x,shift=1,axis=1)
# array([[2, 0, 1],
# [5, 3, 4],
# [8, 6, 7]])
Using np.roll, boundaries are wrapped like on a torus. If you do not want wrapped boundaries, you could pad the array with an edge of zeros, and reset the edge to zero before every iteration.
import numpy as np
def diffusion(arr):
while True:
arr+=0.2*np.roll(arr,shift=1,axis=1) # right
arr+=0.2*np.roll(arr,shift=-1,axis=1) # left
arr+=0.2*np.roll(arr,shift=1,axis=0) # down
arr+=0.2*np.roll(arr,shift=-1,axis=0) # up
yield arr
N=5
initial=np.random.random((N,N))
for state in diffusion(initial):
print(state)
raw_input()
Use convolution.
from numpy import *
from scipy.signal import convolve2d
mapArr=array(map)
kernel=array([[0 , 0.2, 0],
[0.2, 0, 0.2],
[0 , 0.2, 0]])
diffused=convolve2d(mapArr,kernel,boundary='wrap')
Is this for the ants challenge? If so, in the ants context, convolve2d worked ~20 times faster than the loop, in my implementation.
This modification to unutbu's code maintains constant the global sum of the array while diffuses the values of it:
import numpy as np
def diffuse(arr, d):
contrib = (arr * d)
w = contrib / 8.0
r = arr - contrib
N = np.roll(w, shift=-1, axis=0)
S = np.roll(w, shift=1, axis=0)
E = np.roll(w, shift=1, axis=1)
W = np.roll(w, shift=-1, axis=1)
NW = np.roll(N, shift=-1, axis=1)
NE = np.roll(N, shift=1, axis=1)
SW = np.roll(S, shift=-1, axis=1)
SE = np.roll(S, shift=1, axis=1)
diffused = r + N + S + E + W + NW + NE + SW + SE
return diffused

Categories