0

'M' is a numpy ndarray, which dimension 'dim' number is variable (previously generated) but each dimension is of equal size 'size'. In my code it will be more like dim = 5, size = 7.

ex: (dim = 3,size = 4).

M = np.arange(size**dim).reshape((size,)*dim)

[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]
  [24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]
  [40 41 42 43]
  [44 45 46 47]]

 [[48 49 50 51]
  [52 53 54 55]
  [56 57 58 59]
  [60 61 62 63]]]

And I have a permutation generator of my own, 'per', that generates specific permutations (not random) of range(size).

print(next(per))
(1,0,3,2)

My need: transform M, by moving its elements according to as many permutations as I need. In the example: 21 (1 permutation for first dimension, 4 for second, 16 for third - generalised: size**d for d in range(dim) permutations). My permutations are not random, but they are independant, different from each other.

A result may be:

[[[36 39 37 38]
  [33 34 32 35]
  [46 44 45 47]]
  [41 43 40 42]
 [[9  10 11 8]
  [2  1  3  0]
  [6  7  5  4]
  [13 12 14 15]]
 [[56 59 57 58]
  [63 61 62 60]
  [53 54 52 55]
  [51 50 49 48]]
 [[28 30 29 31]
  [27 25 24 26]
  [17 18 16 19]
  [23 21 20 22]]]

How can I do it directly from M as numpy array, whith my code remaining dynamic?

2
  • What do you mean by "by moving its elements according to as many permutations as I need"? What is the exact relationship supposed to be between the input array, the output array, and the permutation(s?) used? Commented Jul 2, 2018 at 23:36
  • If you see my example, each line content has been permuted, but the lines in each 4*4 grid have been also, and the grid order also. All this needs to be done according to individual permutations (pertmuted index) from my generator. Commented Jul 2, 2018 at 23:49

2 Answers 2

1

This is an exercise in broadcasting:

>>> import numpy as np
>>> from itertools import islice
>>> 
>>> A = np.arange(27).reshape(3,3,3)
>>> def per(n):
...     while True:
...         yield np.random.permutation(n)
... 
>>> pg = per(3)
>>> 
>>> p0 = next(pg)[..., None, None]
>>> p1 = np.array([p for p in islice(pg, 3)])[..., None]
>>> p2 = np.array([[p for p in islice(pg, 3)] for _ in range(3)])
>>> 
>>> p0
array([[[2]],

       [[1]],

       [[0]]])
>>> p1
array([[[1],
        [0],
        [2]],

       [[1],
        [0],
        [2]],

       [[0],
        [2],
        [1]]])
>>> p2
array([[[1, 0, 2],
        [0, 2, 1],
        [0, 1, 2]],

       [[2, 1, 0],
        [1, 2, 0],
        [2, 1, 0]],

       [[1, 2, 0],
        [2, 1, 0],
        [2, 1, 0]]])
>>> A[p0, p1, p2]
array([[[22, 21, 23],
        [18, 20, 19],
        [24, 25, 26]],

       [[14, 13, 12],
        [10, 11,  9],
        [17, 16, 15]],

       [[ 1,  2,  0],
        [ 8,  7,  6],
        [ 5,  4,  3]]])

General soln:

import numpy as np
from itertools import islice

def per(n=None):
    while True:
        n = (yield n if n is None else np.random.permutation(n)) or n

def sweep(shp):
    pg = per()
    pg.send(None)
    redshp = len(shp)*[1]
    sz = 1
    for j, k in enumerate(shp):
        pg.send(k)
        redshp[j] = k
        yield np.reshape((*islice(pg, sz),), redshp)
        sz *= k

# example
a = np.arange(24).reshape((2,3,4))
idx = *sweep(a.shape),
for i in idx:
    print(i)
print(a[idx])
Sign up to request clarification or add additional context in comments.

2 Comments

As I'm new here, I would like to understand why my question is downvoted. Is there something wrong with it ?
@Cépagrave I can only guess - but some people here have very strong opinions on what a question should look like - look up "mcve" in the help section. If they suspect you to be lazy either in not trying hard enough yourself or in not making a good effort at explaining your problem, they get annoyed. For example, the line that user2357112 threw back at you---while I find it clear enough from context---some may find it a bit cavalier. But as I said, only guessing.
0

Thanks to Paul Panzer's brilliant answers, I managed to solve this question. Paul's last answer is great and totally generalized (even with non-square matrixes!). My initial question was a little less general, as my goal was to have my all-dimensions permutation working for square matrices. I simplified and shortened the code, so I'm sharing it here:

import numpy as np
from itertools import islice,count

size,dim = 4,3

per = (np.random.permutation(size) for _ in count())
idx = *(np.reshape((*islice(per, size**d),),[size]*(d+1)+[1]*(dim-d-1)) for d in range(dim)),

a = np.arange(size**dim).reshape((size,)*dim)
print(a[idx])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.