Here, one approach using NumPy strides
mostly complements the remaining elements, and then strides
helps us in creating this offset version quite efficiently -
def strided_method(ar):
a = np.concatenate(( ar, ar[:-1] ))
L = len(ar)
n = a.strides[0]
return np.lib.stride_tricks.as_strided(a[L-1:], (L,L), (-n,n))
-
In [42]: ar = np.array([1, 2, 3, 4])
In [43]: strided_method(ar)
Out[43]:
array([[4, 1, 2, 3],
[3, 4, 1, 2],
[2, 3, 4, 1],
[1, 2, 3, 4]])
In [44]: ar = np.array([4,9,3,6,1,2])
In [45]: strided_method(ar)
Out[45]:
array([[2, 4, 9, 3, 6, 1],
[1, 2, 4, 9, 3, 6],
[6, 1, 2, 4, 9, 3],
[3, 6, 1, 2, 4, 9],
[9, 3, 6, 1, 2, 4],
[4, 9, 3, 6, 1, 2]])
-
In [5]: a = np.random.randint(0,9,(1000))
In [6]: %timeit roll_matrix(a)
100 loops, best of 3: 3.39 ms per loop
In [8]: %timeit circulant(a[::-1])
100 loops, best of 3: 2.03 ms per loop
In [18]: %timeit strided_method(a)
100000 loops, best of 3: 6.7 µs per loop
( , ) strides
-
In [19]: %timeit strided_method(a).copy()
1000 loops, best of 3: 381 µs per loop