Skip to content
Nate Jensen edited this page Dec 18, 2019 · 21 revisions

Since Jep 3.3

Java primitive arrays <-> numpy.ndarrays

Jep supports automatic conversion of Java primitive arrays to numpy.ndarrays. For ease and speed of copying the arrays between the two languages, the Java arrays must be one dimensional. This is to ensure a contiguous block of a known size of memory for the conversion. Conceptually the Java array can be n-dimensional with the dimensions argument, but in memory it must be one dimensional.

Sending a Java primitive array into Python as a numpy.ndarray is easy using the class jep.NDArray. For example:

try(SharedInterpreter interp = new SharedInterpreter()) {
   float[] f = new float[] { 1.0f, 2.1f, 3.3f, 4.5f, 5.6f, 6.7f };
   NDArray<float[]> nd = new NDArray<>(f, 3, 2);
   interp.set("x", nd);
}

Inside the interpreter, the variable named x will be a numpy.ndarray with shape (3,2) and dtype float32. If a Java method signature contains an NDArray, it will also be transformed when crossing between the languages. For example:

/**
 * If Python invokes this method, it will receive back a numpy.ndarray.
 */
public NDArray<?> getRawData() {
   // presuming this.rawdata is conceptually only 1-dimensional
   return new NDArray(this.rawdata, this.rawdata.length);
}
/**
 * If Python invokes this method, it should pass in a numpy.ndarray.
 */
public void setData(NDArray<?> dataFromPython) {
   // ignoring dimensions, presuming this.rawdata is conceptually only 1-dimensional
   this.rawdata = dataFromPython.getData();
}

At times Jep will convert a numpy.ndarray into a Java primitive array when the class NDArray does not fit a method signature. For example,

public void setFloatData(float[] dataFromPython) {
   // note that the dimensions are lost
   this.rawdata = dataFromPython;
}

In this scenario the information about the ndarray dimensions will not be sent along.

Direct memory support

When using an NDArray the memory is not shared between numpy and Java, therefore changes in the array in one language are not reflected in the array in the other language. Since Jep 3.7 it is possible to use a DirectNDArray which can be created from a Java NIO buffer object. The Java buffer and the Python ndarray will both use the same memory meaning any changes in one language are immediately visible in the other. For example,

try (SharedInterpreter interp = new SharedInterpreter()){
    FloatBuffer data = ByteBuffer.allocateDirect(6*4).asFloatBuffer();
    DirectNDArray<FloatBuffer> nd = new DirectNDArray<>(data, 6);
    interp.set("x", nd);
    interp.exec("x[1] = 700");
    // val will 700 since we set it in python
    float val = data.get(1);
    data.put(4, val + 100);
    // prints 800 since we set in java
    interp.exec("print(x[4])");
}

Numpy gotchas

Numpy does not support Python sub-interpreters. It is recommended to use Jep's SharedInterpreter for applications that import numpy. If you need to use numpy with Jep's SubInterpreter, it is possible to workaround the numpy problems by including numpy in the list of shared modules in the JepConfig.