Skip to content

Commit 10311c3

Browse files
Merge 7e0a38c into 48515c8
2 parents 48515c8 + 7e0a38c commit 10311c3

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

dpnp/dpnp_array.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ def T(self):
108108
"""View of the transposed array."""
109109
return self.transpose()
110110

111+
@property
112+
def mT(self):
113+
"""View of the matrix transposed array."""
114+
if self.ndim < 2:
115+
raise ValueError("matrix transpose with ndim < 2 is undefined")
116+
117+
return self.swapaxes(-1, -2)
118+
111119
def to_device(self, target_device):
112120
"""Transfer array to target device."""
113121

dpnp/dpnp_iface_manipulation.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"flipud",
7373
"hsplit",
7474
"hstack",
75+
"matrix_transpose",
7576
"moveaxis",
7677
"ndim",
7778
"permute_dims",
@@ -1751,6 +1752,53 @@ def hstack(tup, *, dtype=None, casting="same_kind"):
17511752
return dpnp.concatenate(arrs, axis=1, dtype=dtype, casting=casting)
17521753

17531754

1755+
def matrix_transpose(x, /):
1756+
"""
1757+
Transposes a matrix (or a stack of matrices) ``x``.
1758+
1759+
For full documentation refer to :obj:`numpy.matrix_transpose`.
1760+
1761+
Parameters
1762+
----------
1763+
x : (..., M, N) {dpnp.ndarray, usm_ndarray}
1764+
Input array with ``x.ndim >= 2` and whose two innermost
1765+
dimensions form ``MxN`` matrices.
1766+
1767+
Returns
1768+
-------
1769+
out : dpnp.ndarray
1770+
An array containing the transpose for each matrix and having shape
1771+
(..., N, M).
1772+
1773+
See Also
1774+
--------
1775+
:obj:`dpnp.transpose` : Returns an array with axes transposed.
1776+
1777+
Examples
1778+
--------
1779+
>>> import dpnp as np
1780+
>>> a = np.array([[1, 2], [3, 4]])
1781+
>>> np.matrix_transpose(a)
1782+
array([[1, 3],
1783+
[2, 4]])
1784+
1785+
>>> b = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
1786+
>>> np.matrix_transpose(b)
1787+
array([[[1, 3],
1788+
[2, 4]],
1789+
[[5, 7],
1790+
[6, 8]]])
1791+
1792+
"""
1793+
1794+
dpnp.check_supported_arrays_type(x)
1795+
if x.ndim < 2:
1796+
raise ValueError(
1797+
f"Input array must be at least 2-dimensional, but it is {x.ndim}"
1798+
)
1799+
return dpnp.swapaxes(x, -1, -2)
1800+
1801+
17541802
def moveaxis(a, source, destination):
17551803
"""
17561804
Move axes of an array to new positions. Other axes remain in their original

tests/test_arraymanipulation.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,50 @@ def test_one_element(self):
556556
assert_array_equal(res, a)
557557

558558

559+
# numpy.matrix_transpose() is available since numpy >= 2.0
560+
@testing.with_requires("numpy>=2.0")
561+
class TestMatrixtranspose:
562+
@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
563+
@pytest.mark.parametrize(
564+
"shape",
565+
[(3, 5), (4, 2), (2, 5, 2), (2, 3, 3, 6)],
566+
ids=["(3,5)", "(4,2)", "(2,5,2)", "(2,3,3,6)"],
567+
)
568+
def test_matrix_transpose(self, dtype, shape):
569+
a = numpy.arange(numpy.prod(shape), dtype=dtype).reshape(shape)
570+
dp_a = dpnp.array(a)
571+
572+
expected = numpy.matrix_transpose(a)
573+
result = dpnp.matrix_transpose(dp_a)
574+
575+
assert_allclose(result, expected)
576+
577+
@pytest.mark.parametrize(
578+
"shape",
579+
[(0, 0), (1, 0, 0), (0, 2, 2), (0, 1, 0, 4)],
580+
ids=["(0,0)", "(1,0,0)", "(0,2,2)", "(0, 1, 0, 4)"],
581+
)
582+
def test_matrix_transpose_empty(self, shape):
583+
a = numpy.empty(shape, dtype=dpnp.default_float_type())
584+
dp_a = dpnp.array(a)
585+
586+
expected = numpy.matrix_transpose(a)
587+
result = dpnp.matrix_transpose(dp_a)
588+
589+
assert_allclose(result, expected)
590+
591+
def test_matrix_transpose_errors(self):
592+
a_dp = dpnp.array([[1, 2], [3, 4]], dtype="float32")
593+
594+
# unsupported type
595+
a_np = dpnp.asnumpy(a_dp)
596+
assert_raises(TypeError, dpnp.matrix_transpose, a_np)
597+
598+
# a.ndim < 2
599+
a_dp_ndim_1 = a_dp.flatten()
600+
assert_raises(ValueError, dpnp.matrix_transpose, a_dp_ndim_1)
601+
602+
559603
class TestRollaxis:
560604
data = [
561605
(0, 0),

tests/test_ndarray.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from numpy.testing import assert_allclose, assert_array_equal
55

66
import dpnp
7+
from tests.third_party.cupy import testing
78

89
from .helper import (
910
get_all_dtypes,
@@ -258,6 +259,38 @@ def test_array_as_index(shape, index_dtype):
258259
assert a[tuple(ind_arr)] == a[1]
259260

260261

262+
# numpy.matrix_transpose() is available since numpy >= 2.0
263+
@testing.with_requires("numpy>=2.0")
264+
@pytest.mark.parametrize(
265+
"shape",
266+
[(3, 5), (2, 5, 2), (2, 3, 3, 6)],
267+
ids=["(3,5)", "(2,5,2)", "(2,3,3,6)"],
268+
)
269+
def test_matrix_transpose(shape):
270+
a = numpy.arange(numpy.prod(shape)).reshape(shape)
271+
dp_a = dpnp.array(a)
272+
273+
expected = a.mT
274+
result = dp_a.mT
275+
276+
assert_allclose(result, expected)
277+
278+
# result is a view of dp_a:
279+
# changing result, modifies dp_a
280+
first_elem = (0,) * dp_a.ndim
281+
282+
result[first_elem] = -1.0
283+
assert dp_a[first_elem] == -1.0
284+
285+
286+
@testing.with_requires("numpy>=2.0")
287+
def test_matrix_transpose_error():
288+
# 1D array
289+
dp_a = dpnp.arange(6)
290+
with pytest.raises(ValueError):
291+
dp_a.mT
292+
293+
261294
def test_ravel():
262295
a = dpnp.ones((2, 2))
263296
b = a.ravel()

0 commit comments

Comments
 (0)