R ginv and Matlab pinv produce different results - r

ginv() function from MASS package in R produce totally different values compared to MATLAB pinv() function. They both claim to produce Moore-Penrose generalized inverse of a matrix.
I tried to set the same tolerance for the R implementation but the difference persists.
MATLAB default tol : max(size(A)) * norm(A) * eps(class(A))
R default tol : sqrt(.Machine$double.eps)
Reproduction:
R:
library(MASS)
A <- matrix(c(47,94032,149, 94032, 217179406,313679,149,313679,499),3,3)
ginv(A)
outputs:
[,1] [,2] [,3]
[1,] 1.675667e-03 -8.735203e-06 5.545605e-03
[2,] -8.735203e-06 5.014084e-08 -2.890907e-05
[3,] 5.545605e-03 -2.890907e-05 1.835313e-02
svd(A)
outputs:
$d
[1] 2.171799e+08 4.992800e+01 2.302544e+00
$u
[,1] [,2] [,3]
[1,] -0.0004329688 0.289245088 -9.572550e-01
[2,] -0.9999988632 -0.001507826 -3.304234e-06
[3,] -0.0014443299 0.957253888 2.892454e-01
$v
[,1] [,2] [,3]
[1,] -0.0004329688 0.289245088 -9.572550e-01
[2,] -0.9999988632 -0.001507826 -3.304234e-06
[3,] -0.0014443299 0.957253888 2.892454e-01
MATLAB:
A = [47 94032 149; 94032 217179406 313679; 149 313679 499]
pinv(A)
outputs:
ans =
0.3996 -0.0000 -0.1147
-0.0000 0.0000 -0.0000
-0.1147 -0.0000 0.0547
svd:
[U, S, V] = svd(A)
U =
-0.0004 0.2892 -0.9573
-1.0000 -0.0015 -0.0000
-0.0014 0.9573 0.2892
S =
1.0e+008 *
2.1718 0 0
0 0.0000 0
0 0 0.0000
V =
-0.0004 0.2892 -0.9573
-1.0000 -0.0015 -0.0000
-0.0014 0.9573 0.2892
Solution:
to make R ginv like MATLAB pinv use this function:
#' Pseudo-Inverse of Matrix
#' #description
#' This is the modified version of ginv function in MASS package.
#' It produces MATLAB like pseudo-inverse of a matrix
#' #param X The matrix to compute the pseudo-inverse
#' #param tol The default is the same as MATLAB pinv function
#'
#' #return The pseudo inverse of the matrix
#' #export
#'
#' #examples
#' A <- matrix(1:6,3,2)
#' pinv(A)
pinv <- function (X, tol = max(dim(X)) * max(X) * .Machine$double.eps)
{
if (length(dim(X)) > 2L || !(is.numeric(X) || is.complex(X)))
stop("'X' must be a numeric or complex matrix")
if (!is.matrix(X))
X <- as.matrix(X)
Xsvd <- svd(X)
if (is.complex(X))
Xsvd$u <- Conj(Xsvd$u)
Positive <- any(Xsvd$d > max(tol * Xsvd$d[1L], 0))
if (Positive)
Xsvd$v %*% (1 / Xsvd$d * t(Xsvd$u))
else
array(0, dim(X)[2L:1L])
}

