"""
Types definition.
:githublink:`%|py|5`
"""
import numpy
from .api_extension import AutoType
[docs]class MLType(AutoType):
"""
Base class for every type.
:githublink:`%|py|12`
"""
[docs] def validate(self, value):
"""
Checks that the value is of this type.
:githublink:`%|py|17`
"""
# It must be overwritten.
self._cache = value
[docs] def cast(self, value):
"""
Converts *value* into this type.
:githublink:`%|py|24`
"""
raise NotImplementedError() # pragma: no cover
[docs]class MLNumType(MLType):
"""
Base class for numerical types.
:githublink:`%|py|31`
"""
[docs] def _copy_c(self, src, dst, hook=None):
if hook == "typeref":
return "*{0} = {1};".format(dst, src)
return "{0} = {1};".format(dst, src)
[docs]class MLNumTypeSingle(MLNumType):
"""
int32 or float32
:githublink:`%|py|48`
"""
[docs] def __init__(self, numpy_type, name, ctype, key):
self.numpy_type = numpy_type
self.name = name
self.ctype = ctype
self.key = key
@property
def CTypeSingle(self):
"""
Returns *ctype*.
:githublink:`%|py|60`
"""
return self.ctype
[docs] def validate(self, value):
"""
Checks that the value is of this type.
:githublink:`%|py|66`
"""
MLNumType.validate(self, value)
if not isinstance(value, self.numpy_type):
raise TypeError( # pragma: no cover
"'{0}' is not a {1}.".format(
type(value), self.numpy_type))
return value
[docs] def cast(self, value):
"""
Exports *value* into this type.
:githublink:`%|py|77`
"""
if isinstance(value, numpy.float32):
raise TypeError( # pragma: no cover
"No need to cast, already a {0}".format(self.numpy_type))
if isinstance(value, numpy.ndarray):
if len(value) != 1:
raise ValueError( # pragma: no cover
"Dimension of array must be one single {0}".format(self.numpy_type))
return value[0]
raise NotImplementedError( # pragma: no cover
"Unable to cast '{0}' into a {0}".format(type(self.numpy_type)))
[docs] def softcast(self, value):
"""
Exports *value* into this type, does it anyway without verification.
:githublink:`%|py|92`
"""
if isinstance(value, numpy.ndarray):
v = value.ravel()
if len(v) != 1:
raise ValueError( # pragma: no cover
"Cannot cast shape {0} into {1}".format(
value.shape, self.numpy_type))
return self.numpy_type(v[0])
return self.numpy_type(value)
[docs] def _export_common_c(self, ctype, hook=None, result_name=None):
if hook == 'type':
return {'code': ctype} if result_name is None else {'code': ctype + ' ' + result_name}
if result_name is None:
return {'code': ctype}
return {'code': ctype + ' ' + result_name, 'result_name': result_name}
[docs] def _byref_c(self):
return "&"
[docs] def _export_json(self, hook=None, result_name=None):
return 'float32'
[docs] def _export_c(self, hook=None, result_name=None):
if hook == 'typeref':
return {'code': self.ctype + '*'} if result_name is None else {'code': self.ctype + '* ' + result_name}
return self._export_common_c(self.ctype, hook, result_name)
[docs]class MLNumTypeFloat32(MLNumTypeSingle):
"""
A numpy.float32.
:githublink:`%|py|134`
"""
[docs] def __init__(self):
MLNumTypeSingle.__init__(
self, numpy.float32, 'float32', 'float', 'float32')
[docs]class MLNumTypeFloat64(MLNumTypeSingle):
"""
A numpy.float64.
:githublink:`%|py|144`
"""
[docs] def __init__(self):
MLNumTypeSingle.__init__(
self, numpy.float64, 'float64', 'double', 'float64')
[docs]class MLNumTypeInt32(MLNumTypeSingle):
"""
A numpy.int32.
:githublink:`%|py|154`
"""
[docs] def __init__(self):
MLNumTypeSingle.__init__(self, numpy.int32, 'int32', 'int', 'int32')
[docs]class MLNumTypeInt64(MLNumTypeSingle):
"""
A numpy.int64.
:githublink:`%|py|163`
"""
[docs] def __init__(self):
MLNumTypeSingle.__init__(
self, numpy.int32, 'int64', 'int64_t', 'int64')
[docs]class MLNumTypeBool(MLNumTypeSingle):
"""
A numpy.bool.
:githublink:`%|py|173`
"""
[docs] def __init__(self):
MLNumTypeSingle.__init__(self, numpy.bool, 'BL', 'bool', 'bool')
[docs]class MLTensor(MLType):
"""
Defines a tensor with a dimension and a single type for what it contains.
:githublink:`%|py|182`
"""
[docs] def __init__(self, element_type, dim):
if not isinstance(element_type, MLType):
raise TypeError( # pragma: no cover
'element_type must be of MLType not {0}'.format(type(element_type)))
if not isinstance(dim, tuple):
raise TypeError( # pragma: no cover
'dim must be a tuple.')
if len(dim) == 0:
raise ValueError( # pragma: no cover
"dimension must not be null.")
for d in dim:
if d == 0:
raise ValueError( # pragma: no cover
"No dimension can be null.")
self.dim = dim
self.element_type = element_type
@property
def CTypeSingle(self):
"""
Returns *ctype*.
:githublink:`%|py|205`
"""
return self.element_type.ctype
[docs] def validate(self, value):
"""
Checks that the value is of this type.
:githublink:`%|py|211`
"""
MLType.validate(self, value)
if not isinstance(value, numpy.ndarray):
raise TypeError( # pragma: no cover
"value is not a numpy.array but '{0}'".format(type(value)))
if self.dim != value.shape:
raise ValueError( # pragma: no cover
"Dimensions do not match {0}={1}".format(self.dim, value.shape))
rvalue = value.ravel()
for i, num in enumerate(rvalue):
try:
self.element_type.validate(num)
except TypeError as e: # pragma: no cover
raise TypeError(
'Unable to convert an array due to value index {0}: {1}'.format(i, rvalue[i])) from e
return value
[docs] def _byref_c(self):
return ""
[docs] def _export_json(self, hook=None, result_name=None):
return '{0}:{1}'.format(self.element_type._export_json(hook=hook), self.dim)
[docs] def _export_c(self, hook=None, result_name=None):
if len(self.dim) != 1:
raise NotImplementedError( # pragma: no cover
'Only 1D vector implemented.')
if hook is None:
raise ValueError( # pragma: no cover
"hook must contains either 'signature' or 'declare'.")
if hook == 'signature':
if result_name is None:
raise ValueError( # pragma: no cover
"result_name must be specified.")
return {'code': "{0}[{1}] {2}".format(self.element_type._export_c(hook=hook)['code'],
self.dim[0], result_name),
'result_name': result_name}
elif hook == 'declare':
if result_name is None:
raise ValueError( # pragma: no cover
"result_name must be specified.")
dc = self.element_type._export_c(
hook=hook, result_name=result_name)
return {'code': "{0}[{1}]".format(dc['code'], self.dim[0])}
elif hook == 'type':
return {'code': "{0}*".format(self.element_type._export_c(hook=hook)['code'])}
elif hook == 'typeref':
if result_name is None:
return {'code': "{0}*".format(self.element_type._export_c(hook='type')['code'])}
code = self.element_type._export_c(hook='type')['code']
return {'code': "{0}* {1}".format(code, result_name), 'result_name': result_name}
else:
raise ValueError( # pragma: no cover
"hook must contains either 'signature' or 'declare' not '{0}'.".format(hook))
[docs] def _copy_c(self, src, dest, hook=None):
if len(self.dim) != 1:
raise NotImplementedError( # pragma: no cover
'Only 1D vector implemented.')
code = self.element_type._export_c(hook='type')['code']
return "memcpy({1}, {0}, {2}*sizeof({3}));".format(src, dest, self.dim[0], code)