Task
I want to be able to generate the permutation matrix which divides a 1D array of consecutive numbers (i.e. even, odd, even, odd, even, odd, …) into a 1D array where the first half is the same and the second half is the rating. So (pair1, odd1, pair2, odd2, pair3, odd3) goes to (pair1, pair2, pair3, odd1, odd2, odd3).
For example, with N = 6, the permutation matrix would be:
M = array((1, 0, 0, 0, 0, 0),
(0, 0, 1, 0, 0, 0),
(0, 0, 0, 0, 1, 0),
(0, 1, 0, 0, 0, 0),
(0, 0, 0, 1, 0, 0),
(0, 0, 0, 0, 0, 1))
You can verify that by multiplying this by M * array((0, 1, 2, 3, 4, 5)) = array((0, 2, 4, 1, 3, 5))
.
My pseudocode approach
(Full code below.) Here's the mathematically correct way to generate this:
I = NxN identity matrix
for i in (0:N1):
if i < N/2:
shift the 1 in row i by 2*i to the right
if i >= N/2:
shift the 1 in row i by 2*(i  N/2)+1 to the right
You can see how it works to generate M above.
Code (Python)
I am implementing the above pseudocode using the numpy array manipulation (this code can be copied and pasted):
import numpy as np
def permutation_matrix(N):
N_half = int(N/2) #This is done in order to not repeatedly do int(N/2) on each array slice
I = np.identity(N)
I_even, I_odd = I(:N_half), I(N_half:) #Split the identity matrix into the top and bottom half, since they have different shifting formulas
#Loop through the row indices
for i in range(N_half):
# Apply method to the first half
i_even = 2 * i #Set up the new (shifted) index for the 1 in the row
zeros_even = np.zeros(N) #Create a zeros array (will become the new row)
zeros_even(i_even) = 1. #Put the 1 in the new location
I_even(i) = zeros_even #Replace the row in the array with our new, shifted, row
# Apply method to the second half
i_odd = (2 * (i  N_half)) + 1
zeros_odd = np.zeros(N)
zeros_odd(i_odd) = 1.
I_odd(i) = zeros_odd
M = np.concatenate((I_even, I_odd), axis=0)
return M
N = 8
M = permutation_matrix(N)
print(M)
Output:
array(((1., 0., 0., 0., 0., 0., 0., 0.),
(0., 0., 1., 0., 0., 0., 0., 0.),
(0., 0., 0., 0., 1., 0., 0., 0.),
(0., 0., 0., 0., 0., 0., 1., 0.),
(0., 1., 0., 0., 0., 0., 0., 0.),
(0., 0., 0., 1., 0., 0., 0., 0.),
(0., 0., 0., 0., 0., 1., 0., 0.),
(0., 0., 0., 0., 0., 0., 0., 1.)))
My problems
I have a feeling that there are more effective ways to do this. To summarize what I do for each matrix:

Loop through the rows

In each row, identify where the 1
must be moved to, call it idx

Create a separate zero array and insert a 1
in the index idx

Replace the row we are evaluating with our modified zero array
Is it necessary to divide the table in half?
Is there a Pythonic way to implement two different functions on two halves of the same array without dividing them?
Is there an approach where I can move the 1s without needing to create a separate array of zeros in memory?
Do I even have to run the lines?
Are there more efficient libraries than numpy
for that?