[Rd] rJava question

Simon Urbanek
Tue, 28 Dec 2010 19:05:46 -0000

Dominick,

On Dec 27, 2010, at 11:56 PM, Dominick Samperi wrote:

> After some trial and error I figured out how to pass matrices from R to
java
> and back using rJava, but this method is not documented and I wonder if
there is a
> better way?
>

stats-rosuda-devel is the rJava list you want to use.


> Anyway, here is what I found works:
>
> (m = matrix(as.double(1:12),3,4))
> [shows m as you would expect]
>
> jtest <- .jnew("JTest")
> (v <- .jcall(jtest, '[[D], 'myfunc', .jarray(m),
evalArray=FALSE))
> [shows v = m + 10]
>
> Here the JTest class has a method named myfunc that accepts
> a double[][] and returns a double[][]. It simply adds 10 to every
> element.
>

The above is plain wrong (well, that's actually a guess since you didn't
provide even the signature of the method) - matrices in R are vectors, so the
type is double[]. In Java there is no matrix type, so it's up to the
application to represent matrices and there are many ways - some more efficient
than others. From your example above it seems that you are using double[][] --
so you have to allocate the extra objects one way or another (that's why
it's inefficient to represent matrices that way).

But from your e-mail I have the feeling that your questions is rather about
calling a method that returns double[][], so for example:
public static double[][] pass();
where double[][] is a rectangular array (i.e. length of all inner arrays is
equal).

Unfortunately .jcall is a bit inconsistent due to bug that was introduced with
the new J() API. So the intended behavior is (using class Test with the method
above):
> J("Test")$pass()
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
[4,]   13   14   15   16

The $ operator makes sure that the result is converted to a native R form where
possible, including recursive structures like double[][].

However, the intention of .jcall() was to never perform recursive evaluation, so
this is intended:

> .jcall("Test","[[D","pass", evalArray=TRUE)
[[1]]
[1] "Java-Array-Object[D:[D at 11ddcde"

[[2]]
[1] "Java-Array-Object[D:[D at 18fb1f7"

[[3]]
[1] "Java-Array-Object[D:[D at ed0338"

[[4]]
[1] "Java-Array-Object[D:[D at 6e70c7"


The intended behavior (and true in older version of rJava) was for .jcall with
evalArray=FALSE to return the reference:

> .jcall("Test","[[D","pass", evalArray=FALSE)
[1] "Java-Array-Object[[D:[[D at 8f4fb3"

Unfortunately, the bug is that .jcall uses rJava:::newArray() to create the
reference which defaults to simplify=TRUE so the current (buggy) behavior is:

> .jcall("Test","[[D","pass", evalArray=FALSE)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
[4,]   13   14   15   16


The real issue is that:
a) if the bug is fixed, .jcall() can return just the reference which is intended
but
b) there is currently no exposed API for rJava:::newArray so the simplification
is not available in any form for references if the bug is fixed (other than
using the J/$ API).

That's why I was hesitant so far to fix the bug, but I really should --
which is why the behavior your discovered will change. However, then I need to
add some API to be able to convert a reference in the same way that
rJava:::newArray provides and expose it - I didn't think through that part,
so that's why I got stuck.

I hope it helps...
Cheers,
Simon

(PS: please continue any discussion on stats-rosuda-devel)


> The parameter 'evalArray' is confusing because when
> evalArray=TRUE the result is NOT evaluated (a list is returned
> that you then have to apply .jevalArray to do get the answer).
>
> There seems to be an option to have a java reference returned
> instead of the actual matrix. Can the R side manipulate the
> matrix (on the java side) through this reference?
>
> Thanks,
> Dominick
>
> 	[[alternative HTML version deleted]]
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>