如何从python / numpy调用java函数? [英] How to call a java function from python/numpy?

查看:133
本文介绍了如何从python / numpy调用java函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很清楚如何使用C ++扩展Python,但是如果我想在Java中编写一个与numpy一起使用的函数呢?

it is clear to me how to extend Python with C++, but what if I want to write a function in Java to be used with numpy?

这是一个简单的场景:我想用Java类计算numpy数组的平均值。如何将numpy向量传递给Java类并收集结果?

Here is a simple scenario: I want to compute the average of a numpy array using a Java class. How do I pass the numpy vector to the Java class and gather the result?

感谢您的帮助!

推荐答案

我花了一些时间在我自己的问题上,并希望分享我的答案,因为我觉得在 stackoverflow 上关于这个主题的信息不多。我还认为Java将在科学计算中变得更加相关(例如,参见用于数据挖掘的WEKA包),因为Java的性能和其他良好的软件开发功能得到了改进。

I spent some time on my own question and would like to share my answer as I feel there is not much information on this topic on stackoverflow. I also think Java will become more relevant in scientific computing (e.g. see WEKA package for data mining) because of the improvement of performance and other good software development features of Java.

一般来说,使用正确的工具,使用Java扩展Python比使用C / C ++更容易!

  • http://pypi.python.org/pypi/JCC: because of no proper documentation this tool is useless.

Py4J:需要在使用python之前启动Java进程。正如其他人所说的
这可能是一个失败点。此外,记录的使用示例并不多。

Py4J: requires to start the Java process before using python. As remarked by others this is a possible point of failure. Moreover, not many examples of use are documented.

JPype :虽然开发似乎是死亡,但它运作良好,网上有很多例子,例如参见 http://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/ 用Java编写)。因此我决定将
集中在这个工具上