Running debugonce(MASS::ginv), we see that the difference lies in what is done with the singular value decomposition.
Specifically, R checks the following:
Xsvd <- svd(A)
Positive <- Xsvd$d > max(tol * Xsvd$d[1L], 0)
Positive
# [1] TRUE TRUE FALSE
If the third element were true (which we can force by setting tol = 0, as suggested by #nicola), MASS::ginv would return:
Xsvd$v %*% (1/Xsvd$d * t(Xsvd$u))
# [,1] [,2] [,3]
# [1,] 3.996430e-01 -7.361507e-06 -1.147047e-01
# [2,] -7.361507e-06 5.014558e-08 -2.932415e-05
# [3,] -1.147047e-01 -2.932415e-05 5.468812e-02
(i.e., the same as MATLAB).
Instead, it returns:
Xsvd$v[, Positive, drop = FALSE] %*% ((1/Xsvd$d[Positive]) *
t(Xsvd$u[, Positive, drop = FALSE]))
# [,1] [,2] [,3]
# [1,] 1.675667e-03 -8.735203e-06 5.545605e-03
# [2,] -8.735203e-06 5.014084e-08 -2.890907e-05
# [3,] 5.545605e-03 -2.890907e-05 1.835313e-02
Thanks to #FaridCher for pointing out the source code of pinv.
I'm not sure I 100% understand the MATLAB code, but I think it comes down to a difference in how tol is used. The MATLAB correspondence to Positive in R is:
`r = sum(s>tol)`
Where tol is what's supplied by the user; if none is supplied, we get:
m = 0;
% I don't get the point of this for loop -- why not just `m = max(size(A))`?
for i = 1:n
m = max(m,length(A(:,i)));
end
% contrast with simply `tol * Xsvd$d[1L]` in R
% (note: i believe the elements of d are sorted largest to smallest)
tol = m*eps(max(s));

Related

Incorrect answer from Monte Carlo integration

How can I approximate the integral of [x^4 * sin(x)]/ [exp(1)^(x/5)] (0 to +Inf) with Monte Carlo method in R?
What I tried to do is
set.seed(666)
func1 <- function(x)
{
(x^4 * sin(x))/exp(1)^(x/5)
}
n <- 1000000
x <- rexp(n, 0.2)
f <- func1(x)
E <- mean(f)
but the result of E is not right
If you're going to sample from exponential, it shouldn't be used again in the function.
From code
set.seed(32345)
func <- function(x) { (x^4 * sin(x)) }
n <- 10000000
x <- rexp(n, 0.2)
f <- func(x)
E <- mean(f)
I'm getting the answer
[1] 13.06643
UPDATE
It fluctuates, and fluctuates badly.
Lest first start with the right answer which according to Mathematica is equal to
4453125/371293 = 11.9936.
I transformed integral from
I = ∫ dx exp(-x/5) x4 sin(x)
using substitution y=x/5 to
I = 55 Γ(5) ∫ dy exp(-y) y5-1 / Γ(5) sin(5*y)
Everything but sin(5*y) is normalized gamma distribution, which we will use to sample, and sin(5*y) will be our function to compute mean value.
And used following trick together with large number of samples: I split calculation of positive values and negative values. It helps if you have fluctuating answer with values canceling each other. I did calculation in batches as well. Gamma function of 5 is just 4! (factorial)
Code
set.seed(32345)
N <- 10000000 # number of samples per batch
NN <- 640 # number of batches
pos <- rep(0, NN) # positive values
neg <- rep(0, NN) # negative values
for(k in 1:NN) { # loop over batches
y <- rgamma(N, shape=5, scale=1)
f <- sin(5.0 * y)
pnf <- ifelse(f > 0.0, f, 0.0)
pos[k] <- mean(pnf)
pnf <- ifelse(f < 0.0, -f, 0.0)
neg[k] <- mean(pnf)
print(k)
}
mean(pos)
sd(pos)/sqrt(NN)
mean(neg)
sd(neg)/sqrt(NN)
5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))
Output
> mean(pos)
[1] 0.3183912
> sd(pos)/sqrt(NN)
[1] 4.749269e-06
>
> mean(neg)
[1] 0.3182223
> sd(neg)/sqrt(NN)
[1] 5.087734e-06
>
> 5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))
[1] 12.67078
You could see that we really compute difference of two very close values, this is why it is hard to get convergence. It took a bit over 20 minutes to compute on my Xeon workstation.
And with different seed=12345
> mean(pos)
[1] 0.3183917
> sd(pos)/sqrt(NN)
[1] 4.835424e-06
>
> mean(neg)
[1] 0.3182268
> sd(neg)/sqrt(NN)
[1] 4.633129e-06
>
> 5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))
[1] 12.36735
In the following I deliberately don't set a random seed.
As I mentioned in my comments, there are at least two introductory Q & A on Monte Carlo integration on Stack Overflow:
Wrong result when doing simple Monte Carlo integration in R
Monte Carlo integration using importance sampling given a proposal function
Both explained how to get Monte Carlo estimate, but forgot about the standard error of the estimate. It just turns out that Monte Carlo estimation has extremely slow convergence rate on your function.
It is commonly known that Monte Carlo integration has an O(1 / sqrt(N)) convergence rate, where N is the sample size and O() is the big O notation. However, the constant behind that big O can be very large for some functions, so the realistic convergence rate may be much much slower.
Your functions could be defined in at least two ways:
## direct definition
f <- function (x) x^4 * sin(x) * exp(-x/5)
## using gamma distribution; see ?rgamma
g <- function (x) sin(x) * 5 ^ 5 * gamma(5) * dgamma(x, 5, 1/5)
curve(f, from = 0, to = 100)
curve(g, add = TRUE, col = 2)
The 1st Q & A explained how to compute Monte Carlo integration using uniformly distributed samples. Your function f or g is almost zero beyond x = 200, so integration on [0, +Inf) is effectively on [0, 200]. The following function would return you the integration and its standard error:
MCI1 <- function (n) {
x <- runif(n, 0, 200)
y <- 200 * f(x)
c(mean.default(y), sqrt(var(y) / n))
}
Another way is via importance sampling, as explained in the 2nd Q & A. Here gamma distribution is used as proposal distribution (as Ben Bolker suggested).
MCI2 <- function (n) {
x <- rgamma(n, 5, 0.2)
y <- sin(x) * 75000
c(mean.default(y), sqrt(var(y) / n))
}
Now let's check the convergence rate.
n <- seq(1000, by = 5000, length = 100)
tail(n)
#[1] 471000 476000 481000 486000 491000 496000
b1 <- sapply(n, MCI1)
b2 <- sapply(n, MCI2)
For uniform sampling, we have
par(mfrow = c(1, 2))
plot(b1[1, ], main = "estimate")
plot(b1[2, ], main = "standard error")
b1[, (ncol(b1) - 5):ncol(b1)]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 115.1243 239.9631 55.57149 -325.8631 -140.3745 78.61126
#[2,] 181.0025 179.9988 178.99367 178.2152 177.2193 175.31446
For gamma sampling, we have
par(mfrow = c(1, 2))
plot(b2[1, ], main = "estimate")
plot(b2[2, ], main = "standard error")
b2[, (ncol(b2) - 5):ncol(b2)]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] -100.70344 -150.71536 24.40841 -49.58032 169.85385 122.81731
#[2,] 77.22445 76.85013 76.53198 76.03692 75.69819 75.25755
Whatever method it is, note how big the standard error is (compared with the estimate itself), and how slow it reduces.
It is much easier to use numerical integration (not surprising for integrating univariate functions):
integrate(f, 0, 200)
#11.99356 with absolute error < 0.0012
## trapezoidal rule
200 * mean.default(f(seq(0, 200, length = 10000)))
#[1] 11.99236
In the trapezoidal rule, even if only 1e+4 evenly spaced sampling points are taken, the integration is close enough to the truth.
Remark
Monte Carlo integration would have a less struggle if we do integration on a more restricted domain. From the figure of f or g, we see that this is an oscillating function. And actually, it crosses x-axis with a period of pi. Let's consider an integration on [lower, upper].
MCI3 <- function (n, lower, upper) {
x <- runif(n, lower, upper)
y <- (upper - lower) * f(x)
c(mean.default(y), sqrt(var(y) / n))
}
a1 <- sapply(n, MCI3, lower = 0, upper = pi)
a2 <- sapply(n, MCI3, lower = pi, upper = 2 * pi)
a3 <- sapply(n, MCI3, lower = 2 * pi, upper = 3 * pi)
a4 <- sapply(n, MCI3, lower = 3 * pi, upper = 4 * pi)
a1[, (ncol(a1) - 5):ncol(a1)]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 17.04658711 16.97935808 17.01094302 17.02117843 16.96935285 16.99552898
#[2,] 0.02407643 0.02390894 0.02379678 0.02368683 0.02354298 0.02342799
a2[, (ncol(a2) - 5):ncol(a2)]
# [,1] [,2] [,3] [,4] [,5]
#[1,] -406.5646843 -404.9633321 -405.4300941 -405.4799659 -405.8337416
#[2,] 0.3476975 0.3463621 0.3442497 0.3425202 0.3409073
# [,6]
#[1,] -405.8628741
#[2,] 0.3390045
a3[, (ncol(a3) - 5):ncol(a3)]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1591.539911 1592.280780 1594.307951 1591.375340 1593.171500 1591.648529
#[2,] 1.197469 1.190251 1.183095 1.177079 1.172049 1.165667
a4[, (ncol(a4) - 5):ncol(a4)]
# [,1] [,2] [,3] [,4] [,5]
#[1,] -3235.561677 -3239.147235 -3241.532097 -3238.421556 -3238.667702
#[2,] 2.336684 2.321283 2.311647 2.300856 2.286624
# [,6]
#[1,] -3237.043068
#[2,] 2.279032

