Merge "Omaha #4259 merging most of the rest of JEP updates with our changes" into omaha_16.1.1

Former-commit-id: 0d309effe01d50a323e1a6799632c7cf3efb4b5e
This commit is contained in:
Nate Jensen 2015-04-10 13:39:02 -05:00 committed by Gerrit Code Review
commit bcba6c956b
7 changed files with 1795 additions and 1235 deletions

View file

@ -0,0 +1,163 @@
package jep;
import java.util.Arrays;
/**
* <pre>
* NDArray.java - Represents a numpy.ndarray in Java. Should
* seamlessly transition between this representation in Java and
* a numpy.ndarray representation in Python.
*
* Copyright (c) 2015 Nate Jensen.
*
* This file is licenced under the the zlib/libpng License.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* Created: Tues Apr 07 2015
*
* </pre>
*
* @author [ndjensen at gmail.com] Nate Jensen
* @version $Id$
*/
public class NDArray<T extends Object> {
protected final T data;
protected final int[] dimensions;
public NDArray(T data, int[] dimensions) {
this.data = data;
this.dimensions = dimensions;
/*
* java generics don't give us a nice Class that all the primitive
* arrays extend, so we must enforce the type safety at runtime instead
* of compile time
*/
if (!data.getClass().isArray()
|| !data.getClass().getComponentType().isPrimitive()) {
throw new IllegalArgumentException(
"NDArray only supports primitive arrays, received "
+ data.getClass().getName());
}
}
public int[] getDimensions() {
return dimensions;
}
public T getData() {
return data;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
NDArray<?> other = (NDArray<?>) obj;
/*
* compare dimensions first cause that's most likely a shorter array to
* compare and will be faster
*/
if (!Arrays.equals(dimensions, other.dimensions)) {
return false;
}
// compare the data
if (data == null && other.data == null) {
return true;
} else if (data == null && other.data != null) {
return false;
} else if (data != null && other.data == null) {
return false;
} else {
// neither has null, let's compare values
if (!data.getClass().equals(other.data.getClass())) {
return false;
}
Class<?> clz = data.getClass().getComponentType();
if (clz == Boolean.TYPE) {
return Arrays.equals((boolean[]) data, (boolean[]) other.data);
} else if (clz == Byte.TYPE) {
return Arrays.equals((byte[]) data, (byte[]) other.data);
} else if (clz == Short.TYPE) {
return Arrays.equals((short[]) data, (short[]) other.data);
} else if (clz == Integer.TYPE) {
return Arrays.equals((int[]) data, (int[]) other.data);
} else if (clz == Long.TYPE) {
return Arrays.equals((long[]) data, (long[]) other.data);
} else if (clz == Float.TYPE) {
return Arrays.equals((float[]) data, (float[]) other.data);
} else if (clz == Double.TYPE) {
return Arrays.equals((double[]) data, (double[]) other.data);
} else {
// should be impossible to get here
throw new IllegalStateException(
"NDArray only supports primitive arrays, received "
+ clz.getName());
}
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (data == null) {
result = prime * result + 0;
} else {
Class<?> clz = data.getClass().getComponentType();
if (clz == Boolean.TYPE) {
result = prime * result + Arrays.hashCode((boolean[]) data);
} else if (clz == Byte.TYPE) {
result = prime * result + Arrays.hashCode((byte[]) data);
} else if (clz == Short.TYPE) {
result = prime * result + Arrays.hashCode((short[]) data);
} else if (clz == Integer.TYPE) {
result = prime * result + Arrays.hashCode((int[]) data);
} else if (clz == Long.TYPE) {
result = prime * result + Arrays.hashCode((long[]) data);
} else if (clz == Float.TYPE) {
result = prime * result + Arrays.hashCode((float[]) data);
} else if (clz == Double.TYPE) {
result = prime * result + Arrays.hashCode((double[]) data);
} else {
// should be impossible to get here
throw new IllegalStateException(
"NDArray only supports primitive arrays, received "
+ clz.getName());
}
}
result = prime * result + Arrays.hashCode(dimensions);
return result;
}
}

View file

@ -0,0 +1,260 @@
package jep;
import java.io.File;
/**
* Test.java
*
*
* Created: Wed Apr 08 2015
*
* @author [ndjensen at gmail.com] Nate Jensen
* @version $Id$
*/
public class TestNumpy implements Runnable {
protected Jep jep = null;
// set to a high number to test for memory leaks
private static final int REPEAT = 1; // 0000000;
private static boolean PRINT = false;
@Override
public void run() {
try {
File pwd = new File(".");
/*
* Anytime you start a new Jep interpreter and import numpy within
* it, even if you call close() on the interpreter you will leak
* some native memory. Therefore, for now, do NOT new up the
* interpreter and close it within the for loop.
*/
jep = new Jep(true, pwd.getAbsolutePath());
for (int i = 0; i < REPEAT; i++) {
testSetAndGet();
}
} catch (JepException e) {
e.printStackTrace();
} finally {
if (jep != null)
jep.close();
}
}
public void testSetAndGet() throws JepException {
int[] dimensions = new int[] { 4 };
// test boolean[]
NDArray<boolean[]> zarray = new NDArray<>(new boolean[] { true, false,
true, true }, dimensions);
jep.set("zarray", zarray);
String z_dtype = (String) jep.getValue("zarray.dtype");
if (!"bool".equals(z_dtype)) {
throw new RuntimeException("boolean ndarray set failed, dtype = "
+ z_dtype);
}
NDArray<?> retZ = (NDArray<?>) jep.getValue("zarray");
if (!zarray.equals(retZ)) {
throw new RuntimeException("boolean[] before != boolean[] after");
}
if (zarray.hashCode() != retZ.hashCode()) {
throw new RuntimeException(
"boolean[].hashCode() before != boolean[].hasCode() after");
}
// test byte[]
NDArray<byte[]> barray = new NDArray<>(new byte[] { 0x10, 0x00, 0x54,
032 }, dimensions);
jep.set("barray", barray);
String b_dtype = (String) jep.getValue("barray.dtype");
if (!"int8".equals(b_dtype)) {
throw new RuntimeException("byte ndarray set failed, dtype = "
+ b_dtype);
}
NDArray<?> retB = (NDArray<?>) jep.getValue("barray");
if (!barray.equals(retB)) {
throw new RuntimeException("byte[] before != byte[] after");
}
if (barray.hashCode() != retB.hashCode()) {
throw new RuntimeException(
"byte[].hashCode() before != byte[].hasCode() after");
}
// test short[]
NDArray<short[]> sarray = new NDArray<>(new short[] { 5, 3, 1, 8 },
dimensions);
jep.set("sarray", sarray);
String s_dtype = (String) jep.getValue("sarray.dtype");
if (!"int16".equals(s_dtype)) {
throw new RuntimeException("short ndarray set failed, dtype = "
+ s_dtype);
}
NDArray<?> retS = (NDArray<?>) jep.getValue("sarray");
if (!sarray.equals(retS)) {
throw new RuntimeException("short[] before != short[] after");
}
if (sarray.hashCode() != retS.hashCode()) {
throw new RuntimeException(
"short[].hashCode() before != short[].hasCode() after");
}
// test int[]
NDArray<int[]> iarray = new NDArray<>(
new int[] { 547, 232, -675, 101 }, dimensions);
jep.set("iarray", iarray);
String i_dtype = (String) jep.getValue("iarray.dtype");
if (!"int32".equals(i_dtype)) {
throw new RuntimeException("int ndarray set failed, dtype = "
+ i_dtype);
}
NDArray<?> retI = (NDArray<?>) jep.getValue("iarray");
if (!iarray.equals(retI)) {
throw new RuntimeException("int[] before != int[] after");
}
if (iarray.hashCode() != retI.hashCode()) {
throw new RuntimeException(
"int[].hashCode() before != int[].hasCode() after");
}
// test long[]
NDArray<long[]> larray = new NDArray<>(new long[] { 62724764L,
3424637L, 3426734242L, -3429234L }, dimensions);
jep.set("larray", larray);
String l_dtype = (String) jep.getValue("larray.dtype");
if (!"int64".equals(l_dtype)) {
throw new RuntimeException("long ndarray set failed, dtype = "
+ l_dtype);
}
NDArray<?> retL = (NDArray<?>) jep.getValue("larray");
if (!larray.equals(retL)) {
throw new RuntimeException("long[] before != long[] after");
}
if (larray.hashCode() != retL.hashCode()) {
throw new RuntimeException(
"long[].hashCode() before != long[].hasCode() after");
}
// test float[]
NDArray<float[]> farray = new NDArray<>(new float[] { 4.32f, -0.0001f,
349.285f, 3201.0f }, dimensions);
jep.set("farray", farray);
String f_dtype = (String) jep.getValue("farray.dtype");
if (!"float32".equals(f_dtype)) {
throw new RuntimeException("float ndarray set failed, dtype = "
+ f_dtype);
}
NDArray<?> retF = (NDArray<?>) jep.getValue("farray");
if (!farray.equals(retF)) {
throw new RuntimeException("float[] before != float[] after");
}
if (farray.hashCode() != retF.hashCode()) {
throw new RuntimeException(
"float[].hashCode() before != float[].hasCode() after");
}
// test double[]
NDArray<double[]> darray = new NDArray<>(new double[] { 0.44321,
0.00015, -9.34278, 235574.53 }, dimensions);
jep.set("darray", darray);
String d_dtype = (String) jep.getValue("darray.dtype");
if (!"float64".equals(d_dtype)) {
throw new RuntimeException("double ndarray set failed, dtype = "
+ d_dtype);
}
NDArray<?> retD = (NDArray<?>) jep.getValue("darray");
if (!darray.equals(retD)) {
throw new RuntimeException("double[] before != double[] after");
}
if (darray.hashCode() != retD.hashCode()) {
throw new RuntimeException(
"double[].hashCode() before != double[].hasCode() after");
}
if (PRINT) {
System.out.println("NDArray get/set checked out OK");
}
}
public NDArray<int[]> testArgAndReturn(NDArray<int[]> array) {
int[] data = array.getData();
int[] newData = new int[data.length];
for (int i = 0; i < data.length; i++) {
newData[i] = data[i] + 5;
}
return new NDArray<int[]>(newData, array.getDimensions());
}
// should only be called from main(), not from python unittests
public void runPythonSide() {
try {
File pwd = new File("tests");
/*
* Anytime you start a new Jep interpreter and import numpy within
* it, even if you call close() on the interpreter you will leak
* some native memory. Therefore, for now, do NOT new up the
* interpreter and close it within the for loop.
*/
jep = new Jep(true, pwd.getAbsolutePath());
jep.eval("import test_numpy");
jep.eval("v = test_numpy.TestNumpy('testArgReturn')");
jep.eval("v.setUp()");
for (int i = 0; i < REPEAT; i++) {
jep.eval("v.testArgReturn()");
}
for (int i = 0; i < REPEAT; i++) {
jep.eval("v.testMultiDimensional()");
}
for (int i = 0; i < REPEAT; i++) {
jep.eval("v.testArrayParams()");
}
} catch (JepException e) {
e.printStackTrace();
} finally {
if (jep != null)
jep.close();
}
}
public boolean callBooleanMethod(boolean[] array) {
return array != null;
}
public boolean callByteMethod(byte[] array) {
return array != null;
}
public boolean callShortMethod(short[] array) {
return array != null;
}
public boolean callIntMethod(int[] array) {
return array != null;
}
public boolean callLongMethod(long[] array) {
return array != null;
}
public boolean callFloatMethod(float[] array) {
return array != null;
}
public boolean callDoubleMethod(double[] array) {
return array != null;
}
/**
* This main() is for running the tests from Java. If running from the tests
* from python, use python setup.py test.
*
* @param args
*/
public static void main(String[] args) {
TestNumpy test = new TestNumpy();
test.run();
test.runPythonSide();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
import unittest
import jep
Test = jep.findClass('jep.TestNumpy')
class TestNumpy(unittest.TestCase):
def setUp(self):
self.test = Test()
self.printout = False
def testSetGet(self):
"""
Tests using Jep.set(String, Object) for java NDArrays
of the different primitive types. Then uses
Jep.get(String) to get a Java NDArray back and
checks for equality/symmetry.
"""
if jep.USE_NUMPY:
self.test.run()
def testArgReturn(self):
"""
Tests making a python ndarray, sending it to Java,
Java making a new one and adding 5 to the values,
and then Java returning the new ndarray to python.
"""
if jep.USE_NUMPY:
import numpy
x = numpy.array(range(10), numpy.int32)
y = self.test.testArgAndReturn(x)
self.assertEqual(x.shape, y.shape)
self.assertEqual(x.dtype, y.dtype)
for i in xrange(10):
self.assertEqual(x[i] + 5, y[i])
def testMultiDimensional(self):
"""
Tests sending a 3-dimensional ndarray to Java,
Java making a new one and adding 5 to the values,
and then Java returning the new ndarray to python.
"""
if jep.USE_NUMPY:
import numpy
o = range(24)
x = numpy.array(o, numpy.int32)
y = x.reshape((3,4,2))
z = self.test.testArgAndReturn(y)
self.assertEqual(y.shape, z.shape)
self.assertEqual(y.dtype, z.dtype)
y += 5
self.assertEqual(repr(y), repr(z))
if self.printout:
print ""
print repr(y)
print repr(z)
def testArrayParams(self):
"""
Tests passing an ndarray to a Java method that is expecting
a primitive array. This is useful for 1 dimensional arrays,
or if you already know the dimensions in Java, or you don't
want to depend on the java class NDArray.
"""
if jep.USE_NUMPY:
import numpy
za = numpy.zeros((15, 5), numpy.bool)
za.fill(True)
self.assertTrue(self.test.callBooleanMethod(za))
ba = numpy.zeros((15, 5), numpy.byte)
ba.fill(1)
self.assertTrue(self.test.callByteMethod(ba))
sa = numpy.zeros((15, 5), numpy.short)
sa.fill(2)
self.assertTrue(self.test.callShortMethod(sa))
ia = numpy.zeros((15, 5), numpy.int32)
ia.fill(True)
self.assertTrue(self.test.callIntMethod(ia))
la = numpy.zeros((15, 5), numpy.int64)
la.fill(True)
self.assertTrue(self.test.callLongMethod(la))
fa = numpy.zeros((15, 5), numpy.float32)
fa.fill(True)
self.assertTrue(self.test.callFloatMethod(fa))
da = numpy.zeros((15, 5), numpy.float64)
da.fill(True)
self.assertTrue(self.test.callDoubleMethod(da))

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,15 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 c-style: "K&R" -*- */
/*
/*
jep - Java Embedded Python
Copyright (c) 2004 - 2008 Mike Johnson.
Copyright (c) 2004 - 2011 Mike Johnson.
This file is licenced under the the zlib/libpng License.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
@ -23,8 +23,8 @@
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
distribution.
*/
// shut up the compiler
@ -37,12 +37,13 @@
#endif
#include <Python.h>
// added by njensen
#include "numpy/arrayobject.h"
#ifndef _Included_util
#define _Included_util
#ifndef USE_NUMPY
#define USE_NUMPY 1
#endif
#define JEPEXCEPTION "jep/JepException"
#define THROW_JEP(env, msg) \
@ -109,13 +110,6 @@ void release_utf_char(JNIEnv*, jstring, const char*);
// int param is printTrace, send traceback to stderr
int process_py_exception(JNIEnv*, int);
// added by njensen
static void initNumpy(void);
static int numpyInited = 0;
jarray numpyToJavaArray(JNIEnv*, PyObject*, jclass);
jarray pylistToJStringList(JNIEnv*, PyObject*);
PyObject* javaToNumpyArray(JNIEnv*, jobject, npy_intp*);
// convert java exception to pyerr.
// true (1) if an exception was processed.
int process_java_exception(JNIEnv*);
@ -132,10 +126,16 @@ int get_jtype(JNIEnv*, jobject, jclass);
int pyarg_matches_jtype(JNIEnv*, PyObject*, jclass, int);
PyObject* convert_jobject(JNIEnv*, jobject, int);
jvalue convert_pyarg_jvalue(JNIEnv*, PyObject*, jclass, int, int);
jvalue convert_pynumpyarg_jvalue(JNIEnv*, PyObject*, jclass, int, int);
PyObject* tuplelist_getitem(PyObject*, PyObject*);
#if USE_NUMPY
int npy_array_check(PyObject*);
int jndarray_check(JNIEnv*, jobject, jclass);
jobject convert_pyndarray_jndarray(JNIEnv*, PyObject*);
PyObject* convert_jndarray_pyndarray(JNIEnv*, jobject, jclass);
#endif
#define JBOOLEAN_ID 0
#define JINT_ID 1
#define JLONG_ID 2
@ -163,13 +163,14 @@ extern jclass JCHAR_TYPE;
extern jclass JBYTE_TYPE;
extern jclass JCLASS_TYPE;
// added by njensen
#if USE_NUMPY
extern jclass JBOOLEAN_ARRAY_TYPE;
extern jclass JBYTE_ARRAY_TYPE;
extern jclass JSHORT_ARRAY_TYPE;
extern jclass JINT_ARRAY_TYPE;
extern jclass JLONG_ARRAY_TYPE;
extern jclass JBOOLEAN_ARRAY_TYPE;
extern jclass JDOUBLE_ARRAY_TYPE;
extern jclass JFLOAT_ARRAY_TYPE;
extern jclass JBYTE_ARRAY_TYPE;
extern jclass JDOUBLE_ARRAY_TYPE;
#endif
#endif // ifndef _Included_util