Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ per-file-ignores =
dpctl/_sycl_queue_manager.pyx: E999, E225
dpctl/memory/_memory.pyx: E999, E225, E226, E227
dpctl/program/_program.pyx: E999, E225, E226, E227
dpctl/tensor/_usmarray.pyx: E999, E225, E226, E227
dpctl/tensor/numpy_usm_shared.py: F821
examples/cython/sycl_buffer/_buffer_example.pyx: E999, E225, E402
examples/cython/sycl_direct_linkage/_buffer_example.pyx: E999, E225, E402
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,4 @@ dpctl/_sycl_event.h
dpctl/_sycl_queue.h
dpctl/_sycl_queue_manager.h
dpctl/memory/_memory.h
dpctl/tensor/_usmarray.h
6 changes: 6 additions & 0 deletions dpctl/tensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@
underlying memory buffer is allocated with a USM shared memory allocator.

"""

from dpctl.tensor._usmarray import usm_ndarray

__all__ = [
"usm_ndarray",
]
122 changes: 122 additions & 0 deletions dpctl/tensor/_slicing.pxi
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Data Parallel Control (dpctl)
#
# Copyright 2020-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numbers


cdef object _basic_slice_meta(object ind, tuple shape,
tuple strides, Py_ssize_t offset):
"""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although a cdef adding a docstring is good.


"""
if ind is Ellipsis:
return (shape, strides, offset)
elif ind is None:
return ((1,) + shape, (0,) + strides, offset)
elif isinstance(ind, slice):
sl_start, sl_stop, sl_step = ind.indices(shape[0])
sh0 = (sl_stop - sl_start) // sl_step
str0 = sl_step * strides[0]
new_strides = strides if (sl_step == 1) else (str0,) + strides[1:]
return (
(sh0, ) + shape[1:],
new_strides,
offset + sl_start * strides[0]
)
elif isinstance(ind, numbers.Integral):
if 0 <= ind < shape[0]:
return (shape[1:], strides[1:], offset + ind * strides[0])
elif -shape[0] <= ind < 0:
return (shape[1:], strides[1:],
offset + (shape[0] + ind) * strides[0])
else:
raise IndexError(
"Index {0} is out of range for axes 0 with "
"size {1}".format(ind, shape[0]))
elif isinstance(ind, list):
raise NotImplemented
elif isinstance(ind, tuple):
axes_referenced = 0
ellipses_count = 0
newaxis_count = 0
explicit_index = 0
for i in ind:
if i is None:
newaxis_count = newaxis_count + 1
elif i is Ellipsis:
ellipses_count = ellipses_count + 1
elif isinstance(i, slice):
axes_referenced = axes_referenced + 1
elif isinstance(i, numbers.Integral):
explicit_index = explicit_index + 1
axes_referenced = axes_referenced + 1
elif isinstance(i, list):
raise NotImplemented
else:
raise TypeError
if ellipses_count > 1:
raise IndexError(
"an index can only have a sinlge ellipsis ('...')")
if axes_referenced > len(shape):
raise IndexError(
"too many indices for an array, array is "
"{0}-dimensional, but {1} were indexed".format(
len(shape), axes_referenced))
if ellipses_count:
ellipses_count = len(shape) - axes_referenced
new_shape_len = (newaxis_count + ellipses_count
+ axes_referenced - explicit_index)
new_shape = list()
new_strides = list()
k = 0
new_offset = offset
for i in range(len(ind)):
ind_i = ind[i]
if (ind_i is Ellipsis):
k_new = k + ellipses_count
new_shape.extend(shape[k:k_new])
new_strides.extend(strides[k:k_new])
k = k_new
elif ind_i is None:
new_shape.append(1)
new_strides.append(0)
elif isinstance(ind_i, slice):
k_new = k + 1
sl_start, sl_stop, sl_step = ind_i.indices(shape[k])
sh_i = (sl_stop - sl_start) // sl_step
str_i = sl_step * strides[k]
new_shape.append(sh_i)
new_strides.append(str_i)
new_offset = new_offset + sl_start * strides[k]
k = k_new
elif isinstance(ind_i, numbers.Integral):
if 0 <= ind_i < shape[k]:
k_new = k + 1
new_offset = new_offset + ind_i * strides[k]
k = k_new
elif -shape[k] <= ind_i < 0:
k_new = k + 1
new_offset = new_offset + (shape[k] + ind_i) * strides[k]
k = k_new
else:
raise IndexError(
"Index {0} is out of range for "
"axes {1} with size {2}".format(ind_i, k, shape[k]))
new_shape.extend(shape[k:])
new_strides.extend(strides[k:])
return (tuple(new_shape), tuple(new_strides), new_offset)
else:
raise TypeError
212 changes: 212 additions & 0 deletions dpctl/tensor/_stride_utils.pxi
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Data Parallel Control (dpctl)
#
# Copyright 2020-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# distutils: language = c++
# cython: language_level=3

from cpython.mem cimport PyMem_Malloc
from cpython.ref cimport Py_INCREF
from cpython.tuple cimport PyTuple_New, PyTuple_SetItem


cdef int ERROR_MALLOC = 1
cdef int ERROR_INTERNAL = -1
cdef int ERROR_INCORRECT_ORDER = 2
cdef int ERROR_UNEXPECTED_STRIDES = 3

cdef int USM_ARRAY_C_CONTIGUOUS = 1
cdef int USM_ARRAY_F_CONTIGUOUS = 2
cdef int USM_ARRAY_WRITEABLE = 4


cdef Py_ssize_t shape_to_elem_count(int nd, Py_ssize_t *shape_arr):
"""
Computes number of elements in an array.
"""
cdef Py_ssize_t count = 1
for i in range(nd):
count *= shape_arr[i]
return count


cdef int _from_input_shape_strides(
int nd, object shape, object strides, int itemsize, char order,
Py_ssize_t **shape_ptr, Py_ssize_t **strides_ptr,
Py_ssize_t *nelems, Py_ssize_t *min_disp, Py_ssize_t *max_disp,
int *contig):
"""
Arguments: nd, shape, strides, itemsize, order
Modifies:
shape_ptr - pointer to C array for shape values
stride_ptr - pointer to C array for strides values
nelems - Number of elements in array
min_disp = min( dot(strides, index), index for shape)
max_disp = max( dor(strides, index), index for shape)
contig = enumation for array contiguity
Returns: 0 on success, error code otherwise.
On success pointers point to allocated arrays,
Otherwise they are set to NULL
"""
cdef int i
cdef int all_incr = 1
cdef int all_decr = 1
cdef Py_ssize_t elem_count = 1
cdef Py_ssize_t min_shift = 0
cdef Py_ssize_t max_shift = 0
cdef Py_ssize_t str_i
cdef Py_ssize_t* shape_arr
cdef Py_ssize_t* strides_arr

# 0-d array
if (nd == 0):
contig[0] = USM_ARRAY_C_CONTIGUOUS
nelems[0] = 1
min_disp[0] = 0
max_disp[0] = 0
shape_ptr[0] = <Py_ssize_t *>(<size_t>0)
strides_ptr[0] = <Py_ssize_t *>(<size_t>0)
return 0

shape_arr = <Py_ssize_t*>PyMem_Malloc(nd * sizeof(Py_ssize_t))
if (not shape_arr):
return ERROR_MALLOC
shape_ptr[0] = shape_arr
for i in range(0, nd):
shape_arr[i] = <Py_ssize_t> shape[i]
elem_count *= shape_arr[i]
if elem_count == 0:
contig[0] = USM_ARRAY_C_CONTIGUOUS
nelems[0] = 1
min_disp[0] = 0
max_disp[0] = 0
strides_ptr[0] = <Py_ssize_t *>(<size_t>0)
return 0
nelems[0] = elem_count

if (strides is None):
# no need to allocate and populate strides
if (int(order) not in [ord('C'), ord('F'), ord('c'), ord('f')]):
return ERROR_INCORRECT_ORDER
if order == <char> ord('C') or order == <char> ord('c'):
contig[0] = USM_ARRAY_C_CONTIGUOUS
else:
contig[0] = USM_ARRAY_F_CONTIGUOUS
min_disp[0] = 0
max_disp[0] = (elem_count - 1)
strides_ptr[0] = <Py_ssize_t *>(<size_t>0)
return 0
elif ((isinstance(strides, (list, tuple)) or hasattr(strides, 'tolist'))
and len(strides) == nd):
strides_arr = <Py_ssize_t*>PyMem_Malloc(nd * sizeof(Py_ssize_t))
if (not strides_arr):
return ERROR_MALLOC
strides_ptr[0] = strides_arr
for i in range(0, nd):
str_i = <Py_ssize_t> strides[i]
strides_arr[i] = str_i
if str_i > 0:
max_shift += strides_arr[i] * (shape_arr[i] - 1)
else:
min_shift += strides_arr[i] * (shape_arr[i] - 1)
min_disp[0] = min_shift
max_disp[0] = max_shift
if max_shift == min_shift + (elem_count - 1):
if nd == 1:
contig[0] = USM_ARRAY_C_CONTIGUOUS
return 0
for i in range(0, nd - 1):
if all_incr:
all_incr = strides_arr[i] < strides_arr[i + 1]
if all_decr:
all_decr = strides_arr[i] > strides_arr[i + 1]
if all_incr:
contig[0] = USM_ARRAY_C_CONTIGUOUS
elif all_decr:
contig[0] = USM_ARRAY_F_CONTIGUOUS
else:
contig[0] = 0
return 0
else:
contig[0] = 0 # non-contiguous
return 0
else:
return ERROR_UNEXPECTED_STRIDES
# return ERROR_INTERNAL


cdef object _make_int_tuple(int nd, Py_ssize_t *ary):
"""
Makes Python tuple from C array
"""
cdef tuple res
cdef object tmp
if (ary):
res = PyTuple_New(nd)
for i in range(nd):
tmp = <object>ary[i]
Py_INCREF(tmp) # SetItem steals the reference
PyTuple_SetItem(res, i, tmp)
return res
else:
return None


cdef object _make_reversed_int_tuple(int nd, Py_ssize_t *ary):
"""
Makes Python reversed tuple from C array
"""
cdef tuple res
cdef object tmp
cdef int i
cdef int nd_1
if (ary):
res = PyTuple_New(nd)
nd_1 = nd - 1
for i in range(nd):
tmp = <object>ary[i]
Py_INCREF(tmp) # SetItem steals the reference
PyTuple_SetItem(res, nd_1 - i, tmp)
return res
else:
return None


cdef object _c_contig_strides(int nd, Py_ssize_t *shape):
"""
Makes Python tuple for C-contiguous array
"""
cdef tuple cc_strides = PyTuple_New(nd)
cdef object si = 1
cdef int i
cdef int nd_1 = nd - 1
for i in range(0, nd):
Py_INCREF(si) # SetItem steals the reference
PyTuple_SetItem(cc_strides, nd_1 - i, si)
si = si * shape[nd_1 - i]
return cc_strides


cdef object _f_contig_strides(int nd, Py_ssize_t *shape):
"""
Makes Python t
"""
cdef tuple fc_strides = PyTuple_New(nd)
cdef object si = 1
for i in range(0, nd):
Py_INCREF(si) # SetItem steals the reference
PyTuple_SetItem(fc_strides, i, si)
si = si * shape[i]
return fc_strides
Loading