*`depth(IntTuple)`: The number of hierarchical `IntTuple`s. A single integer has depth 0, a tuple of integers has depth 1, a tuple that contains a tuple of integers has depth 2, etc.
A `Layout` is then a pair of `IntTuple`s. The first element defines the abstract *shape* of the `Layout`, and the second element defines the *strides*, which map from coordinates within the shape to the index space.
*`depth(Layout)`: The number of hierarchical `Layout`s. A single integer has depth 0, a tuple of integers has depth 1, a tuple that contains a tuple of integers has depth 2, etc.
as a vector, since its shape is rank 1. The inner shape describes a 4x2 layout of data in column-major order, but the extra pair of parenthesis suggest we can interpret those two modes as a single 1-D 8-element vector instead. Due to the strides, the elements are also contiguous.
### Matrix examples
Generalizing, we define a matrix as any `Shape` and `Stride` pair with rank 2. For example,
```
Shape: (4,2)
Stride: (1,4)
0 4
1 5
2 6
3 7
```
is a 4x2 column-major matrix, and
```
Shape: (4,2)
Stride: (2,1)
0 1
2 3
4 5
6 7
```
is a 4x2 row-major matrix.
Each of the modes of the matrix can also be split into *multi-indices* like the vector example.
This lets us express more layouts beyond just row major and column major. For example,
```
Shape: ((2,2),2)
Stride: ((4,1),2)
0 2
4 6
1 3
5 7
```
is also logically 4x2, with a stride of 2 across the rows but a multi-stride down the columns.
Since this layout is logically 4x2,
like the column-major and row-major examples above,
we can _still_ use 2-D coordinates to index into it.
## Constructing a `Layout`
A `Layout` can be constructed in many different ways.
It can include any combination of compile-time (static) integers
or run-time (dynamic) integers.
```c++
auto layout_8s = make_layout(Int<8>{});
auto layout_8d = make_layout(8);
auto layout_2sx4s = make_layout(make_shape(Int<2>{},Int<4>{}));
auto layout_2sx4d = make_layout(make_shape(Int<2>{},4));
auto layout_2x4 = make_layout(make_shape (2, make_shape (2,2)),
The fundamental use of a `Layout` is to map between logical coordinate space(s) and an index space. For example, to print an arbitrary rank-2 layout, we can write the function
Note that for `layout_2x4`, we're using a 1-D coordinate for a 2-D multi-index in the second mode. In fact, we can generalize this and treat all of the above layouts as 1-D layouts. For instance, the following `print1D` function
produces the following output for the above examples.
```
> print1D(layout_8s)
0 1 2 3 4 5 6 7
> print1D(layout_8d)
0 1 2 3 4 5 6 7
> print1D(layout_2sx4s)
0 1 2 3 4 5 6 7
> print1D(layout_2sx4d)
0 1 2 3 4 5 6 7
> print1D(layout_2x4)
0 4 2 6 1 5 3 7
```
This shows explicitly that all of the layouts are simply folded views of an 8-element array.
## Summary
* The `Shape` of a `Layout` defines its coordinate space(s).
* Every `Layout` has a 1-D coordinate space.
This can be used to iterate in a "generalized-column-major" order.
* Every `Layout` has a R-D coordinate space,
where R is the rank of the layout.
These spaces are ordered _colexicographically_
(reading right to left, instead of "lexicographically,"
which reads left to right).
The enumeration of that order
corresponds to the 1-D coordinates above.
* Every `Layout` has an h-D coordinate space where h is "hierarchical." These are ordered colexicographically and the enumeration of that order corresponds to the 1-D coordinates above. An h-D coordinate is congruent to the `Shape` so that each element of the coordinate has a corresponding element of the `Shape`.
* The `Stride` of a `Layout` maps coordinates to indices.
* In general, this could be any function from 1-D coordinates (integers) to indices (integers).
* In `CuTe` we use an inner product of the h-D coordinates with the `Stride` elements.