########################################
# MIT License
#
# Copyright (c) 2020 Miguel Ramos Pernas
########################################
from .base.core import get_exposed_package_objects
from .backends import core as backends_core
from .backends import aop
import inspect
import os
PACKAGE_PATH = os.path.dirname(os.path.abspath(__file__))
__all__ = ['Backend']
minkit_api = get_exposed_package_objects(PACKAGE_PATH)
globals().update(minkit_api)
__all__ += list(minkit_api.keys())
__all__.sort()
[docs]class Backend(object):
_exposed_objects = tuple(n for n, c in minkit_api.items(
) if inspect.isclass(c)) # loading all the classes
def __init__(self, btype=backends_core.CPU, **kwargs):
'''
Object used in order to do operations with objects of the :mod:`minkit`
module. Any object depending on a backend can be directly built using
this class, which will forward itself during its construction.
:param btype: backend type ('cpu', 'cuda', 'opencl').
:type btype: str
:param kwargs: arguments forwarded to the backend constructor \
(cuda and opencl backends only). See below for more details.
:type kwargs: dict
The keyword arguments can contain any of the following:
* device
* interactive
These arguments are only available in *cuda* and *opencl* backends only.
'''
super(Backend, self).__init__()
self.__btype = btype.lower()
self.__aop = aop.ArrayOperations(self, **kwargs)
for n in Backend._exposed_objects:
setattr(self, n, object_wrapper(minkit_api[n], self))
@property
def aop(self):
'''
Object to do operations on arrays.
:type: ArrayOperations
'''
return self.__aop
@property
def btype(self):
'''
Backend type.
:type: str
'''
return self.__btype
class object_wrapper(object):
def __init__(self, cls, backend):
'''
Object to wrap the members of other objects so the backend is always
set to that provided to this class.
:param cls: class to wrap.
:type cls: class
:param backend: backend to use when calling the members.
:type backend: Backend
'''
super(object_wrapper, self).__init__()
self._cls = cls
self._backend = backend
def __call_wrapper(self, func):
'''
'''
if 'backend' in inspect.getfullargspec(func).args:
def wrapper(*args, **kwargs):
return func(*args, backend=self._backend, **kwargs)
else:
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.__name__ = func.__name__
wrapper.__doc__ = f'''
Wrapper around the "{func.__name__}" function, which automatically sets the backend.
'''
return wrapper
def __call__(self, *args, **kwargs):
'''
Initialize the wrapped class.
:param args: arguments forwarded to the __init__ function.
:type args: tuple
:param kwargs: arguments forwarded to the __init__ function.
:type kwargs: dict
:returns: Wrapped object.
'''
return self.__call_wrapper(self._cls)(*args, **kwargs)
def __getattr__(self, name):
'''
Get the given member of the object.
:param name: name of the member.
:type name: str
:returns: Wrapped function.
:rtype: function
'''
return self.__call_wrapper(getattr(self._cls, name))
def __repr__(self):
'''
Represent this class as a string.
:returns: This class as a string.
:rtype: str
'''
return f'object_wrapper({self._cls.__name__})'
# Determine the default backend
DEFAULT_BACKEND_TYPE = os.environ.get(
'MINKIT_BACKEND', backends_core.CPU).lower()
if DEFAULT_BACKEND_TYPE == backends_core.CPU:
DEFAULT_BACKEND = Backend(DEFAULT_BACKEND_TYPE)
else:
dev = os.environ.get('MINKIT_DEVICE', 0)
itv = os.environ.get('MINKIT_INTERACTIVE', True)
DEFAULT_BACKEND = Backend(DEFAULT_BACKEND_TYPE,
device=dev, interactive=itv)
backends_core.set_default_aop(DEFAULT_BACKEND.aop)