oracle / fastr

A high-performance implementation of the R programming language, built on GraalVM.
Other
627 stars 64 forks source link

unimplemented .Internal La_dlange #151

Open kurt-o-sys opened 4 years ago

kurt-o-sys commented 4 years ago
$ /usr/lib/jvm/graalvm/bin/java -version
openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02)
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02, mixed mode, sharing)
$ /usr/lib/jvm/graalvm/bin/R                         
R version 3.6.1 (FastR)
Copyright (c) 2013-19, Oracle and/or its affiliates
Copyright (c) 1995-2018, The R Core Team
Copyright (c) 2018 The R Foundation for Statistical Computing
Copyright (c) 2012-4 Purdue University
Copyright (c) 1997-2002, Makoto Matsumoto and Takuji Nishimura
All rights reserved.

After installing the quadprog and NlcOptim package, and trying to run a solver:

Error in norm(as.matrix(DIR), "I") : unimplemented .Internal La_dlange

It seems some internal calculation, used to calculate the norm of a matrix, is not implemented (which somehow seems pretty weird to me). In NlcOptim::solnl, there are a few calls to the R norm function, e.g. https://github.com/cran/NlcOptim/blob/master/R/NlcOptim.R#L506 (this is where fastr seems to fail, but there are other paths as well that use the norm function):

        if (( norm(as.matrix(DIR),"I") < 2*tolX || abs(alpha*ggfDIR)<tolFun) &(maxga < tolCon)){
          finishflag = T
        }

If I check the sources of norm:

> norm
function (x, type = c("O", "I", "F", "M", "2")) 
{
    if (identical("2", type)) {
        svd(x, nu = 0L, nv = 0L)$d[1L]
    }
    else .Internal(La_dlange(x, type))
}

== EDIT: added more info

so, checking the source https://github.com/oracle/fastr/blob/3e4189b7fe018edd4e8f7ec15ae70059f34710c1/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java#L442, it seems many symbols seem not implemented. Is there any particular reason or eta for many of them (excluding things like the distribution functions, since they are used in a different way and it actually doesn't matter for these):

    private static final List<String> NOT_IMPLEMENTED = Arrays.asList(
                    ".addTryHandlers", "interruptsSuspended", "restart", "max.col", "comment", "`comment<-`", "list2env", "tcrossprod",
                    "beta", "dchisq", "pchisq", "qchisq", "dexp", "pexp", "qexp", "dgeom", "pgeom", "qgeom", "dpois", "ppois", "qpois", "dt", "pt", "qt", "dsignrank", "psignrank",
                    "qsignrank", "dbeta", "pbeta", "qbeta", "dbinom", "pbinom", "qbinom", "dcauchy", "pcauchy", "qcauchy", "df", "pf", "qf", "dgamma", "pgamma",
                    "qgamma", "dlnorm", "plnorm", "qlnorm", "dlogis", "plogis", "qlogis", "dnbinom", "pnbinom", "qnbinom", "dnorm", "pnorm", "qnorm", "dunif", "punif", "qunif", "dweibull", "pweibull",
                    "qweibull", "dnchisq", "pnchisq", "qnchisq", "dnt", "pnt", "qnt", "dwilcox", "pwilcox", "qwilcox", "dnbinom_mu", "pnbinom_mu", "qnbinom_mu", "dhyper",
                    "phyper", "qhyper", "dnbeta", "pnbeta", "qnbeta", "dnf", "pnf", "qnf", "dtukey", "ptukey", "qtukey", "rchisq", "rexp", "rgeom", "rpois", "rt", "rsignrank", "rbeta", "rbinom",
                    "rcauchy", "rf", "rgamma", "rlnorm", "rlogis", "rnbinom", "rnbinom_mu", "rnchisq", "rnorm", "runif", "rweibull", "rwilcox", "rhyper",
                    "grepRaw", "regexec", "adist", "aregexec", "chartr", "strtrim", "eapply", "machine", "save", "dump", "prmatrix", "gcinfo",
                    "memory.profile", "sys.on.exit", "builtins", "bodyCode", "rapply",
                    "mem.limits", "capabilitiesX11", "Cstack_info", "file.choose",
                    "setNumMathThreads", "setMaxNumMathThreads", "isatty", "isIncomplete", "pipe", "fifo", "unz", "truncate", "rawConnection",
                    "rawConnectionValue", "sockSelect", "gzcon", "memCompress", "memDecompress", "mkUnbound", "env.profile", "setSessionTimeLimit", "icuSetCollate", "findInterval", "rowsum_df",
                    "La_qr_cmplx", "La_rs_cmplx", "La_rg_cmplx", "La_rs_cmplx", "La_dlange", "La_dgecon", "La_dtrcon", "La_zgecon", "La_ztrcon", "La_solve_cmplx", "La_chol2inv", "qr_qy_real",
                    "qr_qy_cmpl", "La_svd", "La_svd_cmplx");
}
steve-s commented 4 years ago

Hello,

thank you for reaching to us. The list of unimplemented built-ins is not up to date (and we should fix that). However, we only use it to check if we cannot find given built-in implementation in FastR: then we need to report either "unimplemented builtin" or "wrong builtin" and we use this list to distinguish the two. If the builtin is implemented, we do not even reach that point.

That being said, there are unimplemented built-ins in FastR, like the one you've come across. We are implementing them on per needed basis. I cannot give you concrete ETA for individual builtins. The La_xyz built-ins usually down-call to native code from blas/lapack, e.g.: La_svd in https://github.com/oracle/fastr/blob/master/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java#L817

kurt-o-sys commented 4 years ago

So, in short, La_dlange is really not implemented yet?

I cannot find an inner class annotated with @RBuiltin(name = "La_dlange" ...), but there are calls to @Child private LapackRFFI.DlangeNode dlangeNode = LapackRFFI.DlangeNode.create();. Does that mean that it about writing a kind of wrapper class around that LapackRFFI.DlangeNode?

steve-s commented 4 years ago

Does that mean that it about writing a kind of wrapper class around that LapackRFFI.DlangeNode?

Yes. DlangeNode calls into the Lapack routine, which is piece of code unaware of the rest of R and operates only on primitive C arrays. The built-in La_dlange works on R objects: it validates its arguments, converts the R vectors to primitive arrays, calls the Lapack routine and converts the results back to R objects. This is what most of the RBuiltin annotated classes in LaFunctions.java do.

The built-in in GNU-R is here: https://github.com/wch/r-source/blob/R-3-6-branch/src/modules/lapack/Lapack.c#L333. Basically we need to check if the first argument is matrix and coerce it to a real matrix and that the second one is a character vector and then pass the right arguments to DlangeNode#execute.

Note that we use our own thin wrappers around the C/Fortran routines: https://github.com/oracle/fastr/blob/master/com.oracle.truffle.r.native/fficall/src/truffle_common/lapack_rffi.c#L123, so DlangeNode interface is not exactly the same as the dlange native routine.

The classes annotated with @RBuiltin are registered in BasePackage.

kurt-o-sys commented 4 years ago

Allright, thx for the info. I guess I'll just have to wait and hope someone makes this work.