Skip to content

Commit 32196a0

Browse files
committed
Merge branch 'master' into devel
2 parents ced607b + 3cf70d8 commit 32196a0

File tree

4 files changed

+308
-93
lines changed

4 files changed

+308
-93
lines changed

arrayfire/interop.py

+150-89
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,88 @@
1010
"""
1111
Interop with other python packages.
1212
13-
This module provides interoperability with the following python packages.
13+
This module provides helper functions to copy data to arrayfire from the following modules:
14+
15+
1. numpy - numpy.ndarray
16+
2. pycuda - pycuda.gpuarray
17+
3. pyopencl - pyopencl.array
18+
4. numba - numba.cuda.cudadrv.devicearray.DeviceNDArray
1419
15-
1. numpy
16-
2. pycuda
17-
3. pyopencl
1820
"""
1921

2022
from .array import *
2123
from .device import *
2224

25+
26+
def _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device=False, copy = True):
27+
"""
28+
Fortran Contiguous to af array
29+
"""
30+
res = Array(in_ptr, in_shape, in_dtype, is_device=is_device)
31+
32+
if is_device:
33+
lock_array(res)
34+
pass
35+
36+
return res.copy() if copy else res
37+
38+
def _cc_to_af_array(in_ptr, ndim, in_shape, in_dtype, is_device=False, copy = True):
39+
"""
40+
C Contiguous to af array
41+
"""
42+
if ndim == 1:
43+
return _fc_to_af_array(in_ptr, in_shape, in_dtype, is_device, copy)
44+
elif ndim == 2:
45+
shape = (in_shape[1], in_shape[0])
46+
res = Array(in_ptr, shape, in_dtype, is_device=is_device)
47+
if is_device: lock_array(res)
48+
return reorder(res, 1, 0)
49+
elif ndim == 3:
50+
shape = (in_shape[2], in_shape[1], in_shape[0])
51+
res = Array(in_ptr, shape, in_dtype, is_device=is_device)
52+
if is_device: lock_array(res)
53+
return reorder(res, 2, 1, 0)
54+
elif ndim == 4:
55+
shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0])
56+
res = Array(in_ptr, shape, in_dtype, is_device=is_device)
57+
if is_device: lock_array(res)
58+
return reorder(res, 3, 2, 1, 0)
59+
else:
60+
raise RuntimeError("Unsupported ndim")
61+
62+
63+
_nptype_to_aftype = {'b1' : Dtype.b8,
64+
'u1' : Dtype.u8,
65+
'u2' : Dtype.u16,
66+
'i2' : Dtype.s16,
67+
's4' : Dtype.u32,
68+
'i4' : Dtype.s32,
69+
'f4' : Dtype.f32,
70+
'c8' : Dtype.c32,
71+
's8' : Dtype.u64,
72+
'i8' : Dtype.s64,
73+
'f8' : Dtype.f64,
74+
'c16' : Dtype.c64}
75+
2376
try:
2477
import numpy as np
2578
from numpy import ndarray as NumpyArray
2679
from .data import reorder
2780

2881
AF_NUMPY_FOUND=True
2982