JPype: although development seems to be death, it works well and there are many examples on it on the web (e.g. see http://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/ for using data mining libraries written in Java) . Therefore I decided to focus on this tool.

我正在使用Fedora 16,因为在Linux上安装JPype时存在一些问题,我描述了我的方法。
下载 JPype ,然后通过提供JDK修改 setup.py 脚本路径,第48行:

I am using Fedora 16, since there are some issues when installing JPype on Linux, I describe my approach. Download JPype, then modify setup.py script by providing the JDK path, in line 48:

self.javaHome = '/usr/java/default'

然后运行:

sudo python setup.py install

安装成功后,请检查此文件:

Afters successful installation, check this file:

/usr/lib64/python2.7/site-packages/jpype/_linux.py

并删除或重命名方法 getDefaultJVMPath()进入 getDefaultJVMPath_old(),然后添加以下方法:

and remove or rename the method getDefaultJVMPath() into getDefaultJVMPath_old(), then add the following method:

def getDefaultJVMPath():
    return "/usr/java/default/jre/lib/amd64/server/libjvm.so"

替代方法:不要对上述文件 _linux.py 进行任何更改,但绝不使用方法getDefaultJVMPath( )(或称这种方法的方法)。在使用 getDefaultJVMPath()的地方直接提供JVM的路径。请注意,有几个路径,例如在我的系统中,我也有以下路径,指的是不同版本的JVM(我不清楚客户端或服务器JVM是否更适合):

Alternative approach: do not make any change in the above file _linux.py, but never use the method getDefaultJVMPath() (or methods which call this method). At the place of using getDefaultJVMPath() provide directly the path to the JVM. Note that there are several paths, for example in my system I also have the following paths, referring to different versions of the JVM (it is not clear to me whether the client or server JVM is better suited):


  • /usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre/lib/x86_64/client/libjvm.so

  • /usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre/lib/x86_64/server/libjvm.so

  • / usr /lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/libjvm.so

最后,将以下行添加到〜/ .bashrc (或在每次打开python解释器之前运行它):

Finally, add the following line to ~/.bashrc (or run it each time before opening a python interpreter):

export JAVA_HOME='/usr/java/default'

(The上面的目录实际上只是我上一版JDK的符号链接,它位于 /usr/java/jdk1.7.0_04 )。

(The above directory is in reality just a symbolic link to my last version of JDK, which is located at /usr/java/jdk1.7.0_04).

请注意已下载JPype的目录中的所有测试,即 JPype-0.5.4.2 / test / testsuite.py 将失败(所以不关心它们)。

Note that all the tests in the directory where JPype has been downloaded, i.e. JPype-0.5.4.2/test/testsuite.py will fail (so do not care about them).

要查看它是否有效,请在python中测试此脚本:

To see if it works, test this script in python:

import jpype 
jvmPath = jpype.getDefaultJVMPath() 
jpype.startJVM(jvmPath)
# print a random text using a Java class
jpype.java.lang.System.out.println ('Berlusconi likes women') 
jpype.shutdownJVM() 



使用Numpy从Java调用Java类



让我们开始实现一个包含一些我想要应用于 numpy的函数的Java类阵列。由于没有状态概念,我使用静态函数,因此我不需要创建任何Java对象(创建Java对象不会改变任何东西)。

Calling Java classes from Java also using Numpy

Let's start implementing a Java class containing some functions which I want to apply to numpy arrays. Since there is no concept of state, I use static functions so that I do not need to create any Java object (creating Java objects would not change anything).

/**
 * Cookbook to pass numpy arrays to Java via Jpype
 * @author Mannaggia
 */

package test.java;

public class Average2 {

public static double compute_average(double[] the_array){
    // compute the average
    double result=0;
    int i;
    for (i=0;i<the_array.length;i++){
        result=result+the_array[i];
    }
    return result/the_array.length;
}
// multiplies array by a scalar
public static double[] multiply(double[] the_array, double factor) {

    int i;
    double[] the_result= new double[the_array.length];
    for (i=0;i<the_array.length;i++) {
        the_result[i]=the_array[i]*factor;
    }
    return the_result;
}

/**
 * Matrix multiplication. 
 */
public static double[][] mult_mat(double[][] mat1, double[][] mat2){
    // find sizes
    int n1=mat1.length;
    int n2=mat2.length;
    int m1=mat1[0].length;
    int m2=mat2[0].length;
    // check that we can multiply
    if (n2 !=m1) {
        //System.err.println("Error: The number of columns of the first argument must equal the number of rows of the second");
        //return null;
        throw new IllegalArgumentException("Error: The number of columns of the first argument must equal the number of rows of the second");
    }
    // if we can, then multiply
    double[][] the_results=new double[n1][m2];
    int i,j,k;
    for (i=0;i<n1;i++){
        for (j=0;j<m2;j++){
            // initialize
            the_results[i][j]=0;
            for (k=0;k<m1;k++) {
                the_results[i][j]=the_results[i][j]+mat1[i][k]*mat2[k][j];
            }
        }
    }
    return the_results;
}

/**
 * @param args
 */
public static void main(String[] args) {
    // test case
    double an_array[]={1.0, 2.0,3.0,4.0};
    double res=Average2.compute_average(an_array);
    System.out.println("Average is =" + res);
}
}

该类的名称有点误导,如我们不仅要计算numpy向量的平均值(使用方法 compute_average ),还要将numpy向量乘以标量(方法乘法),最后,矩阵乘法(方法 mult_mat )。

The name of the class is a bit misleading, as we do not only aim at computing the average of a numpy vector (using the method compute_average), but also multiply a numpy vector by a scalar (method multiply), and finally, the matrix multiplication (method mult_mat).

编译完上面的Java类后,我们现在可以运行以下Python脚本:

After compiling the above Java class we can now run the following Python script:

import numpy as np
import jpype

jvmPath = jpype.getDefaultJVMPath() 
# we to specify the classpath used by the JVM
classpath='/home/mannaggia/workspace/TestJava/bin'
jpype.startJVM(jvmPath,'-Djava.class.path=%s' % classpath)

# numpy array
the_array=np.array([1.1, 2.3, 4, 6,7])
# build a JArray, not that we need to specify the Java double type using the jpype.JDouble wrapper
the_jarray2=jpype.JArray(jpype.JDouble, the_array.ndim)(the_array.tolist())
Class_average2=testPkg.Average2 
res2=Class_average2.compute_average(the_jarray2)
np.abs(np.average(the_array)-res2) # ok perfect match! 

# now try to multiply an array
res3=Class_average2.multiply(the_jarray2,jpype.JDouble(3))
# convert to numpy array
res4=np.array(res3) #ok

# matrix multiplication
the_mat1=np.array([[1,2,3], [4,5,6], [7,8,9]],dtype=float)
#the_mat2=np.array([[1,0,0], [0,1,0], [0,0,1]],dtype=float)
the_mat2=np.array([[1], [1], [1]],dtype=float)
the_mat3=np.array([[1, 2, 3]],dtype=float)

the_jmat1=jpype.JArray(jpype.JDouble, the_mat1.ndim)(the_mat1.tolist())
the_jmat2=jpype.JArray(jpype.JDouble, the_mat2.ndim)(the_mat2.tolist())
res5=Class_average2.mult_mat(the_jmat1,the_jmat2)
res6=np.array(res5) #ok

# other test
the_jmat3=jpype.JArray(jpype.JDouble, the_mat3.ndim)(the_mat3.tolist())
res7=Class_average2.mult_mat(the_jmat3,the_jmat2)
res8=np.array(res7)
res9=Class_average2.mult_mat(the_jmat2,the_jmat3)
res10=np.array(res9)

# test error due to invalid matrix multiplication
the_mat4=np.array([[1], [2]],dtype=float)
the_jmat4=jpype.JArray(jpype.JDouble, the_mat4.ndim)(the_mat4.tolist())
res11=Class_average2.mult_mat(the_jmat1,the_jmat4)

jpype.java.lang.System.out.println ('Goodbye!') 
jpype.shutdownJVM() 

这篇关于如何从python / numpy调用java函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