R: How to sample from the geometric space outside a 4D hyper ellipse?

Original title (in-precise): How to find all vectors that satisfy a 4-unknown non-linear inequalities?
The question is to find a space C, so that any 4x1 vector x in C satisfies:
t(x) %*% t(Q) %*% Q %*% x > a,
in which Q is a 100 x 4 matrix I already know, and a is a positive constant.
I tried to find the solution from packages such as ellipse, rootSolve, and bvpSolve. But I can't reach a suitable solution.
Any idea or solution will be sincerely appreciated.
Remark: the algorithm below can be used to sample from the surface / manifold of a 4D hyper ellipse, or its inner space, too.
I have changed your question title. It is impossible to list all solutions, although such space has simple mathematical representation. We can at our best sample from such space.
Transformation from Ellipse to Sphere
Here is some mathematics based on Cholesky factorization. Alternatively, consider symmetric Eigen decomposition, and I have a demonstration / comparison between these two at Obtain vertices of the ellipse on an ellipse covariance plot (created by car::ellipse), with nice figures for the geometry.
Since Q is known, R is known. The following R code gets R:
R <- chol(crossprod(Q))
y is from the hypersphere with radius greater than sqrt(a). If we can sample y from such space, we can then map it to x by solving a triangular system:
x <- backsolve(R, y)
Sampling of y
We can use n-sphere coordinates to parametrize such space. For 4D space, we have:
The following R function samples n y-vectors from such space. Because of finite representation of floating point numbers, we can't have infinity radius but .Machine$double.xmax at the best. But we also use an optional argument rmax, if we want a more restricted radius.
ry <- function (n, rmin, rmax = NA) {
if (is.na(rmax)) rmax <- .Machine$double.xmax
if (rmin > rmax) stop("larger `rmax` expected!")
r <- runif(n, rmin, rmax)
phi1 <- runif(n, 0, pi)
phi2 <- runif(n, 0, 2 * pi)
phi3 <- runif(n, 0, 2 * pi)
matrix(c(r * cos(phi1),
r * sin(phi1) * cos(phi2),
r * sin(phi1) * sin(phi2) * cos(phi3),
r * sin(phi1) * sin(phi2) * sin(phi3)),
nrow = 4L, byrow = TRUE, dimnames = list(paste0("y", 1:4), NULL))
}
Try some examples:
## radius between 4 and 10
set.seed(0); ry(5, 4, 10)
# [,1] [,2] [,3] [,4] [,5]
#y1 7.5594886 -5.31049687 -6.1388372 -3.5991830 -3.728597
#y2 5.1402945 0.47936481 0.4799181 -2.5085948 -6.480402
#y3 0.2614002 -1.68833263 -0.1950092 -5.9975328 -4.213166
#y4 -2.0859078 0.02440839 -0.9452077 0.3052708 3.954674
## radius between 4 and "inf"
set.seed(0); ry(5, 4)
# [,1] [,2] [,3] [,4] [,5]
#y1 1.299100e+308 -4.531902e+307 -6.588856e+307 -4.983772e+307 -6.442420e+307
#y2 8.833607e+307 4.090831e+306 5.150993e+306 -3.473640e+307 -1.119710e+308
#y3 4.492167e+306 -1.440799e+307 -2.093047e+306 -8.304756e+307 -7.279678e+307
#y4 -3.584637e+307 2.082977e+305 -1.014498e+307 4.227070e+306 6.833046e+307
I have chosen to use each column than each row as a sample, to make matrix computation easier later.
Transforming y to x
Now assume we have
set.seed(0); Q <- matrix(runif(10 * 4), 10L, 4L)
We get R
R <- chol(crossprod(Q))
# [,1] [,2] [,3] [,4]
#[1,] 2.176848 1.420882 1.2517326 1.4481875
#[2,] 0.000000 1.077816 0.1045581 0.4646328
#[3,] 0.000000 0.000000 1.2284251 0.3961126
#[4,] 0.000000 0.000000 0.0000000 0.9019771
Suppose you have a = 4, then we map y to x:
a <- 4
set.seed(0); y <- ry(5, sqrt(a), 10) ## we set an `rmax` here
x <- backsolve(R, y) ## each column is a sample of `x`
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.7403534 -1.49866534 -2.2359350 2.0269516 2.948561
#[2,] 5.5481682 0.41827601 0.7024109 -1.7606720 -7.288339
#[3,] 0.9373905 -1.01984708 0.1430660 -4.4180688 -4.749419
#[4,] -2.2616584 0.01995357 -0.8367956 0.2995693 4.299268
Checking
We can check that the above x does satisfy our requirement.
z <- Q %*% x
ax <- colSums(x ^ 2) ## value of `diag(x'Q'Qx)`
#[1] 84.15453 17.00795 24.77044 43.33361 85.85250
They are all greater than 4.

Euclidean distance between data sets in R using rdist from "fields" package

I am using rdist to compute Euclidean distances between a matrix and itself:
> m = matrix(c(1,1,1,2,2,2,3,4,3),nrow=3, ncol=3)
> m
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 1 2 4
[3,] 1 2 3
library(fields)
> rdist(m)
[,1] [,2] [,3]
[1,] 1e-10 1e+00 1e-10
[2,] 1e+00 1e-10 1e+00
[3,] 1e-10 1e+00 1e-10
What confuses me is that I think it should have 0s on the diagonal (surely the distance of a vector to itself is 0?), and for the same reason it should have 0s where it compares the first and third row. The value that I see instead (1e-10) looks way to big to be numerical noise. What's going wrong?
EDIT: rdist is from the package fields.
First of all 1e-10 is simply 1*10^-10 which is 0.0000000001, so numericaly very close to 0 (as it is a result of square rooting, so the actual error in the computation is of row of magnitude 1e-20). Is it "too big"? Well, library is written in fortran, and is focused on speed, so it is quite acceptable. If you analyze the exact code, you will find out how it is computed:
# fields, Tools for spatial data
# Copyright 2004-2011, Institute for Mathematics Applied Geosciences
# University Corporation for Atmospheric Research
# Licensed under the GPL -- www.gpl.org/licenses/gpl.html
"rdist" <- function(x1, x2) {
if (!is.matrix(x1))
x1 <- as.matrix(x1)
if (missing(x2))
x2 <- x1
if (!is.matrix(x2))
x2 <- as.matrix(x2)
d <- ncol(x1)
n1 <- nrow(x1)
n2 <- nrow(x2)
par <- c(1/2, 0)
temp <- .Fortran("radbas", nd = as.integer(d), x1 = as.double(x1),
n1 = as.integer(n1), x2 = as.double(x2), n2 = as.integer(n2),
par = as.double(par), k = as.double(rep(0, n1 * n2)))$k
return(matrix(temp, ncol = n2, nrow = n1))
}
And the exact answer is hidden in the fortran files (in radfun.f called from radbas.f), where you can find the line
if( dtemp.lt.1e-20) dtemp =1e-20
which treats small (even 0) values as 1e-20, which after taking square root results in 1e-10. It seems that the motivation was to speed up the process by using logarithm of the value (as a result, square rooting is simply dividing by 2), which of course is not defined for 0.

Can't get a positive definite variance matrix when very small eigen values

To run a Canonical correspondence analysis (cca package ade4) I need a positive definite variance matrix. (Which in theory is always the case)
but:
matrix(c(2,59,4,7,10,0,7,0,0,0,475,18714,4070,97,298,0,1,0,17,7,4,1,4,18,36),nrow=5)
> a
[,1] [,2] [,3] [,4] [,5]
[1,] 2 0 475 0 4
[2,] 59 7 18714 1 1
[3,] 4 0 4070 0 4
[4,] 7 0 97 17 18
[5,] 10 0 298 7 36
> eigen(var(a))
$values
[1] 6.380066e+07 1.973658e+02 3.551492e+01 1.033096e+01
[5] -1.377693e-09
The last eigen value is -1.377693e-09 which is < 0. But the theorical value is > 0.
I can't run the function if one of the eigen value is < 0
I really don't know how to fix this without changing the code of the function cca()
Thanks for help
You can change the input, just a little bit, to make the matrix positive definite.
If you have the variance matrix, you can truncate the eigenvalues:
correct_variance <- function(V, minimum_eigenvalue = 0) {
V <- ( V + t(V) ) / 2
e <- eigen(V)
e$vectors %*% diag(pmax(minimum_eigenvalue,e$values)) %*% t(e$vectors)
}
v <- correct_variance( var(a) )
eigen(v)$values
# [1] 6.380066e+07 1.973658e+02 3.551492e+01 1.033096e+01 1.326768e-08
Using the singular value decomposition, you can do the same thing directly with a.
truncate_singular_values <- function(a, minimum = 0) {
s <- svd(a)
s$u %*% diag( ifelse( s$d > minimum, s$d, minimum ) ) %*% t(s$v)
}
svd(a)$d
# [1] 1.916001e+04 4.435562e+01 1.196984e+01 8.822299e+00 1.035624e-01
eigen(var( truncate_singular_values(a,.2) ))$values
# [1] 6.380066e+07 1.973680e+02 3.551494e+01 1.033452e+01 6.079487e-09
However, this changes your matrix a by up to 0.1, which is a lot
(I suspect it is that high because the matrix a is square: as a result,
one of the eigenvalues of var(a) is exactly 0.)
b <- truncate_singular_values(a,.2)
max( abs(b-a) )
# [1] 0.09410187
We can actually do better simply by adding some noise.
b <- a + 1e-6*runif(length(a),-1,1) # Repeat if needed
eigen(var(b))$values
# [1] 6.380066e+07 1.973658e+02 3.551492e+01 1.033096e+01 2.492604e-09
Here are two approaches:
V <- var(a)
# 1
library(Matrix)
nearPD(V)$mat
# 2 perturb diagonals
eps <- 0.01
V + eps * diag(ncol(V))

