Skip to content

Commit 3ccf31d

Browse files
authored
Merge branch 'master' into fix-lcm-test-on-iris-xe-win
2 parents 785adf0 + 63e641f commit 3ccf31d

File tree

4 files changed

+314
-91
lines changed

4 files changed

+314
-91
lines changed

dpnp/dpnp_array.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ def repeat(self, repeats, axis=None):
12861286

12871287
return dpnp.repeat(self, repeats, axis=axis)
12881288

1289-
def reshape(self, *sh, **kwargs):
1289+
def reshape(self, *shape, order="C", copy=None):
12901290
"""
12911291
Returns an array containing the same data with a new shape.
12921292
@@ -1311,9 +1311,9 @@ def reshape(self, *sh, **kwargs):
13111311
13121312
"""
13131313

1314-
if len(sh) == 1:
1315-
sh = sh[0]
1316-
return dpnp.reshape(self, sh, **kwargs)
1314+
if len(shape) == 1:
1315+
shape = shape[0]
1316+
return dpnp.reshape(self, shape, order=order, copy=copy)
13171317

13181318
# 'resize',
13191319

dpnp/dpnp_iface_manipulation.py

Lines changed: 124 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import math
4242
import operator
43+
import warnings
4344

4445
import dpctl.tensor as dpt
4546
import numpy
@@ -1848,23 +1849,50 @@ def ravel(a, order="C"):
18481849
x : {dpnp.ndarray, usm_ndarray}
18491850
Input array. The elements in `a` are read in the order specified by
18501851
order, and packed as a 1-D array.
1851-
order : {"C", "F"}, optional
1852+
order : {None, "C", "F", "A"}, optional
18521853
The elements of `a` are read using this index order. ``"C"`` means to
18531854
index the elements in row-major, C-style order, with the last axis
18541855
index changing fastest, back to the first axis index changing slowest.
18551856
``"F"`` means to index the elements in column-major, Fortran-style
18561857
order, with the first index changing fastest, and the last index
1857-
changing slowest. By default, ``"C"`` index order is used.
1858+
changing slowest. Note that the "C" and "F" options take no account of
1859+
the memory layout of the underlying array, and only refer to
1860+
the order of axis indexing. "A" means to read the elements in
1861+
Fortran-like index order if `a` is Fortran *contiguous* in
1862+
memory, C-like order otherwise. ``order=None`` is an alias for
1863+
``order="C"``.
1864+
Default: ``"C"``.
18581865
18591866
Returns
18601867
-------
18611868
out : dpnp.ndarray
18621869
A contiguous 1-D array of the same subtype as `a`, with shape (a.size,).
18631870
1871+
Limitations
1872+
-----------
1873+
`order="K"` is not supported and the function raises `NotImplementedError`
1874+
exception.
1875+
18641876
See Also
18651877
--------
1866-
:obj:`dpnp.reshape` : Change the shape of an array without changing its
1867-
data.
1878+
:obj:`dpnp.ndarray.flat` : 1-D iterator over an array.
1879+
:obj:`dpnp.ndarray.flatten` : 1-D array copy of the elements of an array
1880+
in row-major order.
1881+
:obj:`dpnp.ndarray.reshape` : Change the shape of an array without
1882+
changing its data.
1883+
:obj:`dpnp.reshape` : The same as :obj:`dpnp.ndarray.reshape`.
1884+
1885+
Notes
1886+
-----
1887+
In row-major, C-style order, in two dimensions, the row index
1888+
varies the slowest, and the column index the quickest. This can
1889+
be generalized to multiple dimensions, where row-major order
1890+
implies that the index along the first axis varies slowest, and
1891+
the index along the last quickest. The opposite holds for
1892+
column-major, Fortran-style index ordering.
1893+
1894+
When a view is desired in as many cases as possible, ``arr.reshape(-1)``
1895+
may be preferable.
18681896
18691897
Examples
18701898
--------
@@ -1879,9 +1907,27 @@ def ravel(a, order="C"):
18791907
>>> np.ravel(x, order='F')
18801908
array([1, 4, 2, 5, 3, 6])
18811909
1910+
When `order` is ``"A"``, it will preserve the array's
1911+
``"C"`` or ``"F"`` ordering:
1912+
1913+
>>> np.ravel(x.T)
1914+
array([1, 4, 2, 5, 3, 6])
1915+
>>> np.ravel(x.T, order='A')
1916+
array([1, 2, 3, 4, 5, 6])
1917+
18821918
"""
18831919

1884-
return dpnp.reshape(a, -1, order=order)
1920+
if order in "kK":
1921+
raise NotImplementedError(
1922+
"Keyword argument `order` is supported only with "
1923+
f"values None, 'C', 'F', and 'A', but got '{order}'"
1924+
)
1925+
1926+
result = dpnp.reshape(a, -1, order=order)
1927+
if result.flags.c_contiguous:
1928+
return result
1929+
1930+
return dpnp.ascontiguousarray(result)
18851931

18861932

18871933
def repeat(a, repeats, axis=None):
@@ -2055,7 +2101,7 @@ def require(a, dtype=None, requirements=None, *, like=None):
20552101
return arr
20562102

20572103

2058-
def reshape(a, /, newshape, order="C", copy=None):
2104+
def reshape(a, /, shape=None, order="C", *, newshape=None, copy=None):
20592105
"""
20602106
Gives a new shape to an array without changing its data.
20612107
@@ -2065,12 +2111,12 @@ def reshape(a, /, newshape, order="C", copy=None):
20652111
----------
20662112
a : {dpnp.ndarray, usm_ndarray}
20672113
Array to be reshaped.
2068-
newshape : int or tuple of ints
2114+
shape : int or tuple of ints
20692115
The new shape should be compatible with the original shape. If
20702116
an integer, then the result will be a 1-D array of that length.
20712117
One shape dimension can be -1. In this case, the value is
20722118
inferred from the length of the array and remaining dimensions.
2073-
order : {"C", "F"}, optional
2119+
order : {None, "C", "F", "A"}, optional
20742120
Read the elements of `a` using this index order, and place the
20752121
elements into the reshaped array using this index order. ``"C"``
20762122
means to read / write the elements using C-like index order,
@@ -2080,30 +2126,63 @@ def reshape(a, /, newshape, order="C", copy=None):
20802126
changing fastest, and the last index changing slowest. Note that
20812127
the ``"C"`` and ``"F"`` options take no account of the memory layout of
20822128
the underlying array, and only refer to the order of indexing.
2129+
``order=None`` is an alias for ``order="C"``. ``"A"`` means to
2130+
read / write the elements in Fortran-like index order if ``a`` is
2131+
Fortran *contiguous* in memory, C-like order otherwise.
2132+
Default: ``"C"``.
2133+
newshape : int or tuple of ints
2134+
Replaced by `shape` argument. Retained for backward compatibility.
20832135
copy : {None, bool}, optional
2084-
Boolean indicating whether or not to copy the input array.
2085-
If ``True``, the result array will always be a copy of input `a`.
2086-
If ``False``, the result array can never be a copy
2087-
and a ValueError exception will be raised in case the copy is necessary.
2088-
If ``None``, the result array will reuse existing memory buffer of `a`
2089-
if possible and copy otherwise.
2136+
If ``True``, then the array data is copied. If ``None``, a copy will
2137+
only be made if it's required by ``order``. For ``False`` it raises
2138+
a ``ValueError`` if a copy cannot be avoided.
20902139
Default: ``None``.
20912140
20922141
Returns
20932142
-------
20942143
out : dpnp.ndarray
20952144
This will be a new view object if possible; otherwise, it will
2096-
be a copy. Note there is no guarantee of the *memory layout* (C- or
2145+
be a copy. Note there is no guarantee of the *memory layout* (C- or
20972146
Fortran- contiguous) of the returned array.
20982147
2099-
Limitations
2100-
-----------
2101-
Parameter `order` is supported only with values ``"C"`` and ``"F"``.
2102-
21032148
See Also
21042149
--------
21052150
:obj:`dpnp.ndarray.reshape` : Equivalent method.
21062151
2152+
Notes
2153+
-----
2154+
It is not always possible to change the shape of an array without copying
2155+
the data.
2156+
2157+
The `order` keyword gives the index ordering both for *fetching*
2158+
the values from ``a``, and then *placing* the values into the output
2159+
array. For example, let's say you have an array:
2160+
2161+
>>> import dpnp as np
2162+
>>> a = np.arange(6).reshape((3, 2))
2163+
>>> a
2164+
array([[0, 1],
2165+
[2, 3],
2166+
[4, 5]])
2167+
2168+
You can think of reshaping as first raveling the array (using the given
2169+
index order), then inserting the elements from the raveled array into the
2170+
new array using the same kind of index ordering as was used for the
2171+
raveling.
2172+
2173+
>>> np.reshape(a, (2, 3)) # C-like index ordering
2174+
array([[0, 1, 2],
2175+
[3, 4, 5]])
2176+
>>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape
2177+
array([[0, 1, 2],
2178+
[3, 4, 5]])
2179+
>>> np.reshape(a, (2, 3), order='F') # Fortran-like index ordering
2180+
array([[0, 4, 3],
2181+
[2, 1, 5]])
2182+
>>> np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
2183+
array([[0, 4, 3],
2184+
[2, 1, 5]])
2185+
21072186
Examples
21082187
--------
21092188
>>> import dpnp as np
@@ -2120,16 +2199,38 @@ def reshape(a, /, newshape, order="C", copy=None):
21202199
21212200
"""
21222201

2123-
if newshape is None:
2124-
newshape = a.shape
2202+
if newshape is None and shape is None:
2203+
raise TypeError(
2204+
"reshape() missing 1 required positional argument: 'shape'"
2205+
)
2206+
2207+
if newshape is not None:
2208+
if shape is not None:
2209+
raise TypeError(
2210+
"You cannot specify 'newshape' and 'shape' arguments "
2211+
"at the same time."
2212+
)
2213+
# Deprecated in dpnp 0.17.0
2214+
warnings.warn(
2215+
"`newshape` keyword argument is deprecated, "
2216+
"use `shape=...` or pass shape positionally instead. "
2217+
"(deprecated in dpnp 0.17.0)",
2218+
DeprecationWarning,
2219+
stacklevel=2,
2220+
)
2221+
shape = newshape
21252222

21262223
if order is None:
21272224
order = "C"
2225+
elif order in "aA":
2226+
order = "F" if a.flags.fnc else "C"
21282227
elif order not in "cfCF":
2129-
raise ValueError(f"order must be one of 'C' or 'F' (got {order})")
2228+
raise ValueError(
2229+
f"order must be None, 'C', 'F', or 'A' (got '{order}')"
2230+
)
21302231

21312232
usm_a = dpnp.get_usm_ndarray(a)
2132-
usm_res = dpt.reshape(usm_a, shape=newshape, order=order, copy=copy)
2233+
usm_res = dpt.reshape(usm_a, shape=shape, order=order, copy=copy)
21332234
return dpnp_array._create_from_usm_ndarray(usm_res)
21342235

21352236

tests/test_manipulation.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,22 @@ def test_no_copy(self):
448448
assert_array_equal(b, a)
449449

450450

451+
class TestRavel:
452+
def test_error(self):
453+
ia = dpnp.arange(10).reshape(2, 5)
454+
assert_raises(NotImplementedError, dpnp.ravel, ia, order="K")
455+
456+
@pytest.mark.parametrize("order", ["C", "F", "A"])
457+
def test_non_contiguous(self, order):
458+
a = numpy.arange(10)[::2]
459+
ia = dpnp.arange(10)[::2]
460+
expected = numpy.ravel(a, order=order)
461+
result = dpnp.ravel(ia, order=order)
462+
assert result.flags.c_contiguous == expected.flags.c_contiguous
463+
assert result.flags.f_contiguous == expected.flags.f_contiguous
464+
assert_array_equal(result, expected)
465+
466+
451467
class TestRepeat:
452468
@pytest.mark.parametrize(
453469
"data",
@@ -790,6 +806,81 @@ def test_negative_resize(self, xp):
790806
xp.resize(a, new_shape=new_shape)
791807

792808

809+
class TestReshape:
810+
def test_error(self):
811+
ia = dpnp.arange(10)
812+
assert_raises(TypeError, dpnp.reshape, ia)
813+
assert_raises(
814+
TypeError, dpnp.reshape, ia, shape=(2, 5), newshape=(2, 5)
815+
)
816+
817+
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
818+
def test_newshape(self):
819+
a = numpy.arange(10)
820+
ia = dpnp.array(a)
821+
expected = numpy.reshape(a, (2, 5))
822+
result = dpnp.reshape(ia, newshape=(2, 5))
823+
assert_array_equal(result, expected)
824+
825+
@pytest.mark.parametrize("order", [None, "C", "F", "A"])
826+
def test_order(self, order):
827+
a = numpy.arange(10)
828+
ia = dpnp.array(a)
829+
expected = numpy.reshape(a, (2, 5), order)
830+
result = dpnp.reshape(ia, (2, 5), order)
831+
assert result.flags.c_contiguous == expected.flags.c_contiguous
832+
assert result.flags.f_contiguous == expected.flags.f_contiguous
833+
assert_array_equal(result, expected)
834+
835+
# ndarray
836+
result = ia.reshape(2, 5, order=order)
837+
assert result.flags.c_contiguous == expected.flags.c_contiguous
838+
assert result.flags.f_contiguous == expected.flags.f_contiguous
839+
assert_array_equal(result, expected)
840+
841+
def test_ndarray(self):
842+
a = numpy.arange(10)
843+
ia = dpnp.array(a)
844+
expected = a.reshape(2, 5)
845+
result = ia.reshape(2, 5)
846+
assert_array_equal(result, expected)
847+
848+
# packed
849+
result = ia.reshape((2, 5))
850+
assert_array_equal(result, expected)
851+
852+
@testing.with_requires("numpy>=2.0")
853+
def test_copy(self):
854+
a = numpy.arange(10).reshape(2, 5)
855+
ia = dpnp.array(a)
856+
expected = numpy.reshape(a, 10, copy=None)
857+
expected[0] = -1
858+
result = dpnp.reshape(ia, 10, copy=None)
859+
result[0] = -1
860+
assert a[0, 0] == expected[0] # a is also modified, no copy
861+
assert ia[0, 0] == result[0] # ia is also modified, no copy
862+
assert_array_equal(result, expected)
863+
864+
a = numpy.arange(10).reshape(2, 5)
865+
ia = dpnp.array(a)
866+
expected = numpy.reshape(a, 10, copy=True)
867+
expected[0] = -1
868+
result = dpnp.reshape(ia, 10, copy=True)
869+
result[0] = -1
870+
assert a[0, 0] != expected[0] # a is not modified, copy is done
871+
assert ia[0, 0] != result[0] # ia is not modified, copy is done
872+
assert_array_equal(result, expected)
873+
874+
a = numpy.arange(10).reshape(2, 5)
875+
ia = dpnp.array(a)
876+
assert_raises(
877+
ValueError, dpnp.reshape, ia, (5, 2), order="F", copy=False
878+
)
879+
assert_raises(
880+
ValueError, dpnp.reshape, ia, (5, 2), order="F", copy=False
881+
)
882+
883+
793884
class TestRot90:
794885
@pytest.mark.parametrize("xp", [numpy, dpnp])
795886
def test_error(self, xp):

0 commit comments

Comments
 (0)