########################################
# 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*: and integer defining the device to use.
* *interactive*: whether to ask the user to select or correct the input device or not.
If any problem appears and this argument is set to False (default),
the first encountered device will be used and a warning will be displayed.
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 :meth:`object_wrapper.__init__` function.
:type args: tuple
:param kwargs: arguments forwarded to the :meth:`object_wrapper.__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)