# coding: utf-8
# # How are numpy arrays stored?
# In[1]:
import numpy as np
# Numpy presents an n-dimensional abstraction that has to be fit into 1-dimensional computer memory.
#
# Even for 2 dimensions (matrices), this leads to confusion: row-major, column-major.
# In[4]:
A = np.arange(9).reshape(3, 3)
print(A)
# ## Strides and in-memory representation
# How is this represented in memory?
# In[6]:
A.strides
# * `strides` stores for each axis by how many bytes one needs to jump to get from one entry to the next (in that axis)
# * So how is the array above stored?
# * This captures row-major ("C" order) and column-major ("Fortran" order), but is actually much more general.
# We can also ask for Fortran order:
# In[10]:
A2 = np.arange(9).reshape(3, 3, order="F")
A2
# `numpy` defaults to row-major order.
# In[11]:
A2.strides
# ## Strides and Contiguity
# How is the stride model more general than just saying "row major" or "column major"?
# In[15]:
A = np.arange(16).reshape(4, 4)
A
# In[18]:
A.strides
# In[14]:
Asub = A[:3, :3]
Asub
# Recall that `Asub` constitutes a *view* of the original data in `A`.
# In[19]:
Asub.strides
# Now `Asub` is no longer a *contiguous* array!
#
# From the linear-memory representation (as show by the increasing numbers in `A`) 3, 7, 11 are missing.
#
# This is easy to check by a flag:
# In[20]:
Asub.flags