solve() will sometimes produce an undesirable result when the matrix is singular but the determinant is extremely close but not equal to 0.
> a <- cov(model.matrix(~ as.factor(gear) + 0, data = mtcars))
> a[1] <- a[1] + 1e-10
> det(a)
[1] 2.926638e-12
> det(a) == 0
[1] FALSE
> all.equal(det(a), 0)
[1] TRUE
> solve(a)
as.factor(gear)3 as.factor(gear)4 as.factor(gear)5
as.factor(gear)3 1e+10 1e+10 1e+10
as.factor(gear)4 1e+10 1e+10 1e+10
as.factor(gear)5 1e+10 1e+10 1e+10
Our generalized inverse code produces a more sensible inverse:
> s <- svd(a)
> nz <- (s$d > sqrt(.Machine$double.eps) * s$d[1])
> s$v[, nz] %*% (t(s$u[, nz])/s$d[nz])
[,1] [,2] [,3]
[1,] 1.8944444 -0.3444444 -1.550000
[2,] -0.3444444 2.0666667 -1.722222
[3,] -1.5500000 -1.7222222 3.272222
This is related to #230 in the sense that the issue in 230 arose when an externally calculated distance matrix had extreme values due to this bug, however this is a separate concern as this happens internally.
Fix is to drop down to generalized inverse if either solve() errors OR the determinant is "close" to 0. I have a rough solution coded up but don't really have time right now to finish testing and polishing.
How to determine close to 0? .Machine$double.eps is 2e-16 on my macs, but that feels too small. MatchIt will be using 1e-8 for their threshold in their Mahalanobis calculation. I'm tempted to go even higher like 1e4 (adjusting the nz calculation as well) - is there a big downside to carrying out the generalized inverse in situations like this?
solve()will sometimes produce an undesirable result when the matrix is singular but the determinant is extremely close but not equal to 0.Our generalized inverse code produces a more sensible inverse:
This is related to #230 in the sense that the issue in 230 arose when an externally calculated distance matrix had extreme values due to this bug, however this is a separate concern as this happens internally.
Fix is to drop down to generalized inverse if either
solve()errors OR the determinant is "close" to 0. I have a rough solution coded up but don't really have time right now to finish testing and polishing.How to determine close to 0?
.Machine$double.epsis 2e-16 on my macs, but that feels too small. MatchIt will be using 1e-8 for their threshold in their Mahalanobis calculation. I'm tempted to go even higher like 1e4 (adjusting thenzcalculation as well) - is there a big downside to carrying out the generalized inverse in situations like this?