1010"""
1111Interop 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
2022from .array import *
2123from .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+
2376try :
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
83115except :
@@ -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 ())
139157except :
@@ -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 ())
215224except :
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