#######################################################
# Copyright (c) 2015, ArrayFire
# All rights reserved.
#
# This file is distributed under 3-clause BSD license.
# The complete license agreement can be obtained at:
# http://arrayfire.com/licenses/BSD-3-Clause
########################################################
"""
Interop with other python packages.
This module provides helper functions to copy data to arrayfire from the following modules:
1. numpy - numpy.ndarray
2. pycuda - pycuda.gpuarray
3. pyopencl - pyopencl.array
4. numba - numba.cuda.cudadrv.devicearray.DeviceNDArray
"""
from .array import *
from .device import *
def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True):
"""
Fortran Contiguous to af array
"""
res = Array(in_ptr, in_shape, in_dtype, is_device=is_device)
if not is_device:
return res
lock_array(res)
return res.copy() if copy else res
def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = True):
"""
C Contiguous to af array
"""
if ndim == 1:
return _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device, copy)
else:
shape = tuple(reversed(in_shape))
res = Array(in_ptr, shape, in_dtype, is_device=is_device)
if is_device: lock_array(res)
return res._reorder()
_nptype_to_aftype = {'b1' : Dtype.b8,
'u1' : Dtype.u8,
'u2' : Dtype.u16,
'i2' : Dtype.s16,
's4' : Dtype.u32,
'i4' : Dtype.s32,
'f4' : Dtype.f32,
'c8' : Dtype.c32,
's8' : Dtype.u64,
'i8' : Dtype.s64,
'f8' : Dtype.f64,
'c16' : Dtype.c64}
try:
import numpy as np
except ImportError:
AF_NUMPY_FOUND=False
else:
from numpy import ndarray as NumpyArray
from .data import reorder
AF_NUMPY_FOUND=True
[docs] def np_to_af_array(np_arr, copy=True):
"""
Convert numpy.ndarray to arrayfire.Array.
Parameters
----------
np_arr : numpy.ndarray()
copy : Bool specifying if array is to be copied.
Default is true.
Can only be False if array is fortran contiguous.
Returns
---------
af_arr : arrayfire.Array()
"""
in_shape = np_arr.shape
in_ptr = np_arr.ctypes.data_as(c_void_ptr_t)
in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]]
if not copy:
raise RuntimeError("Copy can not be False for numpy arrays")
if (np_arr.flags['F_CONTIGUOUS']):
return _fc_to_af_array(in_ptr, in_shape, in_dtype)
elif (np_arr.flags['C_CONTIGUOUS']):
return _cc_to_af_array(in_ptr, np_arr.ndim, in_shape, in_dtype)
else:
return np_to_af_array(np_arr.copy())
from_ndarray = np_to_af_array
try:
import pycuda.gpuarray
except ImportError:
AF_PYCUDA_FOUND=False
else:
from pycuda.gpuarray import GPUArray as CudaArray
AF_PYCUDA_FOUND=True
def pycuda_to_af_array(pycu_arr, copy=True):
"""
Convert pycuda.gpuarray to arrayfire.Array
Parameters
-----------
pycu_arr : pycuda.GPUArray()
copy : Bool specifying if array is to be copied.
Default is true.
Can only be False if array is fortran contiguous.
Returns
----------
af_arr : arrayfire.Array()
Note
----------
The input array is copied to af.Array
"""
in_ptr = pycu_arr.ptr
in_shape = pycu_arr.shape
in_dtype = pycu_arr.dtype.char
if not copy and not pycu_arr.flags.f_contiguous:
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
if (pycu_arr.flags.f_contiguous):
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
elif (pycu_arr.flags.c_contiguous):
return _cc_to_af_array(in_ptr, pycu_arr.ndim, in_shape, in_dtype, True, copy)
else:
return pycuda_to_af_array(pycu_arr.copy())
try:
from pyopencl.array import Array as OpenclArray
except ImportError:
AF_PYOPENCL_FOUND=False
else:
from .opencl import add_device_context as _add_device_context
from .opencl import set_device_context as _set_device_context
from .opencl import get_device_id as _get_device_id
from .opencl import get_context as _get_context
AF_PYOPENCL_FOUND=True
def pyopencl_to_af_array(pycl_arr, copy=True):
"""
Convert pyopencl.gpuarray to arrayfire.Array
Parameters
-----------
pycl_arr : pyopencl.Array()
copy : Bool specifying if array is to be copied.
Default is true.
Can only be False if array is fortran contiguous.
Returns
----------
af_arr : arrayfire.Array()
Note
----------
The input array is copied to af.Array
"""
ctx = pycl_arr.context.int_ptr
que = pycl_arr.queue.int_ptr
dev = pycl_arr.queue.device.int_ptr
dev_idx = None
ctx_idx = None
for n in range(get_device_count()):
set_device(n)
dev_idx = _get_device_id()
ctx_idx = _get_context()
if (dev_idx == dev and ctx_idx == ctx):
break
if (dev_idx == None or ctx_idx == None or
dev_idx != dev or ctx_idx != ctx):
print("Adding context and queue")
_add_device_context(dev, ctx, que)
_set_device_context(dev, ctx)
info()
in_ptr = pycl_arr.base_data.int_ptr
in_shape = pycl_arr.shape
in_dtype = pycl_arr.dtype.char
if not copy and not pycl_arr.flags.f_contiguous:
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
print("Copying array")
print(pycl_arr.base_data.int_ptr)
if (pycl_arr.flags.f_contiguous):
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
elif (pycl_arr.flags.c_contiguous):
return _cc_to_af_array(in_ptr, pycl_arr.ndim, in_shape, in_dtype, True, copy)
else:
return pyopencl_to_af_array(pycl_arr.copy())
try:
import numba
except ImportError:
AF_NUMBA_FOUND=False
else:
from numba import cuda
NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray
AF_NUMBA_FOUND=True
def numba_to_af_array(nb_arr, copy=True):
"""
Convert numba.gpuarray to arrayfire.Array
Parameters
-----------
nb_arr : numba.cuda.cudadrv.devicearray.DeviceNDArray()
copy : Bool specifying if array is to be copied.
Default is true.
Can only be False if array is fortran contiguous.
Returns
----------
af_arr : arrayfire.Array()
Note
----------
The input array is copied to af.Array
"""
in_ptr = nb_arr.device_ctypes_pointer.value
in_shape = nb_arr.shape
in_dtype = _nptype_to_aftype[nb_arr.dtype.str[1:]]
if not copy and not nb_arr.flags.f_contiguous:
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
if (nb_arr.is_f_contiguous()):
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
elif (nb_arr.is_c_contiguous()):
return _cc_to_af_array(in_ptr, nb_arr.ndim, in_shape, in_dtype, True, copy)
else:
return numba_to_af_array(nb_arr.copy())
[docs]def to_array(in_array, copy = True):
"""
Helper function to convert input from a different module to af.Array
Parameters
-------------
in_array : array like object
Can be one of the following:
- numpy.ndarray
- pycuda.GPUArray
- pyopencl.Array
- numba.cuda.cudadrv.devicearray.DeviceNDArray
- array.array
- list
copy : Bool specifying if array is to be copied.
Default is true.
Can only be False if array is fortran contiguous.
Returns
--------------
af.Array of same dimensions as input after copying the data from the input
"""
if AF_NUMPY_FOUND and isinstance(in_array, NumpyArray):
return np_to_af_array(in_array, copy)
if AF_PYCUDA_FOUND and isinstance(in_array, CudaArray):
return pycuda_to_af_array(in_array, copy)
if AF_PYOPENCL_FOUND and isinstance(in_array, OpenclArray):
return pyopencl_to_af_array(in_array, copy)
if AF_NUMBA_FOUND and isinstance(in_array, NumbaCudaArray):
return numba_to_af_array(in_array, copy)
return Array(src=in_array)