Skip to content

Improve logic of dpnp.outer() #1239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 1, 2022
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
14 changes: 10 additions & 4 deletions dpnp/dpnp_iface_linearalgebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"""


from dpnp.dpnp_array import dpnp_array
from dpnp.dpnp_algo import *
from dpnp.dpnp_utils import *
import dpnp
Expand Down Expand Up @@ -312,10 +313,15 @@ def outer(x1, x2, **kwargs):

"""

x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_nondefault_queue=False)
if x1_desc and x2_desc and not kwargs:
return dpnp_outer(x1_desc, x2_desc).get_pyobj()
if not kwargs:
if isinstance(x1, dpnp_array) and isinstance(x2, dpnp_array):
ravel = lambda x: x.flatten() if x.ndim > 1 else x
return ravel(x1)[:, None] * ravel(x2)[None, :]

x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
x2_desc = dpnp.get_dpnp_descriptor(x2, copy_when_nondefault_queue=False)
if x1_desc and x2_desc:
return dpnp_outer(x1_desc, x2_desc).get_pyobj()

return call_origin(numpy.outer, x1, x2, **kwargs)

Expand Down
4 changes: 1 addition & 3 deletions tests/skipped_tests_gpu.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ tests/third_party/cupy/linalg_tests/test_einsum.py::TestEinSumError::test_too_fe
tests/third_party/cupy/linalg_tests/test_einsum.py::TestEinSumError::test_too_many_dimension3
tests/third_party/cupy/linalg_tests/test_einsum.py::TestListArgEinSumError::test_dim_mismatch3
tests/third_party/cupy/linalg_tests/test_einsum.py::TestListArgEinSumError::test_too_many_dims3
tests/third_party/cupy/linalg_tests/test_product.py::TestProduct::test_outer

tests/third_party/cupy/linalg_tests/test_product.py::TestProduct::test_reversed_outer
tests/third_party/cupy/linalg_tests/test_product.py::TestProduct::test_reversed_vdot
tests/third_party/cupy/manipulation_tests/test_basic.py::TestCopytoFromScalar_param_7_{dst_shape=(0,), src=3.2}::test_copyto_where
Expand Down Expand Up @@ -347,8 +347,6 @@ tests/third_party/cupy/sorting_tests/test_sort.py::TestPartition_param_2_{extern
tests/third_party/cupy/statistics_tests/test_correlation.py::TestCov::test_cov_empty
tests/third_party/cupy/statistics_tests/test_meanvar.py::TestMeanVar::test_external_mean_axis

tests/third_party/cupy/linalg_tests/test_product.py::TestProduct::test_multidim_outer

tests/third_party/cupy/sorting_tests/test_sort.py::TestPartition_param_3_{external=True, length=20000}::test_partition_axis
tests/third_party/cupy/sorting_tests/test_sort.py::TestPartition_param_3_{external=True, length=20000}::test_partition_negative_axis
tests/third_party/cupy/sorting_tests/test_sort.py::TestPartition_param_3_{external=True, length=20000}::test_partition_none_axis
Expand Down
77 changes: 77 additions & 0 deletions tests/test_outer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import unittest
from tests.third_party.cupy import testing

import dpnp as dp
import numpy as np

from numpy.testing import assert_raises


class TestOuter(unittest.TestCase):

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_two_vectors(self, xp, dtype):
a = xp.ones((10, ), dtype=dtype)
b = xp.linspace(-2, 2, 5, dtype=dtype)

return xp.outer(a, b)

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_two_matrix(self, xp, dtype):
a = xp.ones((10, 10, 10), dtype=dtype)
b = xp.full(shape=(3, 7), fill_value=42, dtype=dtype)

return xp.outer(a, b)

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_the_same_vector(self, xp, dtype):
a = xp.full(shape=(100, ), fill_value=7, dtype=dtype)
return xp.outer(a, a)

@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_the_same_matrix(self, xp, dtype):
a = xp.arange(27, dtype=dtype).reshape(3, 3, 3)
return xp.outer(a, a)


class TestScalarOuter(unittest.TestCase):

@unittest.skip("A scalar isn't currently supported as input")
@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_first_is_scalar(self, xp, dtype):
scalar = xp.int64(4)
a = xp.arange(5**3, dtype=dtype).reshape(5, 5, 5)
return xp.outer(scalar, a)

@unittest.skip("A scalar isn't currently supported as input")
@testing.for_all_dtypes()
@testing.numpy_cupy_allclose()
def test_second_is_scalar(self, xp, dtype):
scalar = xp.int32(7)
a = xp.arange(5**3, dtype=dtype).reshape(5, 5, 5)
return xp.outer(a, scalar)

@unittest.skip("A scalar isn't currently supported as input")
@testing.numpy_cupy_array_equal()
def test_both_inputs_as_scalar(self, xp):
a = xp.int64(4)
b = xp.int32(17)
return xp.outer(a, b)


class TestListOuter(unittest.TestCase):

def test_list(self):
a = np.arange(27).reshape(3, 3, 3)
b: list[list[list[int]]] = a.tolist()
dp_a = dp.array(a)

with assert_raises(NotImplementedError):
dp.outer(b, dp_a)
dp.outer(dp_a, b)
dp.outer(b, b)
15 changes: 8 additions & 7 deletions tests/test_sycl_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ def test_1in_1out(func, data, device):
pytest.param("fmod",
[-3., -2., -1., 1., 2., 3.],
[2., 2., 2., 2., 2., 2.]),
pytest.param("matmul",
[[1., 0.], [0., 1.]],
[[4., 1.], [1., 2.]]),
pytest.param("maximum",
[2., 3., 4.],
[1., 5., 2.]),
Expand All @@ -189,6 +192,9 @@ def test_1in_1out(func, data, device):
pytest.param("multiply",
[0., 1., 2., 3., 4., 5., 6., 7., 8.],
[0., 1., 2., 0., 1., 2., 0., 1., 2.]),
pytest.param("outer",
[0., 1., 2., 3., 4., 5.],
[0., 1., 2., 0.]),
pytest.param("power",
[0., 1., 2., 3., 4., 5.],
[1., 2., 3., 3., 2., 1.]),
Expand All @@ -198,9 +204,6 @@ def test_1in_1out(func, data, device):
pytest.param("subtract",
[0., 1., 2., 3., 4., 5., 6., 7., 8.],
[0., 1., 2., 0., 1., 2., 0., 1., 2.]),
pytest.param("matmul",
[[1., 0.], [0., 1.]],
[[4., 1.], [1., 2.]]),
],
)
@pytest.mark.parametrize("device",
Expand All @@ -217,10 +220,8 @@ def test_2in_1out(func, data1, data2, device):

numpy.testing.assert_array_equal(result, expected)

expected_queue = x1.get_array().sycl_queue
result_queue = result.get_array().sycl_queue

assert_sycl_queue_equal(result_queue, expected_queue)
assert_sycl_queue_equal(result.sycl_queue, x1.sycl_queue)
assert_sycl_queue_equal(result.sycl_queue, x2.sycl_queue)


@pytest.mark.parametrize(
Expand Down