30-
_nptype_to_aftype = {'b1' : Dtype.b8,
31-
'u1' : Dtype.u8,
32-
'u2' : Dtype.u16,
33-
'i2' : Dtype.s16,
34-
's4' : Dtype.u32,
35-
'i4' : Dtype.s32,
36-
'f4' : Dtype.f32,
37-
'c8' : Dtype.c32,
38-
's8' : Dtype.u64,
39-
'i8' : Dtype.s64,
40-
'f8' : Dtype.f64,
41-
'c16' : Dtype.c64}
42-
43-
def np_to_af_array(np_arr):
83+
def np_to_af_array(np_arr, copy=True):
4484
"""
4585
Convert numpy.ndarray to arrayfire.Array.
4686
4787
Parameters
4888
----------
4989
np_arr : numpy.ndarray()
5090
91+
copy : Bool specifying if array is to be copied.
92+
Default is true.
93+
Can only be False if array is fortran contiguous.
94+
5195
Returns
5296
---------
5397
af_arr : arrayfire.Array()
@@ -57,27 +101,15 @@ def np_to_af_array(np_arr):
57101
in_ptr = np_arr.ctypes.data_as(c_void_ptr_t)
58102
in_dtype = _nptype_to_aftype[np_arr.dtype.str[1:]]
59103

104+
if not copy:
105+
raise RuntimeError("Copy can not be False for numpy arrays")
106+
60107
if (np_arr.flags['F_CONTIGUOUS']):
61-
return Array(in_ptr, in_shape, in_dtype)
108+
return _fc_to_af_array(in_ptr, in_shape, in_dtype)
62109
elif (np_arr.flags['C_CONTIGUOUS']):
63-
if np_arr.ndim == 1:
64-
return Array(in_ptr, in_shape, in_dtype)
65-
elif np_arr.ndim == 2:
66-
shape = (in_shape[1], in_shape[0])
67-
res = Array(in_ptr, shape, in_dtype)
68-
return reorder(res, 1, 0)
69-
elif np_arr.ndim == 3:
70-
shape = (in_shape[2], in_shape[1], in_shape[0])
71-
res = Array(in_ptr, shape, in_dtype)
72-
return reorder(res, 2, 1, 0)
73-
elif np_arr.ndim == 4:
74-
shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0])
75-
res = Array(in_ptr, shape, in_dtype)
76-
return reorder(res, 3, 2, 1, 0)
77-
else:
78-
raise RuntimeError("Unsupported ndim")
110+
return _cc_to_af_array(in_ptr, np_arr.ndim, in_shape, in_dtype)
79111
else:
80-
return np_to_af_array(np.asfortranarray(np_arr))
112+
return np_to_af_array(np_arr.copy())
81113

82114
from_ndarray = np_to_af_array
83115
except:
@@ -88,14 +120,18 @@ def np_to_af_array(np_arr):
88120
from pycuda.gpuarray import GPUArray as CudaArray
89121
AF_PYCUDA_FOUND=True
90122

91-
def pycuda_to_af_array(pycu_arr):
123+
def pycuda_to_af_array(pycu_arr, copy=True):
92124
"""
93125
Convert pycuda.gpuarray to arrayfire.Array
94126
95127
Parameters
96128
-----------
97129
pycu_arr : pycuda.GPUArray()
98130
131+
copy : Bool specifying if array is to be copied.
132+
Default is true.
133+
Can only be False if array is fortran contiguous.
134+
99135
Returns
100136
----------
101137
af_arr : arrayfire.Array()
@@ -109,31 +145,13 @@ def pycuda_to_af_array(pycu_arr):
109145
in_shape = pycu_arr.shape
110146
in_dtype = pycu_arr.dtype.char
111147

148+
if not copy and not pycu_arr.flags.f_contiguous:
149+
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
150+
112151
if (pycu_arr.flags.f_contiguous):
113-
res = Array(in_ptr, in_shape, in_dtype, is_device=True)
114-
lock_array(res)
115-
res = res.copy()
116-
return res
152+
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
117153
elif (pycu_arr.flags.c_contiguous):
118-
if pycu_arr.ndim == 1:
119-
return Array(in_ptr, in_shape, in_dtype, is_device=True)
120-
elif pycu_arr.ndim == 2:
121-
shape = (in_shape[1], in_shape[0])
122-
res = Array(in_ptr, shape, in_dtype, is_device=True)
123-
lock_array(res)
124-
return reorder(res, 1, 0)
125-
elif pycu_arr.ndim == 3:
126-
shape = (in_shape[2], in_shape[1], in_shape[0])
127-
res = Array(in_ptr, shape, in_dtype, is_device=True)
128-
lock_array(res)
129-
return reorder(res, 2, 1, 0)
130-
elif pycu_arr.ndim == 4:
131-
shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0])
132-
res = Array(in_ptr, shape, in_dtype, is_device=True)
133-
lock_array(res)
134-
return reorder(res, 3, 2, 1, 0)
135-
else:
136-
raise RuntimeError("Unsupported ndim")
154+
return _cc_to_af_array(in_ptr, pycu_arr.ndim, in_shape, in_dtype, True, copy)
137155
else:
138156
return pycuda_to_af_array(pycu_arr.copy())
139157
except:
@@ -147,14 +165,18 @@ def pycuda_to_af_array(pycu_arr):
147165
from .opencl import get_context as _get_context
148166
AF_PYOPENCL_FOUND=True
149167