How to obtain right eigenvectors of matrix in R?

Edition : the problem in my question was I've tried to find matrix S from equation 8 but this equation have error.
How to directly obtain right eigenvectors of matrix in R ? 'eigen()' gives only left eigenvectors
Really last edition, I've made big mess here, but this question is really important for me :
eigen() provides some matrix of eigenvectors, from function help :
" If ‘r <- eigen(A)’, and ‘V <- r$vectors; lam <- r$values’, then
A = V Lmbd V^(-1)
(up to numerical fuzz), where Lmbd =diag(lam)"
that is A V = V Lmbd, where V is matrix now we check it :
set.seed(1)
A<-matrix(rnorm(16),4,4)
Lmbd=diag(eigen(A)$values)
V=eigen(A)$vectors
A%*%V
> A%*%V
[,1] [,2] [,3] [,4]
[1,] 0.0479968+0.5065111i 0.0479968-0.5065111i 0.2000725+0i 0.30290103+0i
[2,] -0.2150354+1.1746298i -0.2150354-1.1746298i -0.4751152+0i -0.76691563+0i
[3,] -0.2536875-0.2877404i -0.2536875+0.2877404i 1.3564475+0i 0.27756026+0i
[4,] 0.9537141-0.0371259i 0.9537141+0.0371259i 0.3245555+0i -0.03050335+0i
> V%*%Lmbd
[,1] [,2] [,3] [,4]
[1,] 0.0479968+0.5065111i 0.0479968-0.5065111i 0.2000725+0i 0.30290103+0i
[2,] -0.2150354+1.1746298i -0.2150354-1.1746298i -0.4751152+0i -0.76691563+0i
[3,] -0.2536875-0.2877404i -0.2536875+0.2877404i 1.3564475+0i 0.27756026+0i
[4,] 0.9537141-0.0371259i 0.9537141+0.0371259i 0.3245555+0i -0.03050335+0i
and I would like to find matrix of right eigenvectors R,
equation which define matrix of left eigenvectors L is :
L A = LambdaM L
equation which define matrix of right eigenvectors R is :
A R = LambdaM R
and eigen() provides only matrix V:
A V = V Lmbd
I would like to obtain matrix R and LambdaM for real matrix A which may be negative-definite.
A worked example.
Default (= right eigenvectors):
m <- matrix(1:9,nrow=3)
e <- eigen(m)
e1 <- e$vectors
zapsmall((m %*% e1)/e1) ## right e'vec
## [,1] [,2] [,3]
## [1,] 16.11684 -1.116844 0
## [2,] 16.11684 -1.116844 0
## [3,] 16.11684 -1.116844 0
Left eigenvectors:
eL <- eigen(t(m))
eL1 <- eL$vectors
(We have to go to a little more effort since we need
to be multiplying by row vectors on the left; if
we extracted just a single eigenvector, R's ignorance
of row/column vector distinctions would make it
"do the right thing" (i.e. (eL1[,1] %*% m)/eL1[,1]
just works).)
zapsmall(t(eL1) %*% m/(t(eL1)))
## [,1] [,2] [,3]
## [1,] 16.116844 16.116844 16.116844
## [2,] -1.116844 -1.116844 -1.116844
## [3,] 0.000000 0.000000 0.000000
This should work
Given a matrix A.
lefteigen <- function(A){
return(t(eigen(t(A))$vectors))
}
Every left eigenvector is the transpose of a right eigenvector of the transpose of a matrix

Resources