Last active
September 23, 2021 12:39
-
-
Save CitizenInsane/c8d3ddc5b14faceec433af3e940e22a8 to your computer and use it in GitHub Desktop.
Marshalling of numpy.ndarray (Python world) with System.Array (.NET world)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Helper module for marshalling Python types with .NET types | |
""" | |
import numpy | |
import ctypes | |
import clr, System | |
clr.AddReference("System.Runtime") | |
clr.AddReference("System.Runtime.Numerics") | |
## Marshalling NumPy <==> .NET | |
def ToDotNetArray(npArray: numpy.ndarray) -> System.Array: | |
#{ | |
""" | |
PURPOSE: | |
Converts a NumPy array to a .NET array. | |
SYNOPSIS: | |
netArray = ToDotNetArray(npArray) | |
INPUTS: | |
'npArray': The NumPy array to convert | |
OUTPUT: | |
'netArray': Resulting .NET array | |
REMARKS: | |
Adapted from PythonNet discussions: | |
- https://github.com/pythonnet/pythonnet/issues/514 | |
- https://github.com/pythonnet/pythonnet/issues/652 | |
- https://gist.github.com/robbmcleod/73ca42da5984e6d0e5b6ad28bc4a504e | |
""" | |
NP2NET = { | |
numpy.dtype(numpy.complex128) : System.Numerics.Complex, # NP.Complex(double) => NET.Complex(double) | |
numpy.dtype(numpy.complex64) : System.Numerics.Complex, # NP.Complex(float) => NET.Complex(double) | |
numpy.dtype(numpy.float64) : System.Double, | |
numpy.dtype(numpy.float32) : System.Single, | |
numpy.dtype(numpy.int64) : System.Int64, | |
numpy.dtype(numpy.int32) : System.Int32, | |
numpy.dtype(numpy.int16) : System.Int16, | |
numpy.dtype(numpy.int8) : System.SByte, | |
numpy.dtype(numpy.uint64) : System.UInt64, | |
numpy.dtype(numpy.uint32) : System.UInt32, | |
numpy.dtype(numpy.uint16) : System.UInt16, | |
numpy.dtype(numpy.uint8) : System.Byte, | |
numpy.dtype(numpy.bool) : System.Boolean, | |
} | |
if (npArray.dtype == numpy.dtype('complex64')): npArray = npArray.astype(numpy.dtype('complex128')) | |
if (not npArray.flags.c_contiguous or not npArray.flags.aligned): npArray = numpy.ascontiguousarray(npArray) | |
assert npArray.flags.c_contiguous | |
try: netArray = System.Array.CreateInstance(NP2NET[npArray.dtype], *(npArray.shape)) | |
except KeyError: raise NotImplementedError("Numpy arrays of type {} are yet not supported.".format(npArray.dtype)) | |
try: | |
destHandle = System.Runtime.InteropServices.GCHandle.Alloc(netArray, System.Runtime.InteropServices.GCHandleType.Pinned) | |
sourcePtr = npArray.__array_interface__['data'][0] | |
destPtr = destHandle.AddrOfPinnedObject().ToInt64() | |
ctypes.memmove(destPtr, sourcePtr, npArray.nbytes) | |
finally: | |
if (destHandle.IsAllocated): destHandle.Free() | |
return netArray | |
#} | |
def FromDotNetArray(netArray: System.Array) -> numpy.ndarray: | |
#{ | |
""" | |
PURPOSE: | |
Converts a .NET array to a NumPy array. | |
SYNOPSIS: | |
npArray = FromDotNetArray(netArray) | |
INPUTS: | |
'netArray': The .NET array to convert | |
OUTPUT: | |
'nptArray': Resulting NumPy array | |
REMARKS: | |
Adapted from PythonNet discussions: | |
- https://github.com/pythonnet/pythonnet/issues/514 | |
- https://github.com/pythonnet/pythonnet/issues/652 | |
- https://gist.github.com/robbmcleod/73ca42da5984e6d0e5b6ad28bc4a504e | |
""" | |
NET2NP = { | |
"System.Numerics.Complex" : numpy.dtype(numpy.complex128), | |
"System.Double" : numpy.dtype(numpy.float64), | |
"System.Single" : numpy.dtype(numpy.float32), | |
"System.Int64" : numpy.dtype(numpy.int64), | |
"System.Int32" : numpy.dtype(numpy.int32), | |
"System.Int16" : numpy.dtype(numpy.int16), | |
"System.SByte" : numpy.dtype(numpy.int8), | |
"System.UInt64" : numpy.dtype(numpy.uint64), | |
"System.UInt32" : numpy.dtype(numpy.uint32), | |
"System.UInt16" : numpy.dtype(numpy.uint16), | |
"System.Byte" : numpy.dtype(numpy.uint8), | |
"System.Boolean" : numpy.dtype(numpy.bool), | |
} | |
dims = numpy.empty(netArray.Rank, dtype=int) | |
for i in range(netArray.Rank): dims[i] = netArray.GetLength(i) | |
netElementType = netArray.GetType().GetElementType().FullName | |
try: npArray = numpy.empty(dims, order='C', dtype=NET2NP[netElementType]) | |
except KeyError: raise NotImplementedError(f'Net arrays of type {netElementType} are yet not supported.') | |
try: | |
sourceHandle = System.Runtime.InteropServices.GCHandle.Alloc(netArray, System.Runtime.InteropServices.GCHandleType.Pinned) | |
sourcePtr = sourceHandle.AddrOfPinnedObject().ToInt64() | |
destPtr = npArray.__array_interface__['data'][0] | |
ctypes.memmove(destPtr, sourcePtr, npArray.nbytes) | |
finally: | |
if sourceHandle.IsAllocated: sourceHandle.Free() | |
return npArray | |
#} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Adapted from: https://gist.github.com/robbmcleod/73ca42da5984e6d0e5b6ad28bc4a504e
Difference: Numpy Complex arrays (python) now directly marshall with System.Array (.NET) whose element type is System.Numerics.Complex