150-
def pyopencl_to_af_array(pycl_arr):
168+
def pyopencl_to_af_array(pycl_arr, copy=True):
151169
"""
152170
Convert pyopencl.gpuarray to arrayfire.Array
153171
154172
Parameters
155173
-----------
156174
pycl_arr : pyopencl.Array()
157175
176+
copy : Bool specifying if array is to be copied.
177+
Default is true.
178+
Can only be False if array is fortran contiguous.
179+
158180
Returns
159181
----------
160182
af_arr : arrayfire.Array()
@@ -179,63 +201,102 @@ def pyopencl_to_af_array(pycl_arr):
179201

180202
if (dev_idx == None or ctx_idx == None or
181203
dev_idx != dev or ctx_idx != ctx):
204+
print("Adding context and queue")
182205
_add_device_context(dev, ctx, que)
183206
_set_device_context(dev, ctx)
184207

208+
info()
185209
in_ptr = pycl_arr.base_data.int_ptr
186210
in_shape = pycl_arr.shape
187211
in_dtype = pycl_arr.dtype.char
188212

213+
if not copy and not pycl_arr.flags.f_contiguous:
214+
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
215+
216+
print("Copying array")
217+
print(pycl_arr.base_data.int_ptr)
189218
if (pycl_arr.flags.f_contiguous):
190-
res = Array(in_ptr, in_shape, in_dtype, is_device=True)
191-
lock_array(res)
192-
return res
219+
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
193220
elif (pycl_arr.flags.c_contiguous):
194-
if pycl_arr.ndim == 1:
195-
return Array(in_ptr, in_shape, in_dtype, is_device=True)
196-
elif pycl_arr.ndim == 2:
197-
shape = (in_shape[1], in_shape[0])
198-
res = Array(in_ptr, shape, in_dtype, is_device=True)
199-
lock_array(res)
200-
return reorder(res, 1, 0)
201-
elif pycl_arr.ndim == 3:
202-
shape = (in_shape[2], in_shape[1], in_shape[0])
203-
res = Array(in_ptr, shape, in_dtype, is_device=True)
204-
lock_array(res)
205-
return reorder(res, 2, 1, 0)
206-
elif pycl_arr.ndim == 4:
207-
shape = (in_shape[3], in_shape[2], in_shape[1], in_shape[0])
208-
res = Array(in_ptr, shape, in_dtype, is_device=True)
209-
lock_array(res)
210-
return reorder(res, 3, 2, 1, 0)
211-
else:
212-
raise RuntimeError("Unsupported ndim")
221+
return _cc_to_af_array(in_ptr, pycl_arr.ndim, in_shape, in_dtype, True, copy)
213222
else:
214223
return pyopencl_to_af_array(pycl_arr.copy())
215224
except:
216225
AF_PYOPENCL_FOUND=False
217226

227+
try:
228+
import numba
229+
from numba import cuda
230+
NumbaCudaArray = cuda.cudadrv.devicearray.DeviceNDArray
231+
AF_NUMBA_FOUND=True
232+
233+
def numba_to_af_array(nb_arr, copy=True):
234+
"""
235+
Convert numba.gpuarray to arrayfire.Array
236+
237+
Parameters
238+
-----------
239+
nb_arr : numba.cuda.cudadrv.devicearray.DeviceNDArray()
240+
241+
copy : Bool specifying if array is to be copied.
242+
Default is true.
243+
Can only be False if array is fortran contiguous.
244+
245+
Returns
246+
----------
247+
af_arr : arrayfire.Array()
218248
219-
def to_array(in_array):
249+
Note
250+
----------
251+
The input array is copied to af.Array
252+
"""
253+
254+
in_ptr = nb_arr.device_ctypes_pointer.value
255+
in_shape = nb_arr.shape
256+
in_dtype = _nptype_to_aftype[nb_arr.dtype.str[1:]]
257+
258+
if not copy and not nb_arr.flags.f_contiguous:
259+
raise RuntimeError("Copy can only be False when arr.flags.f_contiguous is True")
260+
261+
if (nb_arr.is_f_contiguous()):
262+
return _fc_to_af_array(in_ptr, in_shape, in_dtype, True, copy)
263+
elif (nb_arr.is_c_contiguous()):
264+
return _cc_to_af_array(in_ptr, nb_arr.ndim, in_shape, in_dtype, True, copy)
265+
else:
266+
return numba_to_af_array(nb_arr.copy())
267+
except:
268+
AF_NUMBA_FOUND=False
269+
270+
def to_array(in_array, copy = True):
220271
"""
221272
Helper function to convert input from a different module to af.Array
222273
223274
Parameters
224275
-------------
225276
226277
in_array : array like object
227-
Can be one of numpy.ndarray, pycuda.GPUArray, pyopencl.Array, array.array, list
278+
Can be one of the following:
279+
- numpy.ndarray
280+
- pycuda.GPUArray
281+
- pyopencl.Array
282+
- numba.cuda.cudadrv.devicearray.DeviceNDArray
283+
- array.array
284+
- list
285+
copy : Bool specifying if array is to be copied.
286+
Default is true.
287+
Can only be False if array is fortran contiguous.
228288
229289
Returns
230290
--------------
231291
af.Array of same dimensions as input after copying the data from the input
232292
233-
234293
"""
235294
if AF_NUMPY_FOUND and isinstance(in_array, NumpyArray):
236-
return np_to_af_array(in_array)
295+
return np_to_af_array(in_array, copy)
237296
if AF_PYCUDA_FOUND and isinstance(in_array, CudaArray):
238-
return pycuda_to_af_array(in_array)
297+
return pycuda_to_af_array(in_array, copy)
239298
if AF_PYOPENCL_FOUND and isinstance(in_array, OpenclArray):
240-
return pyopencl_to_af_array(in_array)
299+
return pyopencl_to_af_array(in_array, copy)
300+
if AF_NUMBA_FOUND and isinstance(in_array, NumbaCudaArray):
301+
return numba_to_af_array(in_array, copy)
241302
return Array(src=in_array)

0 commit comments

Comments
 (0)