1import numpy
2
3from chainer import _backend
4# TODO(kmaehashi): `from chainer.backends import cuda` causes circular imports.
5# Surprisingly, `import chianer.backends` works as a workaround to avoid, but
6# we should fix circular dependencies themselves around `chainer.backends.*`.
7import chainer.backends
8import chainerx
9
10
11class CpuDevice(_backend.Device):
12
13    """Device for CPU (NumPy) backend"""
14
15    name = '@numpy'
16    xp = numpy
17    supported_array_types = (numpy.ndarray,)
18
19    __hash__ = _backend.Device.__hash__
20
21    @staticmethod
22    def from_array(array):
23        if isinstance(array, numpy.ndarray):
24            return CpuDevice()
25        return None
26
27    def __eq__(self, other):
28        return isinstance(other, CpuDevice)
29
30    def __repr__(self):
31        return '<{} (numpy)>'.format(self.__class__.__name__)
32
33    def send_array(self, array):
34        return _array_to_cpu(array)
35
36    def is_array_supported(self, array):
37        return isinstance(array, numpy.ndarray)
38
39
40def _to_cpu(array):
41    """Converts an array or arrays to NumPy."""
42    return _backend._convert_arrays(array, _array_to_cpu)
43
44
45def _array_to_cpu(array):
46    if array is None:
47        return None
48    if isinstance(array, numpy.ndarray):
49        return array
50    if isinstance(array, chainer.backends.intel64.mdarray):
51        return numpy.asarray(array)
52    if isinstance(array, chainerx.ndarray):
53        return chainerx.to_numpy(array, copy=False)
54    if isinstance(array, chainer.backends.cuda.ndarray):
55        with chainer.backends.cuda.get_device_from_array(array):
56            return array.get()
57    if numpy.isscalar(array):
58        return numpy.asarray(array)
59    raise TypeError(
60        'Array cannot be converted into an numpy.ndarray'
61        '\nActual type: {0}.'.format(type(array)))
62