Source code for wolframclient.serializers.wxfencoder.wxfnumpyencoder
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
from wolframclient.serializers.wxfencoder.constants import ARRAY_TYPES
from wolframclient.serializers.wxfencoder.wxfencoder import WXFEncoder
from wolframclient.serializers.wxfencoder.wxfexpr import (
WXFExprNumericArray,
WXFExprPackedArray,
)
from wolframclient.utils.api import numpy
__all__ = ["NumPyWXFEncoder"]
[docs]class NumPyWXFEncoder(WXFEncoder):
"""
NumPy array encoder. Encode numpy array as instances of packed array and / or raw array.
By default only packed arrays are generated. Unsigned integer data are cast to a type that
can fit the maximum value.
It's possible to add support for raw arrays only for unsigned data, in which case both
`packed_array_support` and `numeric_array_support` must be true.
>>> NumPyWXFEncoder(packed_array_support=True, numeric_array_support=True)
Finally it's possible to only output raw arrays with:
>>> NumPyWXFEncoder(packed_array_support=False, numeric_array_support=True)
"""
def __init__(self, packed_array_support=True, numeric_array_support=False):
if not packed_array_support and not numeric_array_support:
raise ValueError(
"At least one of the two parameters packed_array_support or numeric_array_support must be True."
)
self.packed_array_support = packed_array_support
self.numeric_array_support = numeric_array_support
[docs] def encode(self, python_expr):
if isinstance(python_expr, numpy.ndarray):
if self.packed_array_support:
array_class = WXFExprPackedArray
else:
array_class = WXFExprNumericArray
if python_expr.dtype == numpy.int8:
value_type = ARRAY_TYPES.Integer8
data = python_expr.astype("<i1")
elif python_expr.dtype == numpy.int16:
data = python_expr.astype("<i2")
value_type = ARRAY_TYPES.Integer16
elif python_expr.dtype == numpy.int32:
data = python_expr.astype("<i4")
value_type = ARRAY_TYPES.Integer32
elif python_expr.dtype == numpy.int64:
data = python_expr.astype("<i8")
value_type = ARRAY_TYPES.Integer64
elif python_expr.dtype == numpy.uint8:
if self.numeric_array_support:
value_type = ARRAY_TYPES.UnsignedInteger8
data = python_expr.astype("<u1")
array_class = WXFExprNumericArray
else:
value_type = ARRAY_TYPES.Integer16
data = python_expr.astype("<i2")
elif python_expr.dtype == numpy.uint16:
if self.numeric_array_support:
value_type = ARRAY_TYPES.UnsignedInteger16
data = python_expr.astype("<u2")
array_class = WXFExprNumericArray
else:
value_type = ARRAY_TYPES.Integer32
data = python_expr.astype("<i4")
elif python_expr.dtype == numpy.uint32:
if self.numeric_array_support:
value_type = ARRAY_TYPES.UnsignedInteger32
data = python_expr.astype("<u4")
array_class = WXFExprNumericArray
else:
value_type = ARRAY_TYPES.Integer64
data = python_expr.astype("<i8")
# no one to one mapping to signed values, even if most of the time
# the values would fit
elif python_expr.dtype == numpy.uint64:
if self.numeric_array_support:
value_type = ARRAY_TYPES.UnsignedInteger64
data = python_expr.astype("<u8")
array_class = WXFExprNumericArray
else:
TypeError("Cannot represent data of type uint64 as signed int64")
elif python_expr.dtype == numpy.float32:
value_type = ARRAY_TYPES.Real32
data = python_expr
elif python_expr.dtype == numpy.float64:
value_type = ARRAY_TYPES.Real64
data = python_expr
elif python_expr.dtype == numpy.complex64:
value_type = ARRAY_TYPES.ComplexReal32
data = python_expr
elif python_expr.dtype == numpy.complex128:
value_type = ARRAY_TYPES.ComplexReal64
data = python_expr
else:
raise NotImplementedError(
"NumPy serialization not implemented for %s" % repr(python_expr.dtype)
)
if hasattr(data, "tobytes"):
# Numpy 1.9+ support array.tobytes, but previous versions don't and use tostring instead.
yield array_class(python_expr.shape, value_type, data.tobytes())
else:
yield array_class(python_expr.shape, value_type, data.tostring())