Skip to content
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
101 changes: 100 additions & 1 deletion arrayfire_wrapper/lib/interface_functions/opencl.py
Original file line number Diff line number Diff line change
@@ -1 +1,100 @@
# TODO
import ctypes
from enum import Enum

from arrayfire_wrapper.lib._utility import call_from_clib


class DeviceType(Enum):
CPU = 2
GPU = 4
ACC = 8
UNKNOWN = -1


class PlatformType(Enum):
AMD = 0
APPLE = 1
INTEL = 2
NVIDIA = 3
BEIGNET = 4
POCL = 5
UNKNOWN = -1


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 # type: ignore[return-value]


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 # type: ignore[return-value]


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


def set_device_id(idx: int) -> None:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga600361a20ceac2a65590b67fc0366314
"""
call_from_clib(set_device_id.__name__, ctypes.c_int64(idx), clib_prefix="afcl")
return None


def add_device_context(dev: int, ctx: int, que: int) -> None:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga49f596a4041fb757f1f5a75999cf8858
"""
call_from_clib(
add_device_context.__name__, ctypes.c_int64(dev), ctypes.c_int64(ctx), ctypes.c_int64(que), clib_prefix="afcl"
)
return None


def set_device_context(dev: int, ctx: int) -> None:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga975661f2b06dddb125c5d1757160b02c
"""
call_from_clib(set_device_context.__name__, ctypes.c_int64(dev), ctypes.c_int64(ctx), clib_prefix="afcl")
return None


def delete_device_context(dev: int, ctx: int) -> None:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga1a56dcf05099d6ac0a3b7701f7cb23f8
"""
call_from_clib(delete_device_context.__name__, ctypes.c_int64(dev), ctypes.c_int64(ctx), clib_prefix="afcl")
return None


def get_device_type() -> DeviceType:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga5e360e0fe0eb55d0046191bc3fd6f81d
"""
res = ctypes.c_void_p()
call_from_clib(get_device_type.__name__, ctypes.pointer(res), clib_prefix="afcl")
return DeviceType(res.value)


def get_platform() -> PlatformType:
"""
source: https://arrayfire.org/docs/group__opencl__mat.htm#ga5e360e0fe0eb55d0046191bc3fd6f81d&gsc.tab=0
"""
res = ctypes.c_void_p()
call_from_clib(get_platform.__name__, ctypes.pointer(res), clib_prefix="afcl")
return PlatformType(res.value)
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() -> None:
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() -> None:
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() -> None:
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() -> None:
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() -> None:
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() -> None:
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)]
29 changes: 29 additions & 0 deletions tests/test_opencl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import ctypes

import arrayfire_wrapper.lib.interface_functions.opencl as cl


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


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


def test_get_device_id() -> None:
assert isinstance(cl.get_device_id(), int)


def test_set_device_id() -> None:
cl.set_device_id(0)
assert cl.get_device_id() == 0


def test_get_device_type() -> None:
assert cl.get_device_type() == cl.DeviceType.GPU # change according to device


def test_get_platform() -> None:
assert cl.get_platform() == cl.PlatformType.INTEL # change according to platform