4
x = [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9]]

Rotation by 1 unit should give:

x = [[4, 1, 2],
     [7, 5, 3],
     [8, 9, 6]]

Basically, I want to shift each circular layer in the array by 'n' units.

I looked at numpy.roll but couldn't figure out to use it for this use case. I cannot use image rotation routines like scipy.ndimage.interpolation.rotate as they change the shape and not quite achieve the desired result.

Edit:

For the 4 X 4 matrix:

x = [[a, b, c, d],
     [e, f, g, h],
     [i, j, k, l],
     [m, n, o, p]]

Rotation by 1 unit should give:

x = [[e, a, b, c],
     [i, j, f, d],
     [m, k, g, h],
     [n, o, p, l]]

Edit:

Adding some clarifications on how this works for arbitrary sizes.

For a N X N matrix rotated by 1 unit, the outer 'ring' is first shifted by 1. Same logic is followed the remaining 'inner' (N-2) X (N-2) matrix recursively.

8
  • 2
    I'm not familiar with numpy but should an array rotation affect the elements within it? Because you have 9 in the original array but not in the rotated version. I'm genuinely not sure, just asking in case it might be a mistake. Commented Jan 6, 2017 at 9:26
  • 2
    Could you show a sample case for 4x4 array as well? Commented Jan 6, 2017 at 9:27
  • Can you check your result? Is it supposed to be [[4, 1, 2], [7, 5, 3], [8, 9, 6]]? Because right now, I can't make sense out of it... Commented Jan 6, 2017 at 9:33
  • You're right. Not sure how i messed up. fixed. Commented Jan 6, 2017 at 9:56
  • Edited to add example for 4 X 4 case Commented Jan 6, 2017 at 10:02

3 Answers 3

3

Here's an approach assuming you are looking to rotate such that the amount of shift is constant across slices, where by slice we mean the outermost layer of elements directed outwards from the center -

def outer_slice(x):
    return np.r_[x[0],x[1:-1,-1],x[-1,:0:-1],x[-1:0:-1,0]]

def rotate_steps(x, shift):
    out = np.empty_like(x)
    N = x.shape[0]
    idx = np.arange(x.size).reshape(x.shape)
    for n in range((N+1)//2):
        sliced_idx = outer_slice(idx[n:N-n,n:N-n])
        out.ravel()[sliced_idx] = np.roll(np.take(x,sliced_idx), shift)
    return out

Sample runs

Case #1 (3 x 3 array) :

In [444]: x
Out[444]: 
array([[24, 85, 97],
       [51, 33, 11],
       [86, 38, 33]])

In [445]: rotate_steps(x,shift=1)
Out[445]: 
array([[51, 24, 85],
       [86, 33, 97],
       [38, 33, 11]])

Case #2 (4 x 4 array) :

In [447]: x
Out[447]: 
array([[11, 70, 28, 13],
       [44, 41, 17, 82],
       [47, 32, 89, 25],
       [32, 20, 67, 98]])

In [448]: rotate_steps(x,shift=1)
Out[448]: 
array([[44, 11, 70, 28],
       [47, 32, 41, 13],
       [32, 89, 17, 82],
       [20, 67, 98, 25]])

In [449]: rotate_steps(x,shift=2)
Out[449]: 
array([[47, 44, 11, 70],
       [32, 89, 32, 28],
       [20, 17, 41, 13],
       [67, 98, 25, 82]])
Sign up to request clarification or add additional context in comments.

Comments

1

For a 3x3 array, you can accomplish this with np.roll and ndarray.flat:

>>> x = np.arange(1, 10).reshape((3, 3))
>>> x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> i = np.array([0, 1, 2, 5, 8, 7, 6, 3])  # Indices in circular order
>>> x.flat[i]
array([1, 2, 3, 6, 9, 8, 7, 4])

Rotate by 1 unit:

>>> x.flat[i] = np.roll(x.flat[i], 1)  # Rotate indices and reassign
>>> x
array([[4, 1, 2],
       [7, 5, 3],
       [8, 9, 6]])

Rotate by 4 units:

>>> x.flat[i] = np.roll(x.flat[i], 4)
>>> x
array([[9, 8, 7],
       [6, 5, 4],
       [3, 2, 1]])

For the 4x4 case, I still need some clarity on whether each "circle" needs to be rotated at different "speeds" according to their length...

1 Comment

This is an interesting approach.
1

You're applying a permutation on the matrix. Permutations are usually represented by vectors, (i-->p[i]), and applied on vectors. You can represent a permutation of a matrix in a matrix if you want, the permutation will be a matrix of pairs, so that the element at (i,j) moves to m[i,j] .

Once you build the matrix, it's just a matter of a simple loop to apply the permutation.

1 Comment

I believe this was @Praveen idea too.

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.