From 52bef206878a4384b43494243dd39813b2bdf5ad Mon Sep 17 00:00:00 2001 From: tuorjr Date: Mon, 26 Sep 2016 15:33:15 +0000 Subject: [PATCH] Initial commit of Python Integration feature. git-svn-id: https://www.simantics.org/svn/simantics-incubator/reino@1689 e36c2e66-7d30-0410-bdb2-d9e1f5a6d952 --- org.simantics.pythonlink.feature/.project | 17 +++ .../build.properties | 1 + org.simantics.pythonlink.feature/feature.xml | 44 ++++++++ .../.classpath | 7 ++ .../.project | 28 +++++ .../.settings/org.eclipse.jdt.core.prefs | 7 ++ .../.settings/org.eclipse.pde.core.prefs | 4 + .../META-INF/MANIFEST.MF | 7 ++ .../build.properties | 8 ++ org.simantics.pythonlink/.classpath | 8 ++ org.simantics.pythonlink/.project | 28 +++++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 7 ++ org.simantics.pythonlink/META-INF/MANIFEST.MF | 15 +++ org.simantics.pythonlink/build.properties | 6 + .../scl/Simantics/Python.scl | 104 ++++++++++++++++++ .../org/simantics/pythonlink/Activator.java | 31 ++++++ .../src/org/simantics/pythonlink/NDArray.java | 93 ++++++++++++++++ .../src/org/simantics/pythonlink/Python.java | 39 +++++++ .../simantics/pythonlink/PythonContext.java | 94 ++++++++++++++++ .../pythonlink/test/ScriptTestBase.java | 36 ++++++ .../pythonlink/test/ScriptTests.java | 16 +++ .../pythonlink/test/TestPythonlink.java | 104 ++++++++++++++++++ .../pythonlink/test/scripts/Python.sts | 48 ++++++++ 24 files changed, 754 insertions(+) create mode 100644 org.simantics.pythonlink.feature/.project create mode 100644 org.simantics.pythonlink.feature/build.properties create mode 100644 org.simantics.pythonlink.feature/feature.xml create mode 100644 org.simantics.pythonlink.win32.x86_64/.classpath create mode 100644 org.simantics.pythonlink.win32.x86_64/.project create mode 100644 org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs create mode 100644 org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF create mode 100644 org.simantics.pythonlink.win32.x86_64/build.properties create mode 100644 org.simantics.pythonlink/.classpath create mode 100644 org.simantics.pythonlink/.project create mode 100644 org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs create mode 100644 org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.simantics.pythonlink/META-INF/MANIFEST.MF create mode 100644 org.simantics.pythonlink/build.properties create mode 100644 org.simantics.pythonlink/scl/Simantics/Python.scl create mode 100644 org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java create mode 100644 org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java create mode 100644 org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java create mode 100644 org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java create mode 100644 org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java create mode 100644 org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java create mode 100644 org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java create mode 100644 org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts diff --git a/org.simantics.pythonlink.feature/.project b/org.simantics.pythonlink.feature/.project new file mode 100644 index 0000000..a854e6e --- /dev/null +++ b/org.simantics.pythonlink.feature/.project @@ -0,0 +1,17 @@ + + + org.simantics.pythonlink.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/org.simantics.pythonlink.feature/build.properties b/org.simantics.pythonlink.feature/build.properties new file mode 100644 index 0000000..82ab19c --- /dev/null +++ b/org.simantics.pythonlink.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.simantics.pythonlink.feature/feature.xml b/org.simantics.pythonlink.feature/feature.xml new file mode 100644 index 0000000..97bea75 --- /dev/null +++ b/org.simantics.pythonlink.feature/feature.xml @@ -0,0 +1,44 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + + + + + + + diff --git a/org.simantics.pythonlink.win32.x86_64/.classpath b/org.simantics.pythonlink.win32.x86_64/.classpath new file mode 100644 index 0000000..b862a29 --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.pythonlink.win32.x86_64/.project b/org.simantics.pythonlink.win32.x86_64/.project new file mode 100644 index 0000000..26bdfea --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/.project @@ -0,0 +1,28 @@ + + + org.simantics.pythonlink.win32.x86_64 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..295926d --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..d711c29 --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +pluginProject.equinox=false +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF b/org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF new file mode 100644 index 0000000..166dc32 --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-SymbolicName: org.simantics.pythonlink.win32.x86_64 +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: VTT Technical Research Centre of Finland +Fragment-Host: org.simantics.pythonlink;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/org.simantics.pythonlink.win32.x86_64/build.properties b/org.simantics.pythonlink.win32.x86_64/build.properties new file mode 100644 index 0000000..2d0d26e --- /dev/null +++ b/org.simantics.pythonlink.win32.x86_64/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + jnimatlab.dll,\ + jnipython.dll +src.includes = jnimatlab.dll,\ + jnipython.dll diff --git a/org.simantics.pythonlink/.classpath b/org.simantics.pythonlink/.classpath new file mode 100644 index 0000000..069739a --- /dev/null +++ b/org.simantics.pythonlink/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.simantics.pythonlink/.project b/org.simantics.pythonlink/.project new file mode 100644 index 0000000..01b4044 --- /dev/null +++ b/org.simantics.pythonlink/.project @@ -0,0 +1,28 @@ + + + org.simantics.pythonlink + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs b/org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..375bd7b --- /dev/null +++ b/org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//test/org/simantics/pythonlink/test/TestPythonlink.java=UTF-8 diff --git a/org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs b/org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..295926d --- /dev/null +++ b/org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.simantics.pythonlink/META-INF/MANIFEST.MF b/org.simantics.pythonlink/META-INF/MANIFEST.MF new file mode 100644 index 0000000..14c621b --- /dev/null +++ b/org.simantics.pythonlink/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Pythonlink +Bundle-SymbolicName: org.simantics.pythonlink +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.junit, + org.eclipse.osgi, + org.simantics.scl.runtime, + gnu.trove3;bundle-version="3.0.3", + org.simantics.scl.compiler, + org.simantics.scl.osgi +Export-Package: org.simantics.pythonlink +Bundle-Activator: org.simantics.pythonlink.Activator +Bundle-ActivationPolicy: lazy diff --git a/org.simantics.pythonlink/build.properties b/org.simantics.pythonlink/build.properties new file mode 100644 index 0000000..840ba6a --- /dev/null +++ b/org.simantics.pythonlink/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + scl/ +src.includes = scl/ \ No newline at end of file diff --git a/org.simantics.pythonlink/scl/Simantics/Python.scl b/org.simantics.pythonlink/scl/Simantics/Python.scl new file mode 100644 index 0000000..899f577 --- /dev/null +++ b/org.simantics.pythonlink/scl/Simantics/Python.scl @@ -0,0 +1,104 @@ +import "Vector" + +effect Python + "Simantics/Python/Python" + "org.simantics.pythonlink.PythonContext" + +class PythonCompatible a where + setPythonVariable :: String -> a -> () + getPythonVariable :: String -> a + +importJava "org.simantics.pythonlink.NDArray" where + data NDArray + + @JavaName "" + ndarray :: Vector Double -> NDArray + @JavaName "" + ndarrayM :: Integer -> Integer -> Vector Double -> NDArray + @JavaName "" + ndarrayN :: Vector Integer -> Vector Double -> NDArray + + @JavaName size + ndarraySize :: NDArray -> Integer + @JavaName dims + ndarrayDims :: NDArray -> Vector Integer + @JavaName getValues + ndarrayValues :: NDArray -> Vector Double + @JavaName getValue + ndarrayElement :: NDArray -> Integer -> Double + @JavaName getValue + ndarrayElementM :: NDArray -> Integer -> Integer -> Double + @JavaName getValue + ndarrayElementN :: NDArray -> Vector Integer -> Double + + @JavaName toString + ndarrayToString :: NDArray -> String + @JavaName equals + ndarrayEquals :: NDArray -> NDArray -> Boolean + +instance Show NDArray where + show = ndarrayToString + +importJava "org.simantics.pythonlink.PythonContext" where + data PythonContext + + @JavaName close + closePythonContext :: PythonContext -> () + + executePythonStatement :: String -> Integer + + setPythonIntegerVariable :: String -> Integer -> () + setPythonIntegerArrayVariable :: String -> Vector Integer -> () + setPythonDoubleVariable :: String -> Double -> () + setPythonDoubleArrayVariable :: String -> Vector Double -> () + setPythonStringVariable :: String -> String -> () + setPythonStringArrayVariable :: String -> Vector String -> () + setPythonNDArrayVariable :: String -> NDArray -> () + + getPythonIntegerVariable :: String -> Integer + getPythonIntegerArrayVariable :: String -> Vector Integer + getPythonDoubleVariable :: String -> Double + getPythonDoubleArrayVariable :: String -> Vector Double + getPythonStringVariable :: String -> String + getPythonStringArrayVariable :: String -> Vector String + getPythonNDArrayVariable :: String -> NDArray + + runPythonF :: (() -> a) -> a + runWithPythonContextF :: PythonContext -> (() -> a) -> a + +importJava "org.simantics.pythonlink.Python" where + openPythonContext :: () -> PythonContext + +runPython :: ( a) -> a +runPython v = runPythonF (\_ -> v) + +runWithPythonContext :: PythonContext -> ( a) -> a +runWithPythonContext python v = runWithPythonContextF python (\_ -> v) + +instance PythonCompatible Double where + setPythonVariable = setPythonDoubleVariable + getPythonVariable = getPythonDoubleVariable + +instance PythonCompatible (Vector Double) where + setPythonVariable = setPythonDoubleArrayVariable + getPythonVariable = getPythonDoubleArrayVariable + +instance PythonCompatible Integer where + setPythonVariable = setPythonIntegerVariable + getPythonVariable = getPythonIntegerVariable + +instance PythonCompatible (Vector Integer) where + setPythonVariable = setPythonIntegerArrayVariable + getPythonVariable = getPythonIntegerArrayVariable + +instance PythonCompatible String where + setPythonVariable = setPythonStringVariable + getPythonVariable = getPythonStringVariable + +instance PythonCompatible (Vector String) where + setPythonVariable = setPythonStringArrayVariable + getPythonVariable = getPythonStringArrayVariable + +instance PythonCompatible NDArray where + setPythonVariable = setPythonNDArrayVariable + getPythonVariable = getPythonNDArrayVariable diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java new file mode 100644 index 0000000..83633a4 --- /dev/null +++ b/org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java @@ -0,0 +1,31 @@ +package org.simantics.pythonlink; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + System.loadLibrary("jnipython"); + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java new file mode 100644 index 0000000..69506e9 --- /dev/null +++ b/org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java @@ -0,0 +1,93 @@ +package org.simantics.pythonlink; + +import java.util.Arrays; + +public class NDArray { + int[] dims; + double[] value; + + public NDArray(double[] value) { + this.value = value; + dims = new int[] { value.length }; + } + + public NDArray(int m, int n, double[] value) { + if (n*m != value.length) throw new IllegalArgumentException("Invalid dimensions for data vector"); + + this.value = value; + dims = new int[] { m, n }; + } + + public NDArray(int[] dims, double[] value) { + int l = dims.length > 0 ? 1 : 0; + for (int d : dims) l *= d; + if (l != value.length) throw new IllegalArgumentException("Invalid dimensions for data vector"); + + this.dims = dims; + this.value = value; + } + + public int size() { return value.length; } + public int[] dims() { return dims; } + public double[] getValues() { return value; } + + public double getValue(int index) { return value[index]; } + public double getValue(int i, int j) { + if (dims.length != 2) throw new IllegalArgumentException("Invalid indices for array of dimension " + dims.length); + + return value[dims[1] * i + j]; + } + public double getValue(int... is) { + if (dims.length != is.length) throw new IllegalArgumentException("Invalid indices for array of dimension " + dims.length); + + int index = 0; + for (int k = 0; k < dims.length; k++) { + index = dims[k] * index + is[k]; + } + return value[index]; + } + + @Override + public boolean equals( Object o ) { + return o instanceof NDArray && + Arrays.equals(dims, ((NDArray)o).dims) && + Arrays.equals(value, ((NDArray)o).value); + } + + @Override + public int hashCode() { + return Arrays.hashCode(dims) + 11 * Arrays.hashCode(value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ndarray("); + for (int i = 0; i < dims.length; i++) { + if (i > 0) sb.append('x'); + sb.append(dims[i]); + } + sb.append(") "); + + if (dims.length > 0) + buildString(sb, 0, 0); + else + sb.append("[]"); + return sb.toString(); + } + + private void buildString( StringBuilder sb, int d, int i ) { + if (d == dims.length) { + sb.append(value[i]); + } + else { + i *= dims[d]; + sb.append('['); + for (int j = 0; j < dims[d]; j++) { + if (j > 0) sb.append(", "); + buildString(sb, d+1, i + j); + } + sb.append(']'); + } + } +} diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java new file mode 100644 index 0000000..af5c9e2 --- /dev/null +++ b/org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java @@ -0,0 +1,39 @@ +package org.simantics.pythonlink; + +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function; +import org.simantics.scl.runtime.tuple.Tuple0; + +public class Python { + private static final String PYTHON_CONTEXT = "Simantics/Python/Python"; + + public static PythonContext openPythonContext() { + return new PythonContext(); + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public static Object runPython(Function f) { + SCLContext sclContext = SCLContext.getCurrent(); + Object oldContext = sclContext.get(PYTHON_CONTEXT); + try (PythonContext newContext = openPythonContext()) { + sclContext.put(PYTHON_CONTEXT, newContext); + return f.apply(Tuple0.INSTANCE); + } + finally { + sclContext.put(PYTHON_CONTEXT, oldContext); + } + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public static Object runWithPythonContext(PythonContext context, Function f) { + SCLContext sclContext = SCLContext.getCurrent(); + Object oldContext = sclContext.get(PYTHON_CONTEXT); + try { + sclContext.put(PYTHON_CONTEXT, context); + return f.apply(Tuple0.INSTANCE); + } + finally { + sclContext.put(PYTHON_CONTEXT, oldContext); + } + } +} diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java new file mode 100644 index 0000000..d237c83 --- /dev/null +++ b/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java @@ -0,0 +1,94 @@ +package org.simantics.pythonlink; + +import java.io.Closeable; + +public class PythonContext implements Closeable { + private long contextID; + + PythonContext() { + contextID = openPythonContextImpl(); + } + + @Override + public void close() { + long id = contextID; + contextID = 0; + closePythonContextImpl(id); + } + + public void executePythonStatement(String statement) { + executePythonStatementImpl( contextID, statement ); + } + + public void setPythonIntegerVariable(String variableName, int value) { + setPythonIntegerVariableImpl(contextID, variableName, value); + } + public void setPythonDoubleVariable(String variableName, double value) { + setPythonDoubleVariableImpl(contextID, variableName, value); + } + public void setPythonStringVariable(String variableName, String value) { + setPythonStringVariableImpl(contextID, variableName, value); + } + + public void setPythonIntegerArrayVariable(String variableName, int[] value) { + setPythonIntegerArrayVariableImpl(contextID, variableName, value); + } + public void setPythonDoubleArrayVariable(String variableName, double[] value) { + setPythonDoubleArrayVariableImpl(contextID, variableName, value); + } + public void setPythonStringArrayVariable(String variableName, String[] value) { + setPythonStringArrayVariableImpl(contextID, variableName, value); + } + + public int getPythonIntegerVariable(String variableName) { + return getPythonIntegerVariableImpl(contextID, variableName); + } + public double getPythonDoubleVariable(String variableName) { + return getPythonDoubleVariableImpl(contextID, variableName); + } + public String getPythonStringVariable(String variableName) { + return getPythonStringVariableImpl(contextID, variableName); + } + + public int[] getPythonIntegerArrayVariable(String variableName) { + return getPythonIntegerArrayVariableImpl(contextID, variableName); + } + public double[] getPythonDoubleArrayVariable(String variableName) { + return getPythonDoubleArrayVariableImpl(contextID, variableName); + } + public String[] getPythonStringArrayVariable(String variableName) { + return getPythonStringArrayVariableImpl(contextID, variableName); + } + + public void setPythonNDArrayVariable(String variableName, NDArray value) { + setPythonNDArrayVariableImpl(contextID, variableName, value); + } + public NDArray getPythonNDArrayVariable(String variableName) { + return getPythonNDArrayVariableImpl(contextID, variableName); + } + + // Native function declarations + private static native long openPythonContextImpl(); + private static native void closePythonContextImpl(long contextID); + + private static native void executePythonStatementImpl(long contextID, String statement); + + private static native void setPythonIntegerVariableImpl(long contextID, String variableName, int value); + private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value); + private static native void setPythonStringVariableImpl(long contextID, String variableName, String value); + + private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value); + private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value); + private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value); + + private static native int getPythonIntegerVariableImpl(long contextID, String variableName); + private static native double getPythonDoubleVariableImpl(long contextID, String variableName); + private static native String getPythonStringVariableImpl(long contextID, String variableName); + + private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName); + private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName); + private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName); + + private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value); + private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName); +} diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java new file mode 100644 index 0000000..6328fec --- /dev/null +++ b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java @@ -0,0 +1,36 @@ +package org.simantics.pythonlink.test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +import org.junit.Before; +import org.simantics.scl.compiler.commands.CommandSession; +import org.simantics.scl.compiler.commands.TestScriptExecutor; +import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.compiler.source.repository.CompositeModuleSourceRepository; +import org.simantics.scl.compiler.source.repository.SourceRepositories; +import org.simantics.scl.osgi.SCLOsgi; +import org.simantics.scl.osgi.internal.ServiceBasedModuleSourceRepository; + +public class ScriptTestBase { + + private final String path; + + public ScriptTestBase(String path) { + this.path = path; + } + + protected void test() throws Exception { + String testScriptName = Thread.currentThread().getStackTrace()[2].getMethodName(); + String testPath = path + "/" + testScriptName + ".sts"; + + CommandSession session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, null); + new TestScriptExecutor(session, + new BufferedReader( + new InputStreamReader(getClass().getResourceAsStream(testPath), Charset.forName("UTF-8"))), + null) + .execute(); + } + +} diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java new file mode 100644 index 0000000..4c5318a --- /dev/null +++ b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java @@ -0,0 +1,16 @@ +package org.simantics.pythonlink.test; + +import org.junit.Test; + +public class ScriptTests extends ScriptTestBase { + + public ScriptTests() { + super("scripts"); + } + + @Test public void Arithmetic() throws Exception { test(); } + @Test public void Functions() throws Exception { test(); } + @Test public void Functions2() throws Exception { test(); } + @Test public void Lists() throws Exception { test(); } + +} diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java new file mode 100644 index 0000000..bc6379d --- /dev/null +++ b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java @@ -0,0 +1,104 @@ +package org.simantics.pythonlink.test; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.simantics.pythonlink.NDArray; +import org.simantics.pythonlink.Python; +import org.simantics.pythonlink.PythonContext; + +public class TestPythonlink { + PythonContext python; + + @Before + public void setUp() throws Exception { + python = Python.openPythonContext(); + } + + @After + public void tearDown() throws Exception { + python.close(); + } + + @Test + public void testInteger() { + int input = 4; + python.setPythonIntegerVariable( "foo", input ); + python.executePythonStatement( "bar = foo // 2" ); + int output = python.getPythonIntegerVariable( "bar" ); + assertEquals( input / 2, output, 0.0 ); + } + + @Test + public void testIntegerArray() { + int[] input = new int[] { 1, 2 }; + python.setPythonIntegerArrayVariable( "foo", input ); + python.executePythonStatement( "bar = foo\nbar.append(3)" ); + int[] output = python.getPythonIntegerArrayVariable( "bar" ); + assertArrayEquals( new int[] { 1, 2, 3 }, output ); + } + + @Test + public void testDouble() { + double input = 2.5; + python.setPythonDoubleVariable( "foo", input ); + python.executePythonStatement( "bar = foo / 2" ); + double output = python.getPythonDoubleVariable( "bar" ); + assertEquals( input / 2, output, 0.0 ); + } + + @Test + public void testDoubleArray() { + double[] input = new double[] { 1.0, 2.0 }; + python.setPythonDoubleArrayVariable( "foo", input ); + python.executePythonStatement( "bar = foo\nbar.append(3.0)" ); + double[] output = python.getPythonDoubleArrayVariable( "bar" ); + assertArrayEquals( new double[] { 1.0, 2.0, 3.0 }, output, 0.0 ); + } + + @Test + public void testString() { + String input = "Foo"; + python.setPythonStringVariable( "foo", input ); + python.executePythonStatement( "bar = foo + 'bar!'" ); + String output = python.getPythonStringVariable( "bar" ); + assertEquals( "Foobar!", output ); + } + + @Test + public void testStringArray() { + String[] input = new String[] { "Foo" }; + python.setPythonStringArrayVariable( "foo", input ); + python.executePythonStatement( "bar = foo + ['bar!']" ); + String[] output = python.getPythonStringArrayVariable( "bar" ); + assertArrayEquals( new String[] { "Foo", "bar!" }, output ); + } + + @Test + public void testNumpyArrays() { + NDArray data = new NDArray(new int[] { 2, 3 }, new double[] { 1, 2, 3, 4, 5, 6 }); + python.executePythonStatement( "import numpy" ); + python.setPythonNDArrayVariable( "foo", data ); + python.executePythonStatement( "bar = foo.cumsum(axis = 0)" ); + NDArray result = python.getPythonNDArrayVariable( "bar" ); + assertEquals(new NDArray(new int[] { 2, 3 }, new double[] { 1, 2, 3, 5, 7, 9 }), result); + assertEquals(5, result.getValue( 1, 0 ), 0.0); + assertEquals(3, result.getValue( 0, 2 ), 0.0); + assertEquals(9, result.getValue( 1, 2 ), 0.0); + } + + @Test + public void testNumpyArrays3() { + NDArray data = new NDArray(new int[] { 3, 2, 2 }, new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }); + python.executePythonStatement( "import numpy" ); + python.setPythonNDArrayVariable( "foo", data ); + python.executePythonStatement( "bar = numpy.ndarray(shape = (3,2,2), order='f')" ); + python.executePythonStatement( "bar.flat = foo.cumsum(axis = 1).flat" ); + NDArray result = python.getPythonNDArrayVariable( "bar" ); + assertEquals(new NDArray(new int[] { 3, 2, 2 }, new double[] { 1, 2, 4, 6, 5, 6, 12, 14, 9, 10, 20, 22 }), result); + assertEquals(10, result.getValue( 2, 0, 1 ), 0.0); + assertEquals(12, result.getValue( 1, 1, 0 ), 0.0); + } +} diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts new file mode 100644 index 0000000..409d9b2 --- /dev/null +++ b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts @@ -0,0 +1,48 @@ +> import "Simantics/Python" +> import "Vector" +> +> runPython do +> executePythonStatement "foo = 'bar'\nd = dir()" +> getPythonStringArrayVariable "d" +vector ["__builtins__", "__doc__", "__loader__", "__name__", "__package__", "__spec__", "foo"] +> runPython do +> setPythonDoubleVariable "foo" 1 +> executePythonStatement "foo = foo + 1" +> getPythonDoubleVariable "foo" +2.0 +> runPython do +> setPythonDoubleArrayVariable "foo" (vector [1.0, 2.0, 3.0]) +> executePythonStatement "foo = foo + [4.0]" +> getPythonDoubleArrayVariable "foo" +vector [1.0, 2.0, 3.0, 4.0] +> runPython do +> setPythonIntegerVariable "foo" 5 +> executePythonStatement "import math" +> executePythonStatement "bar = math.factorial(foo)" +> getPythonIntegerVariable "bar" +120 +> runPython do +> setPythonIntegerArrayVariable "foo" (vector [1, 2, 3, 4]) +> executePythonStatement "foo.append(sum(foo))" +> getPythonIntegerArrayVariable "foo" +vector [1, 2, 3, 4, 10] +> ndarray (vector [1, 2, 3]) +ndarray(3) [1.0, 2.0, 3.0] +> ndarrayM 2 2 (vector [1, 2, 3, 4]) +ndarray(2x2) [1.0, 2.0, 3.0, 4.0] +> a = ndarrayN (vector [2, 2, 3]) (vector [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) +> a +ndarray(2x2x3) [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, ...] +> ndarrayDims a +vector [2, 2, 3] +> ndarrayValues a +vector [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0] +> ndarrayElement a 5 +6.0 +> ndarrayElementN a (vector [0, 1, 2]) +6.0 +> runPython do +> setPythonNDArrayVariable "foo" (ndarrayM 2 3 (vector [1, 2, 3, 4, 5, 6])) +> executePythonStatement "bar = foo.cumsum(1)" +> getPythonNDArrayVariable "bar" +ndarray(2x3) [1.0, 3.0, 6.0, 4.0, 9.0, 15.0] -- 2.47.0