Skip to content

Commit 6d1757c

Browse files
Merge master into impl_matrix_transpose
2 parents 86d18f2 + 63e641f commit 6d1757c

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
@@ -1329,7 +1329,7 @@ def repeat(self, repeats, axis=None):
13291329

13301330
return dpnp.repeat(self, repeats, axis=axis)
13311331

1332-
def reshape(self, *sh, **kwargs):
1332+
def reshape(self, *shape, order="C", copy=None):
13331333
"""
13341334
Returns an array containing the same data with a new shape.
13351335
@@ -1354,9 +1354,9 @@ def reshape(self, *sh, **kwargs):
13541354
13551355
"""
13561356

1357-
if len(sh) == 1:
1358-
sh = sh[0]
1359-
return dpnp.reshape(self, sh, **kwargs)
1357+
if len(shape) == 1:
1358+
shape = shape[0]
1359+
return dpnp.reshape(self, shape, order=order, copy=copy)
13601360

13611361
# 'resize',
13621362

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
@@ -1898,23 +1899,50 @@ def ravel(a, order="C"):
18981899
x : {dpnp.ndarray, usm_ndarray}
18991900
Input array. The elements in `a` are read in the order specified by
19001901
order, and packed as a 1-D array.
1901-
order : {"C", "F"}, optional
1902+
order : {None, "C", "F", "A"}, optional
19021903
The elements of `a` are read using this index order. ``"C"`` means to
19031904
index the elements in row-major, C-style order, with the last axis
19041905
index changing fastest, back to the first axis index changing slowest.
19051906
``"F"`` means to index the elements in column-major, Fortran-style
19061907
order, with the first index changing fastest, and the last index
1907-
changing slowest. By default, ``"C"`` index order is used.
1908+
changing slowest. Note that the "C" and "F" options take no account of
1909+
the memory layout of the underlying array, and only refer to
1910+
the order of axis indexing. "A" means to read the elements in
1911+
Fortran-like index order if `a` is Fortran *contiguous* in
1912+
memory, C-like order otherwise. ``order=None`` is an alias for
1913+
``order="C"``.
1914+
Default: ``"C"``.
19081915
19091916
Returns
19101917
-------
19111918
out : dpnp.ndarray
19121919
A contiguous 1-D array of the same subtype as `a`, with shape (a.size,).
19131920
1921+
Limitations
1922+
-----------
1923+
`order="K"` is not supported and the function raises `NotImplementedError`
1924+
exception.
1925+
19141926
See Also
19151927
--------
1916-
:obj:`dpnp.reshape` : Change the shape of an array without changing its
1917-
data.
1928+
:obj:`dpnp.ndarray.flat` : 1-D iterator over an array.
1929+
:obj:`dpnp.ndarray.flatten` : 1-D array copy of the elements of an array
1930+
in row-major order.
1931+
:obj:`dpnp.ndarray.reshape` : Change the shape of an array without
1932+
changing its data.
1933+
:obj:`dpnp.reshape` : The same as :obj:`dpnp.ndarray.reshape`.
1934+
1935+
Notes
1936+
-----
1937+
In row-major, C-style order, in two dimensions, the row index
1938+
varies the slowest, and the column index the quickest. This can
1939+
be generalized to multiple dimensions, where row-major order
1940+
implies that the index along the first axis varies slowest, and
1941+
the index along the last quickest. The opposite holds for
1942+
column-major, Fortran-style index ordering.
1943+
1944+
When a view is desired in as many cases as possible, ``arr.reshape(-1)``
1945+
may be preferable.
19181946
19191947
Examples
19201948
--------
@@ -1929,9 +1957,27 @@ def ravel(a, order="C"):
19291957
>>> np.ravel(x, order='F')
19301958
array([1, 4, 2, 5, 3, 6])
19311959
1960+
When `order` is ``"A"``, it will preserve the array's
1961+
``"C"`` or ``"F"`` ordering:
1962+
1963+
>>> np.ravel(x.T)
1964+
array([1, 4, 2, 5, 3, 6])
1965+
>>> np.ravel(x.T, order='A')
1966+
array([1, 2, 3, 4, 5, 6])
1967+
19321968
"""
19331969

1934-
return dpnp.reshape(a, -1, order=order)
1970+
if order in "kK":
1971+
raise NotImplementedError(
1972+
"Keyword argument `order` is supported only with "
1973+
f"values None, 'C', 'F', and 'A', but got '{order}'"
1974+
)
1975+
1976+
result = dpnp.reshape(a, -1, order=order)
1977+
if result.flags.c_contiguous:
1978+
return result
1979+
1980+
return dpnp.ascontiguousarray(result)
19351981

19361982

19371983
def repeat(a, repeats, axis=None):
@@ -2105,7 +2151,7 @@ def require(a, dtype=None, requirements=None, *, like=None):
21052151
return arr
21062152

21072153

2108-
def reshape(a, /, newshape, order="C", copy=None):
2154+
def reshape(a, /, shape=None, order="C", *, newshape=None, copy=None):
21092155
"""
21102156
Gives a new shape to an array without changing its data.
21112157
@@ -2115,12 +2161,12 @@ def reshape(a, /, newshape, order="C", copy=None):
21152161
----------
21162162
a : {dpnp.ndarray, usm_ndarray}
21172163
Array to be reshaped.
2118-
newshape : int or tuple of ints
2164+
shape : int or tuple of ints
21192165
The new shape should be compatible with the original shape. If
21202166
an integer, then the result will be a 1-D array of that length.
21212167
One shape dimension can be -1. In this case, the value is
21222168
inferred from the length of the array and remaining dimensions.
2123-
order : {"C", "F"}, optional
2169+
order : {None, "C", "F", "A"}, optional
21242170
Read the elements of `a` using this index order, and place the
21252171
elements into the reshaped array using this index order. ``"C"``
21262172
means to read / write the elements using C-like index order,
@@ -2130,30 +2176,63 @@ def reshape(a, /, newshape, order="C", copy=None):
21302176
changing fastest, and the last index changing slowest. Note that
21312177
the ``"C"`` and ``"F"`` options take no account of the memory layout of
21322178
the underlying array, and only refer to the order of indexing.
2179+
``order=None`` is an alias for ``order="C"``. ``"A"`` means to
2180+
read / write the elements in Fortran-like index order if ``a`` is
2181+
Fortran *contiguous* in memory, C-like order otherwise.
2182+
Default: ``"C"``.
2183+
newshape : int or tuple of ints
2184+
Replaced by `shape` argument. Retained for backward compatibility.
21332185
copy : {None, bool}, optional
2134-
Boolean indicating whether or not to copy the input array.
2135-
If ``True``, the result array will always be a copy of input `a`.
2136-
If ``False``, the result array can never be a copy
2137-
and a ValueError exception will be raised in case the copy is necessary.
2138-
If ``None``, the result array will reuse existing memory buffer of `a`
2139-
if possible and copy otherwise.
2186+
If ``True``, then the array data is copied. If ``None``, a copy will
2187+
only be made if it's required by ``order``. For ``False`` it raises
2188+
a ``ValueError`` if a copy cannot be avoided.
21402189
Default: ``None``.
21412190
21422191
Returns
21432192
-------
21442193
out : dpnp.ndarray
21452194
This will be a new view object if possible; otherwise, it will
2146-
be a copy. Note there is no guarantee of the *memory layout* (C- or
2195+
be a copy. Note there is no guarantee of the *memory layout* (C- or
21472196
Fortran- contiguous) of the returned array.
21482197
2149-
Limitations
2150-
-----------
2151-
Parameter `order` is supported only with values ``"C"`` and ``"F"``.
2152-
21532198
See Also
21542199
--------
21552200
:obj:`dpnp.ndarray.reshape` : Equivalent method.
21562201
2202+
Notes
2203+
-----
2204+
It is not always possible to change the shape of an array without copying
2205+
the data.
2206+
2207+
The `order` keyword gives the index ordering both for *fetching*
2208+
the values from ``a``, and then *placing* the values into the output
2209+
array. For example, let's say you have an array:
2210+
2211+
>>> import dpnp as np
2212+
>>> a = np.arange(6).reshape((3, 2))
2213+
>>> a
2214+
array([[0, 1],
2215+
[2, 3],
2216+
[4, 5]])
2217+
2218+
You can think of reshaping as first raveling the array (using the given
2219+
index order), then inserting the elements from the raveled array into the
2220+
new array using the same kind of index ordering as was used for the
2221+
raveling.
2222+
2223+
>>> np.reshape(a, (2, 3)) # C-like index ordering
2224+
array([[0, 1, 2],
2225+
[3, 4, 5]])
2226+
>>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape
2227+
array([[0, 1, 2],
2228+
[3, 4, 5]])
2229+
>>> np.reshape(a, (2, 3), order='F') # Fortran-like index ordering
2230+
array([[0, 4, 3],
2231+
[2, 1, 5]])
2232+
>>> np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
2233+
array([[0, 4, 3],
2234+
[2, 1, 5]])
2235+
21572236
Examples
21582237
--------
21592238
>>> import dpnp as np
@@ -2170,16 +2249,38 @@ def reshape(a, /, newshape, order="C", copy=None):
21702249
21712250
"""
21722251

2173-
if newshape is None:
2174-
newshape = a.shape
2252+
if newshape is None and shape is None:
2253+
raise TypeError(
2254+
"reshape() missing 1 required positional argument: 'shape'"
2255+
)
2256+
2257+
if newshape is not None:
2258+
if shape is not None:
2259+
raise TypeError(
2260+
"You cannot specify 'newshape' and 'shape' arguments "
2261+
"at the same time."
2262+
)
2263+
# Deprecated in dpnp 0.17.0
2264+
warnings.warn(
2265+
"`newshape` keyword argument is deprecated, "
2266+
"use `shape=...` or pass shape positionally instead. "
2267+
"(deprecated in dpnp 0.17.0)",
2268+
DeprecationWarning,
2269+
stacklevel=2,
2270+
)
2271+
shape = newshape
21752272

21762273
if order is None:
21772274
order = "C"
2275+
elif order in "aA":
2276+
order = "F" if a.flags.fnc else "C"
21782277
elif order not in "cfCF":
2179-
raise ValueError(f"order must be one of 'C' or 'F' (got {order})")
2278+
raise ValueError(
2279+
f"order must be None, 'C', 'F', or 'A' (got '{order}')"
2280+
)
21802281

21812282
usm_a = dpnp.get_usm_ndarray(a)
2182-
usm_res = dpt.reshape(usm_a, shape=newshape, order=order, copy=copy)
2283+
usm_res = dpt.reshape(usm_a, shape=shape, order=order, copy=copy)
21832284
return dpnp_array._create_from_usm_ndarray(usm_res)
21842285

21852286

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)