reordering for FFT in python - python

I'm new to python and FFT. I have taken a small task in Python to find the shuffling order for a given number of datapoints.
My objective is to have an output like below for N datapoints. Here N=8, so we have 3 sets:
[0, 1, 0, 1, 0, 1, 0, 1]
[0, 0, 1, 1, 0, 0, 1, 1]
[0, 0, 0, 0, 1, 1, 1, 1]
The code I tried is below. Could someone help me where I'm wrong and suggest modifications to the code to produce the desired output.
le=8
steps=int(math.ceil(math.log(le,2)))
pos2=[]
m=0
for k in range(0,steps):
x=2**k
#print x
pos1=[]
for i in range(0,le):
if m<x:
pos1.append(0)
m=m+1
else:
pos1.append(1)
m=0
pos2.append(pos1)

You immediately get back to appending 0s after appending only one 1. Here is a working version with slightly different logic:
import math
le = 8
steps = int(math.ceil(math.log(le, 2)))
pos2 = []
for k in range(0, steps):
x = 2**k
pos1 = []
while len(pos1) < le:
for i in range(0, x):
pos1.append(0)
for i in range(0, x):
pos1.append(1)
pos2.append(pos1)
print pos1
this will print
[0, 1, 0, 1, 0, 1, 0, 1]
[0, 0, 1, 1, 0, 0, 1, 1]
[0, 0, 0, 0, 1, 1, 1, 1]
and here is a one-liner for you to examine:
import math
le = 8
pos2 = [[(i // 2**k) % 2 for i in range(le)] for k in range(int(math.ceil(math.log(le, 2))))]
print pos2

Related

Python - Replacing Values Leading Up To 1s in an Array

Pretend I have a pandas Series that consists of 0s and 1s, but this can work with numpy arrays or any iterable. I would like to create a formula that would take an array and an input n and then return a new series that contains 1s at the nth indices leading up to every time that there is at least a single 1 in the original series. Here is an example:
array = np.array([0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1])
> preceding_indices_function(array, 2)
np.array([0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1])
For each time there is a 1 in the input array, the two indices preceding it are filled in with 1 regardless of whether there is a 0 or 1 in that index in the original array.
I would really appreciate some help on this. Thanks!
Use a convolution with np.convolve:
N = 2
# craft a custom kernel
kernel = np.ones(2*N+1)
kernel[-N:] = 0
# array([1, 1, 1, 0, 0])
out = (np.convolve(array, kernel, mode='same') != 0).astype(int)
Output:
array([0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1])
Unless you don't want to use numpy, mozway's transpose is the best solution.
But since several iterations have been given, I add my itertools based solution
[a or b or c for a,b,c in itertools.zip_longest(array, array[1:], array[2:], fillvalue=0)]
zip_longest is the same as classical zip, but if the iterators have different "lengths", the number of iteration is the one of the longest, and finished iterators will return None. Unless you add a fillvalue parameter to zip_longest.
So, here itertools.zip_longest(array, array[1:], array[2:], fillvalue=0) gives a sequence of triplets (a,b,c), of 3 subsequent elements (a being the current element, b the next, c the one after, b and c being 0 if there isn't any next element or element after the next).
So from there, a simple comprehension build a list of [a or b or c] that is 1 if a, or b or c is 1, 0 else.
import numpy as np
array = np.array([0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1])
array = np.array([a or array[idx+1] or array[idx+2] for idx, a in enumerate(array[:-2])] + [array[-2] or array[-1]] + [array[-1]])
this function works if a is a list, should work with other iterables as well:
def preceding_indices_function(array, n):
for i in range(len(a)):
if array[i] == 1:
for j in range(n):
if i-j-1 >= 0:
array[i-j-1] = 1
return array
I got a solution that is similar to the other one but slightly simpler in my opinion:
>>> [1 if (array[i+1] == 1 or array[i+2] == 1) else x for i,x in enumerate(array) if i < len(array) - 2]
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1]

Why python sum() function doesn't work in this case?

The prompt for the question is linked here:Hourglass sum in 2D array
I have written 2 different codes that are supposed to output the same thing.
Code1
def hourglassSum(arr):
total = []
for i in range(0, 4):
for j in range(0, 4):
total.append(arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j]+ arr[i+2][j+1]+ arr[i+2][j+2])
return max(total)
Code2
def hourglassSum(arr):
total = []
for i in range(0, 4):
for j in range(0, 4):
total.append(sum(arr[i][j:j+2]) + arr[i+1][j+1] + sum(arr[i+2][j:j+2]))
return max(total)
The 2nd code outputs a different value. Can anyone tell me what went wrong?
You forgot to include the not-included index. A slice has the format of start:end where the end integer is not included. So you have to do a +1 when converting from indices to a slice.
def hourglassSum1(arr):
total = []
for i in range(0, 4):
for j in range(0, 4):
total.append(arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j]+ arr[i+2][j+1]+ arr[i+2][j+2])
return max(total)
def hourglassSum2(arr):
total = []
for i in range(0, 4):
for j in range(0, 4):
# Use +3
total.append(sum(arr[i][j:j+3]) + arr[i+1][j+1] + sum(arr[i+2][j:j+3]))
return max(total)
l = [[1, 1, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
assert hourglassSum1(l) == hourglassSum2(l)
Let arr = [[1, 2, 3]] for this example.
sum(arr[0][0:2]) = 3 because we are summing 1 and 2.
sum(arr[0][0:3]) = 6 because we are summing 1, 2 and 3.
So the answer to your question is that [j:j+2] does not include j+2. You want to use [j:j+3]

Python: distance from index to 1s in binary mask

I have a binary mask like this:
X = [[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1],
[0, 0, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 1]]
I have a certain index in this array and want to compute the distance from that index to the closest 1 in the mask. If there's already a 1 at that index, the distance should be zero.
Examples (assuming Manhattan distance):
distance(X, idx=(0, 5)) == 0 # already is a 1 -> distance is zero
distance(X, idx=(1, 2)) == 2 # second row, third column
distance(X, idx=(0, 0)) == 5 # upper left corner
Is there already existing functionality like this in Python/NumPy/SciPy? Both Euclidian and Manhattan distance would be fine.
I'd prefer to avoid computing distances for the entire matrix (as that is pretty big in my case), and only get the distance for my one index.
Here's one for manhattan distance metric for one entry -
def bwdist_manhattan_single_entry(X, idx):
nz = np.argwhere(X==1)
return np.abs((idx-nz).sum(1)).min()
Sample run -
In [143]: bwdist_manhattan_single_entry(X, idx=(0,5))
Out[143]: 0
In [144]: bwdist_manhattan_single_entry(X, idx=(1,2))
Out[144]: 2
In [145]: bwdist_manhattan_single_entry(X, idx=(0,0))
Out[145]: 5
Optimize further on performance by extracting the boudary elements only off the blobs of 1s -
from scipy.ndimage.morphology import binary_erosion
def bwdist_manhattan_single_entry_v2(X, idx):
k = np.ones((3,3),dtype=int)
nz = np.argwhere((X==1) & (~binary_erosion(X,k,border_value=1)))
return np.abs((idx-nz).sum(1)).min()
Number of elements in nz with this method would be smaller number than the earlier one, hence it improves.
You can use scipy.ndimage.morphology.distance_transform_cdt to compute the "taxicab" (Manhattan) distance transform:
import numpy as np
import scipy.ndimage.morphology
x = np.array([[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1],
[0, 0, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 1]])
d = scipy.ndimage.morphology.distance_transform_cdt(1 - x, 'taxicab')
print(d[0, 5])
# 0
print(d[1, 2])
# 2
print(d[0, 0])
# 5
You can do it like this:
def Manhattan_distance(X, idx):
dist = min([ abs(i-idx[0]) + abs(j-idx[1]) for i, row in enumerate(X) for j, val in enumerate(X[i]) if val == 1])
return dist
Thanks.

Itertools with conditions in python 3

I am trying to generate some vectors with numbers [0....k-1], and with length k^n. n and k were given before.
k = 4
n = 2
args = list(product(range(k), repeat=n))
# vector=str([i for i in range(k)]*(n+1))
for i in product(range(k), repeat=k ** n):
if (check(i, args)): print(i)
Commented line is not important,it was my idea.
I need to generate this vectors with condition: I want to see each number from [0;k-1] in my vectors more or equal to (n) times. So it is task about permutations with replacements with special conditions to control numbers I can get. What shall I do?
For example I have k=2,n=2 vector from 4 elements and want to see 0 and 1 TWO or more times.
I should get 0011 0101 0110 1001 1010 1100
Everything is easy in example, but when k=5,n=2 (for example) there are 25-size vector and i want to see 0 1 2 3 4 2 times and other 17 numbers should be from 0 1 2 3 4 it becomes difficult.
UPDATE:
Here is a solution that generates the necessary combinations only. It is in principle faster, although the complexity is still exponential and you can quickly hit the limits of recursion.
def my_vectors(k, n):
# Minimum repetitions per element
base_repetitions = [n] * k
# "Unassigned" repetitions
rest = k ** n - k * n
# List reused for permutation construction
permutation = [-1] * (k ** n)
# For each possible repetition assignment
for repetitions in make_repetitions(base_repetitions, rest):
# Make all possible permutations
yield from make_permutations(repetitions, permutation)
# Finds all possible repetition assignments
def make_repetitions(repetitions, rest, first=0):
if rest <= 0:
yield repetitions
else:
for i in range(first, len(repetitions)):
repetitions[i] += 1
yield from make_repetitions(repetitions, rest - 1, i)
repetitions[i] -= 1
# Make all permutations with repetitions
def make_permutations(repetitions, permutation, idx=0):
if idx >= len(permutation):
yield list(permutation)
# If you are going to use the permutation within a loop only
# maybe you can avoid copying the list and do just:
# yield permutation
else:
for elem in range(len(repetitions)):
if repetitions[elem] > 0:
repetitions[elem] -= 1
permutation[idx] = elem
yield from make_permutations(repetitions, permutation, idx + 1)
repetitions[elem] += 1
for v in my_vectors(3, 2):
print(v)
Output:
(0, 0, 0, 0, 0, 1, 1, 2, 2)
(0, 0, 0, 0, 0, 1, 2, 1, 2)
(0, 0, 0, 0, 0, 1, 2, 2, 1)
(0, 0, 0, 0, 0, 2, 1, 1, 2)
(0, 0, 0, 0, 0, 2, 1, 2, 1)
(0, 0, 0, 0, 0, 2, 2, 1, 1)
(0, 0, 0, 0, 1, 0, 1, 2, 2)
(0, 0, 0, 0, 1, 0, 2, 1, 2)
(0, 0, 0, 0, 1, 0, 2, 2, 1)
(0, 0, 0, 0, 1, 1, 0, 2, 2)
...
This is an inefficient but simple way to implement it:
from itertools import product
from collections import Counter
def my_vectors(k, n):
for v in product(range(k), repeat=k ** n):
count = Counter(v)
if all(count[i] >= n for i in range(k)):
yield v
for v in my_vectors(3, 2):
print(v)
Output:
(0, 0, 0, 0, 0, 1, 1, 2, 2)
(0, 0, 0, 0, 0, 1, 2, 1, 2)
(0, 0, 0, 0, 0, 1, 2, 2, 1)
(0, 0, 0, 0, 0, 2, 1, 1, 2)
(0, 0, 0, 0, 0, 2, 1, 2, 1)
(0, 0, 0, 0, 0, 2, 2, 1, 1)
(0, 0, 0, 0, 1, 0, 1, 2, 2)
(0, 0, 0, 0, 1, 0, 2, 1, 2)
(0, 0, 0, 0, 1, 0, 2, 2, 1)
(0, 0, 0, 0, 1, 1, 0, 2, 2)
...
Obviously, as soon as your numbers get slightly bigger it will take forever to run, so it is only useful either for very small problems or as a baseline for comparison.
In any case, the number of items that the problem produces is exponentially large anyway, so although you can make it significantly better (i.e. generate only the right elements instead of all the possible ones and discarding), it cannot be "fast" for any size.

Calling a function within function does not work as expected?

I'm designing a maze generator in python and have various functions for different steps of the process. (I know the code can most definitely be improved but I'm just looking for an answer to my problem first before I work on optimizing it)
the first function generates a base maze in the form of a 2D list and works as expected:
def base_maze(dimension):
num_rows = int((2 * dimension[1]) + 1) #number of rows / columns
num_columns = int((2 * dimension[0]) + 1) #from tuple input
zero_row = [] #initialise a row of 0s
for i in range(num_columns):
zero_row.append(0)
norm_row = [] #initialise a row of
for i in range(num_columns // 2): #alternating 0s and 1s
norm_row.extend([0,1])
norm_row.append(0)
maze = [] #initialise maze
#(combination of zero rows
for i in range(num_rows // 2): # and normal rows)
maze.append(zero_row)
maze.append(norm_row)
maze.append(zero_row)
return maze
Another function gets the neighbors of the selected cell, and also works as expected:
def get_neighbours(cell, dimension):
y = cell[0] #set x/y values
max_y = dimension[0] - 1 #for reference
x = cell[1]
max_x = dimension[1] - 1
n = (x, y-1) #calculate adjacent
e = (x+1, y) #coordinates
s = (x, y+1)
w = (x-1, y)
if y > max_y or y < 0 or x > max_x or x < 0: #check if x/y
raise IndexError("Cell is out of maze bounds") #in bounds
neighbours = []
if y > 0: #add cells to list
neighbours.append(n) #if they're valid
if x < max_x: #cells inside maze
neighbours.append(e)
if y < max_y:
neighbours.append(s)
if x > 0:
neighbours.append(w)
return neighbours
the next function removes the wall between two given cells:
def remove_wall(maze, cellA, cellB):
dimension = []
x_dim = int(((len(maze[0]) - 1) / 2)) #calc the dimensions
y_dim = int(((len(maze) - 1) / 2)) #of maze matrix (x,y)
dimension.append(x_dim)
dimension.append(y_dim)
A_loc = maze[2*cellA[1]-1][2*cellA[0]-1]
B_loc = maze[2*cellB[1]-1][2*cellB[0]-1]
if cellB in get_neighbours(cellA, dimension): #if cell B is a neighbour
if cellA[0] == cellB[0] and cellA[1] < cellB[1]: #if the x pos of A is equal
adj_wall = maze[(2*cellA[0]+1)][2*cellA[1]+1+1] = 1 #to x pos of cell B and the y pos
#of A is less than B (A is below B)
elif cellA[0] == cellB[0] and cellA[1] > cellB[1]: #the adjacent wall is set to 1 (removed)
adj_wall = maze[(2*cellA[0]+1)][2*cellA[1]+1-1] = 1
#same is done for all other directions
if cellA[1] == cellB[1] and cellA[0] < cellB[0]:
adj_wall = maze[(2*cellA[0]+1)+1][(2*cellA[1]+1)] = 1
elif cellA[1] == cellB[1] and cellA[0] > cellB[0]:
adj_wall = maze[(2*cellA[0]+1-1)][(2*cellA[1]+1)] = 1
return maze
yet when I try to put these functions together into one final function to build the maze, they do not work as they work on their own, for example:
def test():
maze1 = base_maze([3,3])
maze2 = [[0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0]]
if maze1 == maze2:
print("they are exactly the same")
else:
print("WHY ARE THEY DIFFERENT???")
remove_wall(maze1,(0,0),(0,1))
remove_wall(maze2,(0,0),(0,1))
these will produce different results despite the input being exactly the same?:
test()
they are exactly the same
[[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0]]
The problem is in your base_maze function, where you first create two types of row:
zero_row = [] #initialise a row of 0s
for i in range(num_columns):
zero_row.append(0)
norm_row = [] #initialise a row of
for i in range(num_columns // 2): #alternating 0s and 1s
norm_row.extend([0,1])
norm_row.append(0)
This is fine so far and works as expected, however when you build the maze from there
for i in range(num_rows // 2): # and normal rows)
maze.append(zero_row)
maze.append(norm_row)
maze.append(zero_row)
You are filling up the maze list with multiple instances of the same list. This means if you modify row 0 of the maze, row 2 & 4 will also be affected. To illustrate:
>>> def print_maze(maze):
... print('\n'.join(' '.join(str(x) for x in row) for row in maze))
...
>>> print_maze(maze)
0 0 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 0 1 0
0 0 0 0 0
>>> maze[0][0] = 3
>>> print_maze(maze)
3 0 0 0 0
0 1 0 1 0
3 0 0 0 0
0 1 0 1 0
3 0 0 0 0
Note that rows 0, 2, & 4 have all changed. This is because maze[0] is the same zero_row instance as maze[2] and maze[4].
Instead, when you create the maze you want to use a copy of the row lists. This can be done easily in Python using the following slicing notation
for i in range(num_rows // 2):
maze.append(zero_row[:]) # note the [:] syntax for copying a list
maze.append(norm_row[:])
maze.append(zero_row[:])

Categories

Resources