[R] Solve an ordinary or generalized eigenvalue problem in R?

Berend Hasselman bhh at xs4all.nl
Sat Apr 21 11:40:04 CEST 2012


On 20-04-2012, at 21:18, Jonathan Greenberg wrote:

> Ok, I figured out a solution and I'd like to get some feedback on this from
> the R-helpers as to how I could modify the following to be "package
> friendly" -- the main thing I'm worried about is how to dynamically set the
> "dyn.load" statement below correctly (obviously, its hard coded to my
> particular install, and would only work with windows since I'm using a
> .dll):
> 
> Rdggev <- function(JOBVL=F,JOBVR=T,A,B)
> {
> # R implementation of the DGGEV LAPACK function (with generalized
> eigenvalue computation)
> # See http://www.netlib.org/lapack/double/dggev.f
> # coded by Jonathan A. Greenberg <jgrn at illinois.edu>
> dyn.load("C:\\Program Files\\R\\R-2.14.2\\bin\\x64\\Rlapack.dll")
> 
> if(JOBVL)
> {
> JOBVL="V"
> } else
> {
> JOBVL="N"
> }
> if(JOBVR)
> {
> JOBVR="V"
> } else
> {
> JOBVR="N"
> }
> # Note, no error checking is performed.
> # Input parameters
> N=dim(A)[[1]]
> LDA=N
> LDB=N
> LDVL=N
> LDVR=N
> LWORK=as.integer(max(1,8*N))
> Rdggev_out <- .Fortran("dggev", JOBVL, JOBVR, N, A, LDA, B, LDB,
> double(N), double(N), double(N),
> array(data=0,dim=c(LDVL,N)), LDVL, array(data=0,dim=c(LDVR,N)), LDVR,
> double(max(1,LWORK)), LWORK, integer(1))
> 
> names(Rdggev_out)=c("JOBVL","JOBVR","N","A","LDA","B","LDB","ALPHAR","ALPHAI",
> "BETA","VL","LDVL","VR","LDVR","WORK","LWORK","INFO")
> 
> Rdggev_out$GENEIGENVALUES=(Rdggev_out$ALPHAR+Rdggev_out$ALPHAI)/Rdggev_out$BETA
> return(Rdggev_out)
> }
> 

See this:

<start R code>
# This works on Mac OS X
# Change as needed for other systems
# or compile geigen into a standalone shared object.

dyn.load(file.path(R.home("lib"),"libRlapack.dylib"))

geigen <- function(A,B,jobvl=FALSE,jobvr=FALSE) {

    # simplistic interface to Lapack dggev
    # for generalized eigenvalue problem
    # general matrices
    # for symmetric matrices use dsygv

    if(!is.matrix(A)) stop("Argument A should be a matrix")
    if(!is.matrix(B)) stop("Argument B should be a matrix")
    dimA <- dim(A)
    if(dimA[1]!=dimA[2]) stop("A must be a square matrix")
    dimB <- dim(B)
    if(dimB[1]!=dimB[2]) stop("B must be a square matrix")
    if(dimA[1]!=dimB[1]) stop("A and B must have the same dimensions")
    
    if( is.complex(A) ) stop("A may not be complex")
    if( is.complex(B) ) stop("B may not be complex")
    
    jobvl.char <- if(jobvl) "V" else "N"
    jobvr.char <- if(jobvr) "V" else "N"

    n <- dimA[1]
    
    # minimum amount of work memory
    # for performance this needs to be set properly 
    # (see source dggev)
    
    lwork <- as.integer(8*n)
    work <- numeric(lwork)
    
    if( jobvl && jobvr )
        z <- .Fortran("dggev", jobvl.char, jobvr.char, n, A, n, B, n, alphar=numeric(n), alphai=numeric(n),
                              beta=numeric(n), vl=matrix(0,nrow=n,ncol=n), n, vr=matrix(0,nrow=n,ncol=n), n,
                              work, lwork,info=integer(1L))
    else if(jobvl && !jobvr )
        z <- .Fortran("dggev", jobvl.char, jobvr.char, n, A, n, B, n, alphar=numeric(n), alphai=numeric(n),
                              beta=numeric(n), vl=matrix(0,nrow=n,ncol=n), n, numeric(1), 1L,
                              work, lwork,info=integer(1L))
    else if(!jobvl && jobvr )
        z <- .Fortran("dggev", jobvl.char, jobvr.char, n, A, n, B, n, alphar=numeric(n), alphai=numeric(n),
                              beta=numeric(n), numeric(1),1L, vr=matrix(0,nrow=n,ncol=n), n,
                              work, lwork,info=integer(1L))
    else
        z <- .Fortran("dggev", jobvl.char, jobvr.char, n, A, n, B, n, alphar=numeric(n), alphai=numeric(n),
                              beta=numeric(n), numeric(1), 1L,  numeric(1), 1L,
                              work, lwork,info=integer(1L))
    
    if( z$info > 0 ) stop(paste("Lapack  dggev fails with info=",z$info))
    
    # simplistic calculation of eigenvalues (see caveat in source dggev)
    if( all(z$alphai==0) )
        values <- z$alphar/z$beta
    else
        values <- complex(real=z$alphar, imaginary=z$alphai)/z$beta
    
    if( jobvl && jobvr )    
        return(list(values=values, vl=z$vl, vr=z$vr))
    else if( jobvl )    
        return(list(values=values, vl=z$vl))
    else if( jobvr )    
        return(list(values=values, vr=z$vr))
    else
        return(list(values=values))       
}

A <- matrix(c(1457.738, 1053.181, 1256.953,
              1053.181, 1213.728, 1302.838,
              1256.953, 1302.838, 1428.269), nrow=3, byrow=TRUE)

B <- matrix(c(4806.033, 1767.480, 2622.744,
              1767.480, 3353.603, 3259.680,
              2622.744, 3259.680, 3476.790), nrow=3, byrow=TRUE)

A
B

geigen(A, B)
geigen(A, B, TRUE , TRUE)
geigen(A, B, TRUE , FALSE)
geigen(A, B, FALSE, TRUE)

<end R code>

Berend



More information about the R-help mailing list