ML Foundations
When NumPy reshape shares memory and indexing does not
A reshaped feature array can alias the original data, while integer-array selection makes a copy. Inspect both before mutating a pipeline intermediate.
Evidence and testing
Review record: Tensor Almanac automated evidence gate (no independent human review). Example versions, recorded outputs and limitations appear below.
The same values do not establish the same ownership
Suppose a preprocessing step reshapes a feature vector before applying an in-place normalization or cleanup. You may think the intermediate is an independent array because it has a different shape. In NumPy that assumption can be wrong. An ndarray has a data buffer and metadata describing its shape and strides. Two distinct array objects can describe the same underlying memory, so changing one can change values observed through the other. [1]
The important engineering question is not whether the result prints with the intended dimensions. It is whether the operation returned a view sharing existing storage or a copy with its own storage. Reshape can return either, depending on whether the required element layout can be represented with strides. Treat the ownership relationship as something to verify when a later step mutates the array. [1]
References: [1]
Reproduce a view and a copy with one small test
Begin with twelve consecutive integers. Reshaping that contiguous one-dimensional array into three rows and four columns shares storage in this example. Selecting the elements at indices 0, 2, 4 and 6 with an integer index array instead performs advanced indexing, which creates a copy. The subsequent reshape of that selected result does not reattach it to the original. [1, 2]
The script performs a direct memory-sharing check on both results, changes one value through each result, then verifies what the original array actually contains. This is an executed CPU example, not a timing experiment or a claim about the memory footprint of a larger training system.
Executed on CPU with Python 3.12.14 and NumPy 2.3.5 · 2026-10-22
import numpy as np
base = np.arange(12)
reshaped = base.reshape(3, 4)
selected = base[[0, 2, 4, 6]].reshape(2, 2)
print('reshape shares data:', np.shares_memory(base, reshaped))
print('advanced selection shares data:', np.shares_memory(base, selected))
reshaped[0, 0] = 99
print('base after view edit:', int(base[0]))
selected[0, 0] = 77
print('base after copy edit:', int(base[0]))
assert np.shares_memory(base, reshaped)
assert not np.shares_memory(base, selected)
assert base[0] == 99
assert selected[0, 0] == 77
Recorded output
reshape shares data: True advanced selection shares data: False base after view edit: 99 base after copy edit: 99
Read the mutation test carefully
Changing the top-left element of the reshaped array writes 99 into the first element of the base array, because those two arrays share that element. Changing the top-left element of the selected array to 77 affects only the independently selected result. The original still begins with 99. Both arrays contain plausible numerical values and both have valid shapes; the difference is storage aliasing. The assertions in the example make that contract explicit.
NumPy documentation distinguishes basic slicing, which returns views, from advanced integer or Boolean indexing, which returns copies. That distinction matters in feature processing because two superficially similar transformations can have different mutation and memory-allocation behavior. It does not mean that every reshape must share storage or that every change to an intermediate will be visible in the source array. [1, 2]
Check actual sharing without making the check itself expensive
For small arrays such as this example, numpy.shares_memory gives an exact answer about whether two arrays overlap in their data storage. It is more relevant to this question than comparing shapes, Python object identities or the existence of a base attribute. The simple True and False results here come from directly checking the two array pairs. [3]
There is a useful limitation: for specially constructed high-dimensional strides, the exact overlap problem can be computationally expensive. The NumPy API permits a bounded max_work argument, and numpy.may_share_memory provides a faster conservative alternative based on memory bounds. Use those options when inspecting unusual array layouts rather than assuming an exact overlap check is always constant time. [3]
References: [3]
Decide whether your pipeline needs shared storage
When the next operation mutates data, document whether it is allowed to modify the original. If sharing is intentional, state that contract and test it with a tiny known example. If independence is required, make a deliberate copy, and account for its allocation rather than relying on a reshape or selection to happen to copy. [1]
This guide demonstrates one NumPy 2.3.5 example with a contiguous input and integer-array selection. It does not benchmark runtime or memory peaks, nor does it establish aliasing behavior for a particular tensor framework, device backend, noncontiguous layout or custom array subclass. Those cases require checking the library's own API and testing the actual inputs.
References: [1]