10000 Merge pull request #2950 from seberg/issue-2949 · numpy/numpy@0934653 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0934653

Browse files
committed
Merge pull request #2950 from seberg/issue-2949
BUG: Fix strides of trailing 1s when reshaping
2 parents 22decf9 + 49bf204 commit 0934653

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

numpy/core/src/multiarray/shape.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,14 @@ _attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims,
355355
int oldnd;
356356
npy_intp olddims[NPY_MAXDIMS];
357357
npy_intp oldstrides[NPY_MAXDIMS];
358-
npy_intp np, op;
358+
npy_intp np, op, last_stride;
359359
int oi, oj, ok, ni, nj, nk;
360360

361361
oldnd = 0;
362+
/*
363+
* Remove axes with dimension 1 from the old array. They have no effect
364+
* but would need special cases since their strides do not matter.
365+
*/
362366
for (oi = 0; oi < PyArray_NDIM(self); oi++) {
363367
if (PyArray_DIMS(self)[oi]!= 1) {
364368
olddims[oldnd] = PyArray_DIMS(self)[oi];
@@ -390,27 +394,31 @@ _attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims,
390394
/* different total sizes; no hope */
391395
return 0;
392396
}
393-
/* the current code does not handle 0-sized arrays, so give up */
397+
394398
if (np == 0) {
399+
/* the current code does not handle 0-sized arrays, so give up */
395400
return 0;
396401
}
397402

403+
/* oi to oj and ni to nj give the axis ranges currently worked with */
398404
oi = 0;
399405
oj = 1;
400406
ni = 0;
401407
nj = 1;
402-
while(ni < newnd && oi < oldnd) {
408+
while (ni < newnd && oi < oldnd) {
403409
np = newdims[ni];
404410
op = olddims[oi];
405411

406412
while (np != op) {
407413
if (np < op) {
414+
/* Misses trailing 1s, these are handled later */
408415
np *= newdims[nj++];
409416
} else {
410417
op *= olddims[oj++];
411418
}
412419
}
413420

421+
/* Check whether the original axes can be combined */
414422
for (ok = oi; ok < oj - 1; ok++) {
415423
if (is_f_order) {
416424
if (oldstrides[ok+1] != olddims[ok]*oldstrides[ok]) {
@@ -427,6 +435,7 @@ _attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims,
427435
}
428436
}
429437

438+
/* Calculate new strides for all axes currently worked with */
430439
if (is_f_order) {
431440
newstrides[ni] = oldstrides[oi];
432441
for (nk = ni + 1; nk < nj; nk++) {
@@ -444,6 +453,22 @@ _attempt_nocopy_reshape(PyArrayObject *self, int newnd, npy_intp* newdims,
444453
oi = oj++;
445454
}
446455

456+
/*
457+
* Set strides corresponding to trailing 1s of the new shape.
458+
*/
459+
if (ni >= 1) {
460+
last_stride = newstrides[ni - 1];
461+
}
462+
else {
463+
last_stride = PyArray_ITEMSIZE(self);
464+
}
465+
if (is_f_order) {
466+
last_stride *= newdims[ni - 1];
467+
}
468+
for (nk = ni; nk < newnd; nk++) {
469+
newstrides[nk] = last_stride;
470+
}
471+
447472
/*
448473
fprintf(stderr, "success: _attempt_nocopy_reshape (");
449474
for (oi=0; oi<oldnd; oi++)

numpy/core/tests/test_regression.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,15 @@ def test_reshape_zero_size(self, level=rlevel):
545545
a = np.ones((0,2))
546546
a.shape = (-1,2)
547547

548+
def test_reshape_trailing_ones_strides(self):
549+
# Github issue gh-2949, bad strides for trailing ones of new shape
550+
a = np.zeros(12, dtype=np.int32)[::2] # not contiguous
551+
strides_c = (16, 8, 8, 8)
552+
strides_f = (8, 24, 48, 48)
553+
assert_equal(a.reshape(3, 2, 1, 1).strides, strides_c)
554+
assert_equal(a.reshape(3, 2, 1, 1, order='F').strides, strides_f)
555+
assert_equal(np.array(0, dtype=np.int32).reshape(1,1).strides, (4,4))
556+
548557
def test_repeat_discont(self, level=rlevel):
549558
"""Ticket #352"""
550559
a = np.arange(12).reshape(4,3)[:,2]

0 commit comments

Comments
 (0)
0