What List-like structures in Python can Wolfram Client handle and how can support for new structures be added?
In this answer I describe how to execute from Python, code in a Mathematica package that that has been compiled to C.
One such compiled function for test purposes is this:
compiledTestFunction2 =
Compile[{{n, _Real, 1}, {m, _Real, 1}},
Module[{},
Cross[n, m]
],
CompilationTarget->"C", "RuntimeOptions"->"Speed"];
(Cross[] is compilable). This function is called from Python by defining
compiledTestFunctionPython2 = session.function('compiledTestFunction2')
And the function is invoked as
compiledTestFunctionPython2(thing1, thing2)
Using Wolfram Language functions via Wolfram Client to Wolfram Engine we obtain a reference result:
thing1 = array.array('f', [1,2,3])
thing2 = array.array('f',[2,3.3,7])
session.evaluate(wl.Cross(thing1, thing2))
PackedArray([ 4.1, -1. , -0.7])
We obtain the correct answer if we define thing1 and thing2 as Python:
- Lists e.g. [1, 2, 3]
- Arrays e.g. array.array('f', [1, 2, 3])
- Tuples e.g. (1, 2, 3), and even
- Sets e.g. set([1, 2, 3]) despite the lack of ostensible order to sets
but Numpy arrays are not supported. Attempting to use a Numpy array such as
thing1 = np.array([1.0, 2.0, 3.0])
causes the compiled function to be returned unevaluated with the error:
Argument … at position 1 should be a rank 1 tensor of machine-size real numbers.
Questions What array types does Wolfram Client handle and could support for other structures such as Numpy arrays be added; if so, how? (The documentation says Numpy is supported, but does it work for compiled functions?)
And although PackedArray([...]) is returned by default, is there any choice in the matter?
Update on passing in 26/11/2019
By trying to force Numpy arrays to be of a particular data type, using
thing1 = np.array([1.0, 2.0., 3.0], dtype = np.float16)
we discover, from the Not Supported Error for dtype('float16'), that Wolfram Client serialisation (in \wolframclient\serializers\encoders\numpy.py) supports the following: int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128
However, no explicit float choices are acceptable to the compiled function.
It looks as though any existing numpy array must be coerced back to some other form, and after a few experiments it seems that the most efficient way is e.g.
thing1 = np.array([1.0, 2.0, 3.0], dtype = np.float64)
thing1 = array.array('d', thing1)
but the differences between array, list and tuple are small.
Update on receiving back 26/11/2019
According to the documentation here
By default, packed arrays are deserialized as list. Specify a consumer instance that supports NumPy arrays WXFConsumerNumpy
If one then prepares a session with
session = WolframLanguageSession(kernelLoc, consumer=WXFConsumerNumpy())
then my compiled function that returns a 1D (table) of reals appears back in Python as class 'wolframclient.utils.packedarray.PackedArray' - not numpy array. Why?
I have yet to find the list of deserializers.