assert a.flags["C_CONTIGUOUS"], "This function relies on the memory layout of the array."
blockshape = tuple(blockshape)
view_shape = tuple(numpy.array(a.shape) / blockshape) + blockshape
if require_aligned_blocks:
assert (numpy.mod(a.shape, blockshape) == 0).all(), \
"blockshape {} must divide evenly into array shape {}"\
.format( blockshape, a.shape )
// The code below is for the ND case.
// For example, in 4D, given shape=(t,z,y,x) and blockshape=(bt,bz,by,bx),
// we could have written this:
//
// intra_block_strides = a.itemsize * numpy.array([z*y*x, y*x, x, 1])
// inter_block_strides = a.itemsize * numpy.array([z*y*x*bt, y*x*bz, x*by, bx])
// strides within each block
intra_block_strides = [1]
for s in a.shape[-1:0:-1]:
intra_block_strides.append( s*intra_block_strides[-1] )
intra_block_strides = numpy.array(intra_block_strides[::-1])
// strides from one block to another
inter_block_strides = numpy.array(intra_block_strides) * blockshape
intra_block_strides *= a.itemsizeinter_block_strides *= a.itemsize
strides = tuple(inter_block_strides) + tuple(intra_block_strides)
// This is where the magic happens.
// Generate a view with our new strides.
return numpy.lib.stride_tricks.as_strided(a, shape=view_shape, strides=strides)