aaa
aaa

Reputation: 251

Generate permutation matrix from permutation vector

Say I have a permutation vector (row permutation)

x <- c(1,2,3,4,7,8,5,6,9,10) # I exchanged 7 with 5 and 8 with 6.

Is there any function in R that can generate the corresponding permutation matrix from permutation vector? If so, please give me a example.

Upvotes: 1

Views: 3281

Answers (3)

antonio
antonio

Reputation: 11150

This what one can simply do in base R (no packages).

Let's start to set some matrix to permute.

# Let us assume your nxn-matrix is
n <- 3
(M <- matrix(as.numeric(1:(n*n)), n))
#     [,1] [,2] [,3]
#[1,]    1    4    7
#[2,]    2    5    8
#[3,]    3    6    9

For a single permutation matrix, based on a random vector permutation (pivot), we have:

## To generate the permutation matrix associated to a random 1:n permutation:
vperm <- sample(1:n)
(mperm <- Reduce(\(m,i) `[[<-`(m, i, vperm[i], 1), 1:n, matrix(0, n, n)))
#     [,1] [,2] [,3]
#[1,]    0    1    0
#[2,]    1    0    0
#[3,]    0    0    1

## To permute the columns of M:
t(mperm) %*% M
#     [,1] [,2] [,3]
#[1,]    2    5    8
#[2,]    1    4    7
#[3,]    3    6    9


## And, to permute the rows of M:
M  %*%  mperm
#     [,1] [,2] [,3]
#[1,]    4    1    7
#[2,]    5    2    8
#[3,]    6    3    9

Now, we generate all possible pivot vectors and the related permutation matrices

## To generate all possible random 1:n permutations:
vdisps <- expand.grid(rep(list(1:n), n))  # with repetitions
vperms <- Filter(\(v) length(unique(t(v))) == n, split(vdisps, 1:n^n))

## To generate the permutation matrices associated to each random permutation:
mperms <- lapply(vperms, \(permdf)
       Reduce(\(m,i) `[[<-`(m, i, permdf[[i]], 1), 1:n, matrix(0, n, n)))

## The related list of column-permutated matrices are
lapply(mperms, \(P) t(P) %*% M)

Of course, this is R, so we can use its subsetting features.

## Given 
oo <- order(vperm) #,

## we can replace t(mperm) %*% M with:
identical(t(mperm) %*% M,  M[oo, ]) # TRUE
identical(M %*% mperm,  M[, oo]) # TRUE

This is what is suggested to do when using the Cholesky decomposition with chol(..., pivot = TRUE).

NB as.numeric() is important, when generating M, to have identical() to work.

Upvotes: 0

akrun
akrun

Reputation: 887901

This could also be done with sparseMatrix

library(Matrix)
m1 <- sparseMatrix(seq_along(v1), v1, x=1)

We can coerce it to matrix with as.matrix

as.matrix(m1)

data

v1 <- c(1,2,3,4,7,8,5,6,9,10)

Upvotes: 3

josliber
josliber

Reputation: 44340

I believe this can be done by reordering the rows of the identity matrix:

x <- c(1,2,3,4,7,8,5,6,9,10)
diag(length(x))[x,]
#       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#  [1,]    1    0    0    0    0    0    0    0    0     0
#  [2,]    0    1    0    0    0    0    0    0    0     0
#  [3,]    0    0    1    0    0    0    0    0    0     0
#  [4,]    0    0    0    1    0    0    0    0    0     0
#  [5,]    0    0    0    0    0    0    1    0    0     0
#  [6,]    0    0    0    0    0    0    0    1    0     0
#  [7,]    0    0    0    0    1    0    0    0    0     0
#  [8,]    0    0    0    0    0    1    0    0    0     0
#  [9,]    0    0    0    0    0    0    0    0    1     0
# [10,]    0    0    0    0    0    0    0    0    0     1

Upvotes: 3

Related Questions