Skip to content

Commit

Permalink
added interop functionality and tests, edited str_to_dtype function i…
Browse files Browse the repository at this point in the history
…n dtypes, added opencl tests, chaged get_queue and get_context return types to void pointers
  • Loading branch information
sakchal committed May 8, 2024
1 parent 4a505dc commit 32c5bf2
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 8 deletions.
2 changes: 1 addition & 1 deletion arrayfire_wrapper/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def c_api_value_to_dtype(value: int) -> Dtype:

def str_to_dtype(value: str) -> Dtype:
for dtype in supported_dtypes:
if value == dtype.typecode or value == dtype.typename or value == dtype.name:
if value == dtype.typecode or value == dtype.typename or value == dtype.name or value == dtype.c_type:
return dtype

raise TypeError("There is no supported dtype that matches passed dtype typecode.")
60 changes: 60 additions & 0 deletions arrayfire_wrapper/lib/interface_functions/interop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import ctypes

import numpy as np
import pyopencl.array as cl # type: ignore[import-untyped]

from arrayfire_wrapper.defines import AFArray, CShape
from arrayfire_wrapper.dtypes import c_api_value_to_dtype, str_to_dtype
from arrayfire_wrapper.lib._utility import call_from_clib
from arrayfire_wrapper.lib.create_and_modify_array.manage_array import create_array, get_data_ptr, get_dims, get_type


def numpy_to_af_array(np_arr: np.ndarray) -> AFArray:
out = AFArray(0)
shape = np_arr.shape
c_shape = CShape(*shape)

c_type = np.ctypeslib.as_ctypes_type(np_arr.dtype)
dtype = str_to_dtype(c_type)

call_from_clib(
create_array.__name__,
ctypes.pointer(out),
np_arr.ctypes.data_as(ctypes.c_void_p),
c_shape.original_shape,
ctypes.pointer(c_shape.c_array),
dtype.c_api_value,
)
return out


def af_to_numpy_array(af_arr: AFArray) -> np.ndarray:
shape = get_dims(af_arr)
dtype = c_api_value_to_dtype(get_type(af_arr))
typecode = dtype.typecode

out = np.empty(shape, typecode, "F")
call_from_clib(get_data_ptr.__name__, ctypes.c_void_p(out.ctypes.data), af_arr)
return out


def pyopencl_to_af_array(pycl_arr: cl.Array) -> AFArray:
out = AFArray(0)
np_arr = pycl_arr.get()

shape = np_arr.shape
c_shape = CShape(*shape)

c_type = np.ctypeslib.as_ctypes_type(np_arr.dtype)
dtype = str_to_dtype(c_type)

call_from_clib(
create_array.__name__,
ctypes.pointer(out),
np_arr.ctypes.data_as(ctypes.c_void_p),
c_shape.original_shape,
ctypes.pointer(c_shape.c_array),
dtype.c_api_value,
)

return out
10 changes: 5 additions & 5 deletions arrayfire_wrapper/lib/interface_functions/opencl.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ class PlatformType(Enum):
UNKNOWN = -1


def get_context(retain: bool = False) -> int:
def get_context(retain: bool = False) -> ctypes.c_void_p:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#gad42de383f405b3e38d6eb669c0cbe2e3
"""
out = ctypes.c_void_p()
call_from_clib(get_context.__name__, ctypes.pointer(out), retain, clib_prefix="afcl")
return out.value # type: ignore[return-value]
return out # type: ignore[return-value]


def get_queue(retain: bool = False) -> int:
def get_queue(retain: bool = False) -> ctypes.c_void_p:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#gab1701ef4f2b68429eb31c1e21c88d0bc
"""
out = ctypes.c_void_p()
call_from_clib(get_queue.__name__, ctypes.pointer(out), retain, clib_prefix="afcl")
return out.value # type: ignore[return-value]
return out # type: ignore[return-value]


def get_device_id() -> int:
Expand All @@ -45,7 +45,7 @@ def get_device_id() -> int:
"""
out = ctypes.c_void_p()
call_from_clib(get_device_id.__name__, ctypes.pointer(out), clib_prefix="afcl")
return out.value # type: ignore[return-value]
return out # type: ignore[return-value]


def set_device_id(idx: int) -> None:
Expand Down
72 changes: 72 additions & 0 deletions tests/test_interop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import numpy as np
import pyopencl as cl # type: ignore
import pyopencl.array as cl_array # type: ignore

import arrayfire_wrapper.lib as wrapper
from arrayfire_wrapper.defines import AFArray
from arrayfire_wrapper.dtypes import int16
from arrayfire_wrapper.lib.create_and_modify_array.manage_array import get_dims, get_numdims
from arrayfire_wrapper.lib.interface_functions.interop import ( # noqa: E501
af_to_numpy_array,
numpy_to_af_array,
pyopencl_to_af_array,
)

# flake8: noqa: E203


def test_numpy_to_af_array_type():
arr = np.array([1, 2, 3, 4])

af_array = numpy_to_af_array(arr)

assert isinstance(af_array, AFArray)


def test_af_to_numpy_array_type():
arr = wrapper.constant(2, (5, 5), int16)

np_arr = af_to_numpy_array(arr)

assert isinstance(np_arr, np.ndarray)


def test_pyopencl_to_af_array_type():
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

host_array = np.array([1, 2, 3, 4])

cl_array_device = cl_array.to_device(queue, host_array)

af_array = pyopencl_to_af_array(cl_array_device)

assert isinstance(af_array, AFArray)


def test_numpy_to_af_array_shape():
np_arr = np.array([1, 2, 3, 4])

af_arr = numpy_to_af_array(np_arr)

assert get_dims(af_arr)[0 : get_numdims(af_arr)] == np_arr.shape[0 : get_numdims(af_arr)]


def test_af_to_numpy_array_shape():
af_arr = wrapper.constant(2, (5, 5), int16)

np_arr = af_to_numpy_array(af_arr)
assert np_arr.shape[0 : get_numdims(af_arr)] == get_dims(af_arr)[0 : get_numdims(af_arr)]


def test_pyopencl_to_af_array_shape():
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

host_array = np.array([1, 2, 3, 4])

cl_arr = cl_array.to_device(queue, host_array)

af_arr = pyopencl_to_af_array(cl_arr)

assert cl_arr.shape[0 : get_numdims(af_arr)] == get_dims(af_arr)[0 : get_numdims(af_arr)]
7 changes: 5 additions & 2 deletions tests/test_opencl.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import ctypes

import arrayfire_wrapper.lib.interface_functions.opencl as cl


def test_get_context_type() -> None:
assert isinstance(cl.get_context(), int)
ptr = cl.get_context()
assert isinstance(ptr, ctypes.c_void_p)


def test_get_queue_type() -> None:
assert isinstance(cl.get_queue(), int)
assert isinstance(cl.get_queue(), ctypes.c_void_p)


def test_get_device_id() -> None:
Expand Down

0 comments on commit 32c5bf2

Please sign in to comment.