I am having difficulties trying to generate a specific pattern that would work for any square matrix with any square dimension using NumPy
For example:
User input: n = 3
Output:
[[1 2 0]
[2 3 2]
[0 2 1]]
User input: n = 5
Output:
[[1 2 3 0 0]
[2 3 4 0 0]
[3 4 5 4 3]
[0 0 4 3 2]
[0 0 3 2 1]]
User input: n = 8
Output:
[[1 2 3 4 5 0 0 0]
[2 3 4 5 6 0 0 0]
[3 4 5 6 7 0 0 0]
[4 5 6 9 8 7 6 5]
[5 6 7 8 9 6 5 4]
[0 0 0 7 6 5 4 3]
[0 0 0 6 5 4 3 2]
[0 0 0 5 4 3 2 1]]
Since a square matrix can be generated with any number in the form of (n x n), there would be instances where the user input is an odd number, how would I start figuring out the equations needed to make this work?
I got this going on but I was only able to do it on one corner of the matrix, any suggestion or idea is appreciated, thank you!
def input_number(n):
matrix = np.zeros(shape=(n, n), dtype=int)
for y in range(round(n // 2) + 1):
for x in range(round(n // 2) + 1):
matrix[y, x] = x + y + 1
y += 1
Input: n = 4
Output:
[[1 2 3 0 0]
[2 3 4 0 0]
[3 4 5 0 0]
[0 0 0 0 0]
[0 0 0 0 0]]
Try this:
def foo(n):
half = (n+1) // 2
res = np.zeros((n, n), int)
res[:half, :half] = np.arange(1, 1 + half) + np.arange(half).reshape(half, 1)
res[n//2:, n//2:] = res[half-1::-1, half-1::-1]
return res
This creates the top-left quarter then mirrors it to the bottom-right quarter.
Note it behaves a little differently to your example of n=8, the output is:
[[1, 2, 3, 4, 0, 0, 0, 0],
[2, 3, 4, 5, 0, 0, 0, 0],
[3, 4, 5, 6, 0, 0, 0, 0],
[4, 5, 6, 7, 0, 0, 0, 0],
[0, 0, 0, 0, 7, 6, 5, 4],
[0, 0, 0, 0, 6, 5, 4, 3],
[0, 0, 0, 0, 5, 4, 3, 2],
[0, 0, 0, 0, 4, 3, 2, 1]]
But I'll leave it this way because it seems more logical...you can edit the code if needed to make the center 4 values mix with each other as you showed.
I looked around a bit more and was eventually able to pull it off, here's my take on it.
import numpy as np
def input_number(n):
matrix = np.zeros(shape=(n, n), dtype=int)
for y in range(round(n // 2) + 1):
for x in range(round(n // 2) + 1):
matrix[y, x] = y + x + 1
matrix[(n - y) - 1][(n - x) - 1] = matrix[y, x]
print(matrix)
input_number(n)
Input: 3
Output:
[[1 2 0]
[2 3 2]
[0 2 1]]
Input: 5
Output:
[[1 2 3 0 0]
[2 3 4 0 0]
[3 4 5 4 3]
[0 0 4 3 2]
[0 0 3 2 1]]
Input: 8
Output:
[[1 2 3 4 5 0 0 0]
[2 3 4 5 6 0 0 0]
[3 4 5 6 7 0 0 0]
[4 5 6 9 8 7 6 5]
[5 6 7 8 9 6 5 4]
[0 0 0 7 6 5 4 3]
[0 0 0 6 5 4 3 2]
[0 0 0 5 4 3 2 1]]
I am not sure what is the pattern of zeros in these examples. In the cases of n=3 and n=5 the zero subarrays in the corners are of the size (n//2)x(n//2), but for n=8 they are of the size 3x3 and not 4x4. Assuming that the size of these subarrays should be (n//2)x(n//2) the following code should work:
n = 7
A = np.zeros((n, n), dtype=int)
for i in range(n):
A.ravel()[i:(n-i)*n:n+1] = n-i
m = n//2
A[:m, :m] = 0
A[-m:, -m:] = 0
A = A + A.T - np.diag(np.diag(A))
A = A[:, ::-1]
If the zero subarrays should be smaller, it suffices to change the value of m.
Related
Could you tell me if there is any 'smart' way to generate a 3D numpy array based on provided pattern? Let me explain what I mean by this. E.g., if pattern is [1, 4, 6, 4, 1], corresponding 2D array for it would be:
[
[1, 1, 1, 1, 1],
[1, 4, 4, 4, 1],
[1, 4, 6, 4, 1],
[1, 4, 4, 4, 1],
[1, 1, 1, 1, 1]
]
And 3D array is similar to 2D. If you imagine that 3D array as a cube: just one 6 in the center of 'cube', twenty six 4s around it in the closest neighborhood, and the rest 1s.
I apologize for potentially confusing explanation, I'm not a native English speaker. Please ask if something is unclear.
Thanks!
Any python library can be used.
You can use numpy.pad to add "layers" around your center number one by one (like an onion (well, a very cubic onion, actually) ):
pattern = [1,4,6]
x = np.array(pattern[-1]).reshape([1,1,1])
for p in reversed(pattern[:-1]):
x = np.pad(x, mode='constant', constant_values=p, pad_width=1)
print(x)
#[[[1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]]
#
# [[1 1 1 1 1]
# [1 4 4 4 1]
# [1 4 4 4 1]
# [1 4 4 4 1]
# [1 1 1 1 1]]
#
# [[1 1 1 1 1]
# [1 4 4 4 1]
# [1 4 6 4 1]
# [1 4 4 4 1]
# [1 1 1 1 1]]
#
# [[1 1 1 1 1]
# [1 4 4 4 1]
# [1 4 4 4 1]
# [1 4 4 4 1]
# [1 1 1 1 1]]
#
# [[1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]
# [1 1 1 1 1]]]
The code above should work with an arbitrary number of layers (in fact, it also works for an arbitrary amount of dimensions, if you adapt the reshape). However, it scales poorly with the number of layers, due to the for-loop. While it certainly is overkill to vectorize this for-loop in this application, I'd be open for suggestions if anyone has an idea.
The tricky part is generating the indices matching the pattern. The following should work for palindromes:
a = np.array([1,4,6,4,1])
i = np.ceil((np.r_[:2, 2:-1:-1][:, None] * np.r_[:2, 2:-1:-1]) / 2).astype(int)
a[i]
output:
array([[1, 1, 1, 1, 1],
[1, 4, 4, 4, 1],
[1, 4, 6, 4, 1],
[1, 4, 4, 4, 1],
[1, 1, 1, 1, 1]])
I have a tensor like this:
tf_a2 = tf.constant([[1, 2, 5 ],
[1, 4, 6 ],
[0, 10, 10],
[2, 4, 6 ],
[2, 4, 10]])
I would like to find whole indices in this matrice which are repeated more than n time.
For example: 1 being repeated two times. 2 being repeated three times. 5 being repeated one time. Repetition between rows is considered. Also, I want to skip the number 10 totally(10 is constant).
here n=2, So the result looks like: because 2 and 4 being repeated more than two times.
[[0, 2, 0 ],
[0, 4, 0 ],
[0, 0, 0 ],
[2, 4, 0 ],
[2, 4, 0 ]]
I found an example here but the explanations are for Matlab code.
Thanks in advance:)
First you can use tf.unique_with_counts to finds unique elements in a 1-D tensor.
import tensorflow as tf
tf_a2 = tf.constant([[1, 2, 5 ],
[1, 4, 6 ],
[0, 10, 10],
[2, 4, 6 ],
[2, 4, 10]])
n = 2
constant = 10
y, idx, count = tf.unique_with_counts(tf.reshape(tf_a2,[-1,]))
# y = [ 1 2 5 4 6 0 10]
# idx = [0 1 2 0 3 4 5 6 6 1 3 4 1 3 6]
# count = [2 3 1 3 2 1 3]
Then you can map repetition times to original tensor.
count_mask = tf.reshape(tf.gather(count,idx),tf_a2.shape)
# [[2 3 1]
# [2 3 2]
# [1 3 3]
# [3 3 2]
# [3 3 3]]
Finally you can skip the number 10 and get the result you expect by tf.where.
# skip constant and filter n time
result = tf.where(tf.logical_and(tf.greater(count_mask,n),
tf.not_equal(tf_a2,constant)),
tf_a2,
tf.zeros_like(tf_a2))
with tf.Session() as sess:
print(sess.run(result))
# [[0 2 0]
# [0 4 0]
# [0 0 0]
# [2 4 0]
# [2 4 0]]
I have a bool array (bool_arr) that I want to replace the consecutive non-zero numbers along the columns with their count (consecutive_count) (which is also the max/last number of the consecutive group)
bool_arr = consecutive_count =
[[1 1 1 1 0 1] [[3 6 1 6 0 1]
[1 1 0 1 1 0] [3 6 0 6 5 0]
[1 1 1 1 1 1] [3 6 3 6 5 2]
[0 1 1 1 1 1] [0 6 3 6 5 2]
[1 1 1 1 1 0] [2 6 3 6 5 0]
[1 1 0 1 1 1]] [2 6 0 6 5 1]]
I've created my own function that gets the cumulative sum of consecutive non-zero elements along the columns
consecutive_cumsum =
[[1 1 1 1 0 1]
[2 2 0 2 1 0]
[3 3 1 3 2 1]
[0 4 2 4 3 2]
[1 5 3 5 4 0]
[2 6 0 6 5 1]]
I currently use the following to get consecutive_count:
bool_arr = np.array([[1,1,1,1,0,1],
[1,1,0,1,1,0],
[1,1,1,1,1,1],
[0,1,1,1,1,1],
[1,1,1,1,1,0],
[1,1,0,1,1,1]])
consecutive_cumsum = np.array([[1,1,1,1,0,1],
[2,2,0,2,1,0],
[3,3,1,3,2,1],
[0,4,2,4,3,2],
[1,5,3,5,4,0],
[2,6,0,6,5,1]])
consecutive_count = consecutive_cumsum.copy()
for x in range(consecutive_count.shape[1]):
maximum = 0
for y in range(consecutive_count.shape[0]-1, -1, -1):
if consecutive_cumsum[y,x] > 0:
if consecutive_cumsum[y,x] < maximum: consecutive_count[y,x] = maximum
else: maximum = consecutive_cumsum[y,x]
else: maximum = 0
print(consecutive_count)
It works great but I am iterating over every element to replace with the max, between zeros.
Is there a way to use numpy to vectorize this instead of looping over all elements. And as a bonus, specify which axis (row vs column) it will perform it on
The new (v1.15.0 I believe) append and prepend keywords of np.diff make this easy:
bnd = np.diff(bool_arr, axis=0, prepend=0, append=0)
x, y = np.where(bnd.T)
bnd.T[x, y] *= (y[1::2]-y[::2]).repeat(2)
bnd[:-1].cumsum(axis=0)
# array([[3, 6, 1, 6, 0, 1],
# [3, 6, 0, 6, 5, 0],
# [3, 6, 3, 6, 5, 2],
# [0, 6, 3, 6, 5, 2],
# [2, 6, 3, 6, 5, 0],
# [2, 6, 0, 6, 5, 1]])
With selectable axis:
def count_ones(a, axis=-1):
a = a.swapaxes(-1, axis)
bnd = np.diff(a, axis=-1, prepend=0, append=0)
*idx, last = np.where(bnd)
bnd[(*idx, last)] *= (last[1::2]-last[::2]).repeat(2)
return bnd[..., :-1].cumsum(axis=-1).swapaxes(-1, axis)
UPDATE: and a version that works with general (not just 0/1) entries:
def sum_stretches(a, axis=-1):
a = a.swapaxes(-1, axis)
dtype = np.result_type(a, 'i1')
bnd = np.diff((a!=0).astype(dtype), axis=-1, prepend=0, append=0)
*idx, last = np.where(bnd)
A = np.concatenate([np.zeros((*a.shape[:-1], 1), a.dtype), a.cumsum(axis=-1)], -1)[(*idx, last)]
bnd[(*idx, last)] *= (A[1::2]-A[::2]).repeat(2)
return bnd[..., :-1].cumsum(axis=-1).swapaxes(-1, axis)
Using itertools.groupby:
import itertools
for i in range(b.shape[1]):
counts = []
for k,v in itertools.groupby(b[:,i]):
g = list(v)
counts.extend([sum(g)] * len(g))
b[:,i] = counts
Output:
array([[3, 6, 1, 6, 0, 1],
[3, 6, 0, 6, 5, 0],
[3, 6, 3, 6, 5, 2],
[0, 6, 3, 6, 5, 2],
[2, 6, 3, 6, 5, 0],
[2, 6, 0, 6, 5, 1]])
building on paulpanzer's answer for poor souls (like me) who dont have numpy v1.15+
def sum_stretches(a, axis=-1):
a = a.swapaxes(-1, axis)
padding = [[0,0].copy()]*a.ndim
padding[-1] = [1,1]
padded = np.pad((a!=0), padding, 'constant', constant_values=0).astype('int32')
bnd = np.diff(padded, axis=-1)
*idx, last = np.where(bnd)
A = np.concatenate([np.zeros((*a.shape[:-1], 1), 'int32'), a.cumsum(axis=-1)], -1)[(*idx, last)]
bnd[(*idx, last)] *= (A[1::2]-A[::2]).repeat(2)
return bnd[..., :-1].cumsum(axis=-1).swapaxes(-1, axis)
What I wanna process is slice 2D array partially without numpy module like following example with numpy.
and I want to know Time Complexity of Slicing Lists in python basic function
import numpy as np
A = np.array([ [1,2,3,4,5,6,7,8] for i in range(8)])
n = len(A[0])
x = int(n/2)
TEMP = [[None]*2 for i in range(2)]
for w in range(2):
for q in range(2):
TEMP[w][q] = A[w*x:w*x+x,q*x:q*x+x]
for w in range(2):
for q in range(2):
print(TEMP[w][q])
here is the result that i wanna get
[[1 2 3 4]
[1 2 3 4]
[1 2 3 4]
[1 2 3 4]]
[[5 6 7 8]
[5 6 7 8]
[5 6 7 8]
[5 6 7 8]]
[[1 2 3 4]
[1 2 3 4]
[1 2 3 4]
[1 2 3 4]]
[[5 6 7 8]
[5 6 7 8]
[5 6 7 8]
[5 6 7 8]]
Process finished with exit code 0
For the first question:
A = [ [1,2,3,4,5,6,7,8] for i in range(8)]
n = len(A[0])
x = int(n/2)
TEMP = [[None]*2 for i in range(2)]
for w in range(2):
for q in range(2):
TEMP[w][q] = [item[q * x:(q * x) + x] for item in A[w * x:(w * x) + x]]
for w in range(2):
for q in range(2):
print("{i}, {j}: {item}".format(i=w, j=q, item=repr(TEMP[w][q])))
Numpy makes the vertical slicing of 2 dimensional array easier. However, you can achieve the same results without it. Imagine if we have the following 2D list:
arr1=[[1,1,1,0,0,0],[0,1,0,0,0,0],[1,1,1,0,0,0],[0,0,2,4,4,0],[0,0,0,2,0,0],[0,0,1,2,4,0]]
which is represented as the following matrix:
[[1, 1, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0],
[0, 0, 2, 4, 4, 0],
[0, 0, 0, 2, 0, 0],
[0, 0, 1, 2, 4, 0]]
Let's say that you want to slice this to form the pattern below :
This can be achieved without numpy by the following :
for x in range (0,4):
for y in range (0,4):
# Here we traverse through the 2D array vertically
temp_matrix= arr1[x][y:y+3],arr1[x+1][y:y+3],arr1[x+2][y:y+3]
print (temp_matrix)
If we use numpy instead we can re-write the following code :
arr=np.array(arr1)
rows = arr.shape[0]
cols = arr.shape[1]
for x in range (0,rows-2):
for y in range (0, cols-2):
print(arr[x:x+3,y:y+3])
In the following I will give two examples that have different dimension values.
Lock-1
# numbers are the shown values on the so in this case: 0,1,2
numbers = 5
# fields are those things i can turn to change my combination
fields = 4
So what I would expect for all of my posibilities is
0 0 0 5
0 0 1 4
0 0 2 3
0 0 3 2
0 0 4 1
0 0 5 0
0 1 0 4
0 1 1 3
0 1 2 2
0 1 3 1
0 1 4 0
0 2 0 3
0 2 1 2
0 2 2 1
0 2 3 0
0 3 0 2
0 3 1 1
0 3 2 0
0 4 0 1
0 4 1 0
0 5 0 0
1 0 0 4
1 0 1 3
1 0 2 2
1 0 3 1
1 0 4 0
1 1 0 3
1 1 1 2
1 1 2 1
1 1 3 0
1 2 0 2
1 2 1 1
1 2 2 0
1 3 0 1
1 3 1 0
1 4 0 0
2 0 0 3
2 0 1 2
2 0 2 1
2 0 3 0
2 1 0 2
2 1 1 1
2 1 2 0
2 2 0 1
2 2 1 0
2 3 0 0
3 0 0 2
3 0 1 1
3 0 2 0
3 1 0 1
3 1 1 0
3 2 0 0
4 0 0 1
4 0 1 0
4 1 0 0
5 0 0 0
My second lock has the following values:
numbers = 3
values = 3
So what I would expect as my posibilities would look like this
0 0 3
0 1 2
0 2 1
0 3 0
1 0 2
1 1 1
1 2 0
2 0 1
2 1 0
3 0 0
I know this can be done with itertools.permutations and so on, but I want to generate the rows by building them and not by overloading my RAM. I figured out that the last 2 rows are always building up the same way.
So I wrote a funtion which builds it for me:
def posibilities(value):
all_pos = []
for y in range(value + 1):
posibility = []
posibility.append(y)
posibility.append(value)
all_pos.append(posibility)
value -= 1
return all_pos
Now I want some kind of way to fit the other values dynamically around my function, so e.g. Lock - 2 would now look like this:
0 posibilities(3)
1 posibilities(2)
2 posibilities(1)
3 posibilities(0)
I know I should use a while loops and so on, but I can't get the solution for dynamic values.
You could do this recursively, but it's generally best to avoid recursion in Python unless you really need it, eg, when processing recursive data structures (like trees). Recursion in standard Python (aka CPython) is not very efficient because it cannot do tail call elimination. Also, it applies a recursion limit (which is by default 1000 levels, but that can be modified by the user).
The sequences that you want to generate are known as weak compositions, and the Wikipedia article gives a simple algorithm which is easy to implement with the help of the standard itertools.combinations function.
#!/usr/bin/env python3
''' Generate the compositions of num of a given width
Algorithm from
https://en.wikipedia.org/wiki/Composition_%28combinatorics%29#Number_of_compositions
Written by PM 2Ring 2016.11.11
'''
from itertools import combinations
def compositions(num, width):
m = num + width - 1
last = (m,)
first = (-1,)
for t in combinations(range(m), width - 1):
yield [v - u - 1 for u, v in zip(first + t, t + last)]
# test
for t in compositions(5, 4):
print(t)
print('- ' * 20)
for t in compositions(3, 3):
print(t)
output
[0, 0, 0, 5]
[0, 0, 1, 4]
[0, 0, 2, 3]
[0, 0, 3, 2]
[0, 0, 4, 1]
[0, 0, 5, 0]
[0, 1, 0, 4]
[0, 1, 1, 3]
[0, 1, 2, 2]
[0, 1, 3, 1]
[0, 1, 4, 0]
[0, 2, 0, 3]
[0, 2, 1, 2]
[0, 2, 2, 1]
[0, 2, 3, 0]
[0, 3, 0, 2]
[0, 3, 1, 1]
[0, 3, 2, 0]
[0, 4, 0, 1]
[0, 4, 1, 0]
[0, 5, 0, 0]
[1, 0, 0, 4]
[1, 0, 1, 3]
[1, 0, 2, 2]
[1, 0, 3, 1]
[1, 0, 4, 0]
[1, 1, 0, 3]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3, 0]
[1, 2, 0, 2]
[1, 2, 1, 1]
[1, 2, 2, 0]
[1, 3, 0, 1]
[1, 3, 1, 0]
[1, 4, 0, 0]
[2, 0, 0, 3]
[2, 0, 1, 2]
[2, 0, 2, 1]
[2, 0, 3, 0]
[2, 1, 0, 2]
[2, 1, 1, 1]
[2, 1, 2, 0]
[2, 2, 0, 1]
[2, 2, 1, 0]
[2, 3, 0, 0]
[3, 0, 0, 2]
[3, 0, 1, 1]
[3, 0, 2, 0]
[3, 1, 0, 1]
[3, 1, 1, 0]
[3, 2, 0, 0]
[4, 0, 0, 1]
[4, 0, 1, 0]
[4, 1, 0, 0]
[5, 0, 0, 0]
- - - - - - - - - - - - - - - - - - - -
[0, 0, 3]
[0, 1, 2]
[0, 2, 1]
[0, 3, 0]
[1, 0, 2]
[1, 1, 1]
[1, 2, 0]
[2, 0, 1]
[2, 1, 0]
[3, 0, 0]
FWIW, the above code can generate the 170544 sequences of compositions(15, 8) in around 1.6 seconds on my old 2GHz 32bit machine, running on Python 3.6 or Python 2.6. (The timing information was obtained by using the Bash time command).
FWIW, here's a recursive version taken from this answer by user3736966. I've modified it to use the same argument names as my code, to use lists instead of tuples, and to be compatible with Python 3.
def compositions(num, width, parent=[]):
if width > 1:
for i in range(num, -1, -1):
yield from compositions(i, width - 1, parent + [num - i])
else:
yield parent + [num]
Somewhat surprisingly, this one is a little faster than the original version, clocking in at around 1.5 seconds for compositions(15, 8).
If your version of Python doesn't understand yield from, you can do this:
def compositions(num, width, parent=[]):
if width > 1:
for i in range(num, -1, -1):
for t in compositions(i, width - 1, parent + [num - i]):
yield t
else:
yield parent + [num]
To generate the compositions in descending order, simply reverse the range call, i.e. for i in range(num + 1):.
Finally, here's an unreadable one-line version. :)
def c(n, w, p=[]):
yield from(t for i in range(n,-1,-1)for t in c(i,w-1,p+[n-i]))if w-1 else[p+[n]]
Being an inveterate tinkerer, I couldn't stop myself from making yet another version. :) This is simply the original version combined with the code for combinations listed in the itertools docs. Of course, the real itertools.combinations is written in C so it runs faster than the roughly equivalent Python code shown in the docs.
def compositions(num, width):
r = width - 1
indices = list(range(r))
revrange = range(r-1, -1, -1)
first = [-1]
last = [num + r]
yield [0] * r + [num]
while True:
for i in revrange:
if indices[i] != i + num:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield [v - u - 1 for u, v in zip(first + indices, indices + last)]
This version is about 50% slower than the original at doing compositions(15, 8): it takes around 2.3 seconds on my machine.