Skip to content

Instantly share code, notes, and snippets.

@CitizenInsane
Last active September 23, 2021 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CitizenInsane/c8d3ddc5b14faceec433af3e940e22a8 to your computer and use it in GitHub Desktop.
Save CitizenInsane/c8d3ddc5b14faceec433af3e940e22a8 to your computer and use it in GitHub Desktop.
Marshalling of numpy.ndarray (Python world) with System.Array (.NET world)
"""
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
#}
@CitizenInsane
Copy link
Author

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

  • First time I'm coding in python sorry if syntax is not so conventional ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment