From a672aee409861b8a122ad891912bfd9de022a335 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 2 Mar 2022 17:28:42 +0300 Subject: [PATCH 1/4] Add permute_dims func --- docs/generate_rst.py | 1 + dpctl/tensor/__init__.py | 2 + dpctl/tensor/_manipulation_functions.py | 63 +++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 dpctl/tensor/_manipulation_functions.py diff --git a/docs/generate_rst.py b/docs/generate_rst.py index 1c80f4bc4a..e0676d26a5 100644 --- a/docs/generate_rst.py +++ b/docs/generate_rst.py @@ -45,6 +45,7 @@ "dpctl.tensor._copy_utils": "Array Construction", "dpctl.tensor._dlpack": "Array Construction", "dpctl.tensor._reshape": "Array Manipulation", + "dpctl.tensor._manipulation_functions": "Array Manipulation", "dpctl.memory._memory": "Functions", "dpctl.program._program": "Functions", "dpctl.utils._compute_follows_data": "Functions", diff --git a/dpctl/tensor/__init__.py b/dpctl/tensor/__init__.py index 7aee5ebad1..418abbfe27 100644 --- a/dpctl/tensor/__init__.py +++ b/dpctl/tensor/__init__.py @@ -25,6 +25,7 @@ from dpctl.tensor._ctors import asarray, empty from dpctl.tensor._device import Device from dpctl.tensor._dlpack import from_dlpack +from dpctl.tensor._manipulation_functions import permute_dims from dpctl.tensor._reshape import reshape from dpctl.tensor._usmarray import usm_ndarray @@ -36,6 +37,7 @@ "copy", "empty", "reshape", + "permute_dims", "from_numpy", "to_numpy", "asnumpy", diff --git a/dpctl/tensor/_manipulation_functions.py b/dpctl/tensor/_manipulation_functions.py new file mode 100644 index 0000000000..0e265df217 --- /dev/null +++ b/dpctl/tensor/_manipulation_functions.py @@ -0,0 +1,63 @@ +# 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 numpy as np + +import dpctl.tensor as dpt + + +def _check_value_of_axes(axes): + axes_len = len(axes) + check_array = np.zeros(axes_len) + for i in axes: + ii = i.__index__() + if ii < 0 or ii > axes_len or check_array[ii] != 0: + return False + check_array[ii] = 1 + return True + + +def permute_dims(X, axes): + """ + permute_dims(X: usm_ndarray, axes: tuple or list) -> usm_ndarray + + Permute the axes (dimensions) of an array; returns the permuted + array as a view. + """ + if not isinstance(X, dpt.usm_ndarray): + raise TypeError(f"Expected usm_ndarray type, got {type(X)}.") + if not isinstance(axes, (tuple, list)): + axes = (axes,) + if not X.ndim == len(axes): + raise ValueError( + "The length of the passed axes does not match " + "to the number of usm_ndarray dimensions." + ) + if not _check_value_of_axes(axes): + raise ValueError( + "The values of the axes must be in the range " + f"from 0 to {X.ndim} and have no duplicates." + ) + newstrides = [X.strides[i] for i in axes] + newshape = [X.shape[i] for i in axes] + return dpt.usm_ndarray( + shape=tuple(newshape), + dtype=X.dtype, + buffer=X, + strides=tuple(newstrides), + offset=X.__sycl_usm_array_interface__.get("offset", 0), + ) From 08643425c32e8dda7efaa423ec77507adaa5bb63 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 2 Mar 2022 17:29:58 +0300 Subject: [PATCH 2/4] Add tests for permute_dims func --- dpctl/tests/test_usm_ndarray_manipulation.py | 92 ++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 dpctl/tests/test_usm_ndarray_manipulation.py diff --git a/dpctl/tests/test_usm_ndarray_manipulation.py b/dpctl/tests/test_usm_ndarray_manipulation.py new file mode 100644 index 0000000000..39be876a7b --- /dev/null +++ b/dpctl/tests/test_usm_ndarray_manipulation.py @@ -0,0 +1,92 @@ +# 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 numpy as np +import pytest +from numpy.testing import assert_array_equal + +import dpctl +import dpctl.tensor as dpt + + +def test_permute_dims_incorrect_type(): + X_list = list([[1, 2, 3], [4, 5, 6]]) + X_tuple = tuple(X_list) + Xnp = np.array(X_list) + + pytest.raises(TypeError, dpt.permute_dims, X_list, (1, 0)) + pytest.raises(TypeError, dpt.permute_dims, X_tuple, (1, 0)) + pytest.raises(TypeError, dpt.permute_dims, Xnp, (1, 0)) + + +def test_permute_dims_empty_array(): + try: + q = dpctl.SyclQueue() + except dpctl.SyclQueueCreationError: + pytest.skip("Queue could not be created") + + Xnp = np.empty((10, 0)) + X = dpt.asarray(Xnp, sycl_queue=q) + Y = dpt.permute_dims(X, (1, 0)) + Ynp = np.transpose(Xnp, (1, 0)) + assert_array_equal(Ynp, dpt.asnumpy(Y)) + + +def test_permute_dims_0d_1d(): + try: + q = dpctl.SyclQueue() + except dpctl.SyclQueueCreationError: + pytest.skip("Queue could not be created") + + Xnp_0d = np.array(1, dtype="int64") + X_0d = dpt.asarray(Xnp_0d, sycl_queue=q) + Y_0d = dpt.permute_dims(X_0d, ()) + assert_array_equal(dpt.asnumpy(Y_0d), dpt.asnumpy(X_0d)) + + Xnp_1d = np.random.randint(0, 2, size=6, dtype="int64") + X_1d = dpt.asarray(Xnp_1d, sycl_queue=q) + Y_1d = dpt.permute_dims(X_1d, (0)) + assert_array_equal(dpt.asnumpy(Y_1d), dpt.asnumpy(X_1d)) + + pytest.raises(ValueError, dpt.permute_dims, X_1d, ()) + pytest.raises(IndexError, dpt.permute_dims, X_1d, (1)) + pytest.raises(ValueError, dpt.permute_dims, X_1d, (1, 0)) + pytest.raises( + ValueError, dpt.permute_dims, dpt.reshape(X_1d, (2, 3)), (1, 1) + ) + + +@pytest.mark.parametrize("shapes", [(2, 2), (1, 4), (3, 3, 3), (4, 1, 3)]) +def test_permute_dims_2d_3d(shapes): + try: + q = dpctl.SyclQueue() + except dpctl.SyclQueueCreationError: + pytest.skip("Queue could not be created") + + Xnp_size = np.prod(shapes) + + Xnp = np.random.randint(0, 2, size=Xnp_size, dtype="int64").reshape(shapes) + X = dpt.asarray(Xnp, sycl_queue=q) + X_ndim = X.ndim + if X_ndim == 2: + Y = dpt.permute_dims(X, (1, 0)) + Ynp = np.transpose(Xnp, (1, 0)) + elif X_ndim == 3: + X = dpt.asarray(Xnp, sycl_queue=q) + Y = dpt.permute_dims(X, (2, 0, 1)) + Ynp = np.transpose(Xnp, (2, 0, 1)) + assert_array_equal(Ynp, dpt.asnumpy(Y)) From 4c5b1d17deea9d29a1ba1aa8051c724543649e7f Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 4 Mar 2022 11:13:18 -0600 Subject: [PATCH 3/4] attempt to triage failed documentation build --- .github/workflows/generate-docs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index adf8717192..9581458ab7 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -112,7 +112,7 @@ jobs: git config --global user.email 'github-actions[doc-deploy-bot]@users.noreply.github.com' git commit -m "Docs for pull request ${PR_NUM}" git push tokened_docs gh-pages - - name: Unpublished pull-request docs + - name: Unpublish pull-request docs if: ${{ github.event.pull_request && github.event.action == 'closed' }} env: PR_NUM: ${{ github.event.number }} @@ -122,6 +122,8 @@ jobs: git fetch tokened_docs git checkout --track tokened_docs/gh-pages echo `pwd` + ls + [ -d pulls ] && ls pulls && echo "This is pull/${PR_NUM}" [ -d pulls/${PR_NUM} ] && git rm -rf pulls/${PR_NUM} git config --global user.name 'github-actions[doc-deploy-bot]' git config --global user.email 'github-actions[doc-deploy-bot]@users.noreply.github.com' From 26107bf5185e4a74eae79da49565fc087b931d02 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 4 Mar 2022 20:14:20 -0600 Subject: [PATCH 4/4] No need to create temporary lists --- dpctl/tensor/_manipulation_functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dpctl/tensor/_manipulation_functions.py b/dpctl/tensor/_manipulation_functions.py index 0e265df217..91effa01ce 100644 --- a/dpctl/tensor/_manipulation_functions.py +++ b/dpctl/tensor/_manipulation_functions.py @@ -52,12 +52,12 @@ def permute_dims(X, axes): "The values of the axes must be in the range " f"from 0 to {X.ndim} and have no duplicates." ) - newstrides = [X.strides[i] for i in axes] - newshape = [X.shape[i] for i in axes] + newstrides = tuple(X.strides[i] for i in axes) + newshape = tuple(X.shape[i] for i in axes) return dpt.usm_ndarray( - shape=tuple(newshape), + shape=newshape, dtype=X.dtype, buffer=X, - strides=tuple(newstrides), + strides=newstrides, offset=X.__sycl_usm_array_interface__.get("offset", 0), )