Search code examples
rmatrixmatrix-multiplicationmatrix-inverse

create a random non-singular matrix reliably


How can I create a matrix of pseudo-random values that is guaranteed to be non-singular? I tried the code below, but it failed. I suppose I could just loop until I got one by chance but I would prefer a more elegant "R-like" solution if anyone has an idea.

library(matrixcalc)
exampledf<- matrix(ceiling(runif(16,0,50)), ncol=4)
is.singular.matrix(exampledf) #this may or may not return false

using a while loop:

exampledf<-NULL
library(matrixcalc)
while(is.singular.matrix(exampledf)!=TRUE){
  exampledf<- matrix(ceiling(runif(16,0,50)), ncol=4)
}

Solution

  • It should be fairly unlikely that this will produce a singular matrix:

     Mat1 <- matrix(rnorm(100), ncol=4)
     Mat2 <- matrix(rnorm(100), ncol=4)
    
     crossprod(Mat1,Mat2)
            [,1]   [,2]   [,3]   [,4]
    [1,]  0.8138  5.112  2.945 -5.003
    [2,]  4.9755 -2.420  1.801 -4.188
    [3,] -3.8579  8.791 -2.594  3.340
    [4,]  7.2057  6.426  2.663 -1.235
    
     solve( crossprod(Mat1,Mat2) )
             [,1]     [,2]     [,3]    [,4]
    [1,] -0.11273  0.15811  0.05616 0.07241
    [2,]  0.03387  0.01187  0.07626 0.02881
    [3,]  0.19007 -0.60377 -0.40665 0.17771
    [4,] -0.07174 -0.31751 -0.15228 0.14582
    
    
    
    inv1000 <- replicate(1000, {
                      Mat1 <- matrix(rnorm(100), ncol=4)
                      Mat2 <- matrix(rnorm(100), ncol=4)
                      try(solve( crossprod(Mat1,Mat2)))} )
     str(inv1000)
    #num [1:4, 1:4, 1:1000] 0.1163 0.0328 0.3424 -0.227 0.0347 ...
     max(inv1000)
    #[1] 451.6
    
    > inv100000 <- replicate(100000, {Mat1 <- matrix(rnorm(100), ncol=4)
    +  Mat2 <- matrix(rnorm(100), ncol=4)
    + is.singular.matrix( crossprod(Mat1,Mat2))} )
    > sum(inv100000)
    [1] 0