# Tensors and Views

> NumKong for C++

The native containers are where most integration mistakes happen.
They need to be documented explicitly.

- `vector<T, A>` owns storage and defaults to `aligned_allocator<T, 64>`.
- `vector_view<T>` is a const strided non-owning view.
- `vector_span<T>` is a mutable strided non-owning view.
- `tensor<T, A, R>` owns rank-`R` storage and also defaults to aligned allocation.
- `tensor_view<T>` and `tensor_span<T>` are the view forms.
- `matrix`, `matrix_view`, and `matrix_span` are rank-2 aliases.

The important layout rules are:

- Signed strides are supported by the view types.
- Reversed and sliced views are valid for many elementwise and reduction kernels.
- `reshape` and `flatten` require contiguous layout.
- Matrix-style kernels care about _row contiguity_, not just total tensor contiguity.
- Negative strides are conceptually valid views, but matrix packing and packed matmul workflows are not written around them.

Memory ownership is explicit.
`vector` and `tensor` deallocate through their allocator.
`vector_view`, `tensor_view`, `matrix_view`, and spans never own memory.
And heterogenous index types for `operator[]` enable more interesting access patterns:

```cpp
#include <numkong/numkong.hpp>

namespace nk = ashvardanian::numkong;
using nk::slice, nk::all, nk::f32_t, nk::tensor, nk::tensor_view;

auto [t, status] = tensor<f32_t>::from({
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
});
assert(nk::succeeded(status) && "allocated");

f32_t scalar_at_2d_coordinate = t[1, -1];
f32_t scalar_at_global_offset = t[5];
assert(scalar_at_2d_coordinate == scalar_at_global_offset && "same value");

tensor_view<f32_t> scalar_as_tensor = t[1, 1, slice]; 
tensor_view<f32_t> second_row = t[1, slice];
tensor_view<f32_t> second_column = t[all, 1, slice];
assert(second_row[1] == second_column[1] && "same value");
```

You can also use a more traditional syntax with member functions, also leveraging built-in functionality for hardware-accelerated strided reductions and elementwise operations along any axis combination.
Similar to NumPy, but statically typed:

```cpp
tensor_view<f32_t> second_column = t[all, 1, slice]; // strided column view → {2, 5, 8}
auto minimum_index = nk::argmin(second_column);   // index of the minimum in the second column
```

The view types are conceptually close to `std::mdspan` from C++23.
The main differences are sub-byte element support, signed strides, and the kernel dispatch integration that `std::mdspan` does not provide.
If your codebase already uses `std::mdspan`, converting at the NumKong call boundary is straightforward:

```cpp
#include <numkong/numkong.hpp>
#include <mdspan>

namespace nk = ashvardanian::numkong;

// Existing std::mdspan from your codebase
float data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
auto md = std::mdspan<float, std::extents<std::size_t, 3, 3>>(data);

// Wrap into a NumKong matrix_view — data pointer, extents, and strides map directly
auto view = nk::matrix_view<nk::f32_t>(
    reinterpret_cast<nk::f32_t const *>(md.data_handle()),
    md.extent(0), md.extent(1));

// Now use any NumKong kernel on it
auto [dot, status] = nk::dot<nk::f32_t>(view.row(0).as_vector(), view.row(1).as_vector());
```

### Iterators and Enumeration

NumKong containers expose random-access iterators for element and row traversal.

- __`dim_iterator`__ — random-access iterator over element values, used by `vector`, `vector_view`, and `vector_span`.
  Supports all standard iterator operations plus `index()` to retrieve the current position.
- __`axis_iterator`__ — random-access iterator over sub-views (rows), used by `tensor_view` and `tensor_span`.
  Also exposes `index()`.
- __`enumerate()`__ — free function returning a lightweight view that yields `{index, value}` pairs from any container with `begin()`/`end()`/`size()`.

```cpp
#include <numkong/numkong.hpp>

namespace nk = ashvardanian::numkong;

auto [v, v_status] = nk::vector<nk::f16_t>::zeros(128);
if (nk::failed(v_status)) return v_status;
for (auto [i, val] : nk::enumerate(v))
    std::printf("[%zu] = %f\n", i, val.to_f32());

// index() on raw iterators
for (auto it = v.begin(); it != v.end(); ++it)
    std::printf("[%zu] = %f\n", it.index(), (*it).to_f32());
```

Since `tensor.hpp` includes `vector.hpp`, `enumerate()` works on tensor row views too.

Tensors also support range-for over all logical scalar elements, yielding `(position, value)` pairs.
For sub-byte types each dimension is a logical scalar.
Use `.dims()` to iterate values without positions.

```cpp
for (auto [pos, val] : matrix)          { /* pos is std::array<size_t, R> */ }
for (auto [pos, ref] : matrix.span())   { ref = nk::f32_t{1}; }
for (auto val : matrix.dims())          { /* scalar only, no position */ }
```

`#include <numkong/tensor.hpp>`

`#include <numkong/vector.hpp>`

`#include <numkong/random.hpp>`

## axis_iterator

Random-access iterator over slices along the leading dimension.

```cpp
template <typename view_type_>
class axis_iterator
```

For a rank-2 matrix, iterating yields rank-1 row views/spans. Dereference calls `parent_.slice_leading(index_)` to produce each sub-view.

## keep_dims_t

Controls whether reduction collapses or preserves the reduced axis.

```cpp
enum keep_dims_t
```

- `collapse_dims_k` = `false`
- `keep_dims_k` = `true`

## all_t

Tag type for selecting all elements along a dimension.

```cpp
struct all_t
```

## range_t

Slicing descriptor: [start, stop) with optional step.

```cpp
struct range_t
```

`step` must be non-zero. Negative start/stop indices wrap from the end.

- `start` `std::ptrdiff_t`
- `stop` `std::ptrdiff_t`
- `step` `std::ptrdiff_t`

## dim_iterator

Random-access iterator over logical dimensions.

```cpp
template <typename container_type_>
class dim_iterator
```

For sub-byte types ([i4x2_t](https://www.unum.cloud/docs/numkong/cpp/scalar-types.md#i4x2_t), [u1x8_t](https://www.unum.cloud/docs/numkong/cpp/scalar-types.md#u1x8_t)), dereference returns a proxy reference. For normal types, dereference returns a direct reference.

## scaled_tensor

Owning, allocating block-scaled tensor.

```cpp
template <typename format_,
          typename element_allocator_ = aligned_allocator<typename format_::element_t>,
          typename scale_allocator_ = aligned_allocator<typename format_::scale_t>,
          std::size_t max_rank_ = 8>
struct scaled_tensor
```

## scaled_tensor

```cpp
scaled_tensor() noexcept=default;
```

```cpp
scaled_tensor(scaled_tensor &&) noexcept=default;
```

```cpp
scaled_tensor(scaled_tensor const &)=delete;
```

## operator=

```cpp
scaled_tensor & operator=(scaled_tensor &&) noexcept=default;
```

```cpp
scaled_tensor & operator=(scaled_tensor const &)=delete;
```

## *

Contextual-bool: truthy when the tensor owns storage.

```cpp
constexpr operator bool() const noexcept;
```

Enables the `if(!t)` empty-check idiom.

## capacity

Allocated logical-element capacity — the ceiling coordinated `resize()` honors.

```cpp
size_type capacity() const noexcept;
```

## resize

Reshape in place to `extents` whose last dimension is a multiple of `block_size`, resizing both tensors without reallocating.

```cpp
status_t resize(size_type const *extents, size_type rank) noexcept;
```

```cpp
status_t resize(std::initializer_list<size_type> extents) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) Leaving both untouched, if the rank is bad, the last extent is not block-aligned, or either component's capacity is exceeded.

## reserve

Grow capacity to at least [`values`](#values) logical elements, plus the matching per-block scales; may reallocate/move the component buffers.

```cpp
status_t reserve(size_type values) noexcept;
```

No-op when already large enough.

## clear

Drop to an empty shape while keeping both component capacities.

```cpp
void clear() noexcept;
```

## swap

Swap contents: both component tensors and the per-tensor scale.

```cpp
void swap(scaled_tensor & other) noexcept;
```

## elements

Immutable component accessors.

```cpp
element_tensor_type::view_type elements() const noexcept;
```

## tensor_scale

Per-tensor multiplier, NVFP4 only, absent for the MX family.

```cpp
requires (format_::has_tensor_scale())
f32_t tensor_scale() const noexcept;
```

`cast()` derives and writes it on encode through `span().tensor_scale_slot()`.

## view

Immutable whole-tensor view.

```cpp
view_type view() const noexcept;
```

## span

Mutable whole-tensor span, writes through to the per-tensor scale.

```cpp
span_type span() noexcept;
```

## row

Leading-axis row view.

```cpp
template <std::integral index_type_>
view_type row(index_type_ i) const noexcept;
```

## columns

Block-aligned last-axis, column, range view.

```cpp
view_type columns(size_type start, size_type stop) const noexcept;
```

## rows_views

Iterate leading-axis rows as immutable views.

```cpp
view_type::rows_views_t rows_views() const noexcept;
```

## uninitialized

Factory: allocate an uninitialized block-scaled tensor with the given extents.

```cpp
expected<scaled_tensor> uninitialized(
    size_type const *extents,
    size_type rank,
    element_allocator_ element_alloc = {},
    scale_allocator_ scale_alloc = {}) noexcept;
```

```cpp
expected<scaled_tensor> uninitialized(
    std::initializer_list<size_type> extents,
    element_allocator_ element_alloc = {},
    scale_allocator_ scale_alloc = {}) noexcept;
```

Allocate from an `extents` list; see the pointer overload for the failure statuses.

- `extents` (in): Logical extents; the last one must be a multiple of `block_size`.
- `rank` (in): Number of extents.
- `element_alloc` (in): Allocator of the element tensor.
- `scale_alloc` (in): Allocator of the block-scale tensor.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) A bad rank or an unaligned last extent.

## from_components

Adopt already-built component tensors and a per-tensor scale.

```cpp
expected<scaled_tensor> from_components(
    element_tensor_type elements,
    scale_tensor_type block_scales,
    f32_t tensor_scale = 1.0f) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) [`block_scales`](#block_scales) isn't shaped like [`elements`](#elements) with the last extent divided by `block_size`.

## scaled_tensor_span

Non-owning, mutable span of a block-scaled tensor, a write target for `cast()`.

```cpp
template <typename format_,
          std::size_t max_rank_>
struct scaled_tensor_span
```

## scaled_tensor_span

```cpp
constexpr scaled_tensor_span() noexcept=default;
```

```cpp
constexpr scaled_tensor_span(
    element_span_type elements,
    scale_span_type block_scales,
    f32_t *tensor_scale = nullptr) noexcept;
```

## *

Contextual-bool: truthy when the handle is non-empty.

```cpp
constexpr operator bool() const noexcept;
```

Enables the `if(!span)` empty-check idiom.

Enables the `if(!view)` empty-check idiom.

Enables the `if`(!view) empty-check idiom.

Enables the `if(!v)` empty-check idiom.

## elements

Mutable span of the packed micro-float elements.

```cpp
element_span_type elements() const noexcept;
```

## block_scales

Mutable span of the per-block scales.

```cpp
scale_span_type block_scales() const noexcept;
```

## tensor_scale_slot

Pointer to the per-tensor multiplier slot, NVFP4 only; kernels write it here.

```cpp
requires (format_::has_tensor_scale())
f32_t * tensor_scale_slot() const noexcept;
```

## view

Decay to an immutable view.

```cpp
view_type view() const noexcept;
```

## scaled_tensor_view

A block-scaled tensor = packed micro-float __elements__ + per-block __scales__ + an optional per-tensor __scale__, all on the last, quantized, axis.

```cpp
template <typename format_,
          std::size_t max_rank_>
struct scaled_tensor_view
```

Non-owning, immutable view of a block-scaled tensor.

Composes two ordinary tensors rather than inventing a parallel container family:

```
*  - elements()   — tensor   of the logical shape, packed sub-byte.
*  - block_scales()   — tensor   of the same shape with the last extent
*    divided by block_size  ; one scale per block.
*  - tensor_scale()   — a scalar f32_t   multiplier, NVFP4 only; the call is removed by a
*    requires   clause for the MX family, which has no per-tensor scale.
*
```

Because the scales are a real reduced-shape tensor, slicing reuses the tensor machinery and slices both components in lockstep; a last-axis, column, range is divided by `block_size`. Encode / decode / transcode all go through `cast()` in `[cast.hpp](https://www.unum.cloud/docs/numkong/cpp/scalar-types.md#cast)`; `[scaled_tensor](#scaled_tensor)` itself is pure storage and never calls a kernel. The struct-of-arrays layout is exactly the NVFP4/MXFP8 GPU representation — `elements()` and `block_scales()` each export a DLPack / CUDA-array interface for zero-copy access.

Shape convention: `elements()` reports the __logical__ shape ____[rows,columns] because its value type is the sub-byte-aware packed scalar, e.g. `[e2m1x2_t](https://www.unum.cloud/docs/numkong/cpp/scalar-types.md#e2m1x2_t)`, so `extent(last)` is the element count even though storage is packed. Array-protocol bindings without a sub-byte scalar — the Python [`ScaledTensor.elements`](#elements) ndarray, Rust's packed slice — instead expose the __packed__ byte shape ____[rows,columns] with the column extent scaled by element_bits/8, same bytes, reported per their type system.

## scaled_tensor_view

```cpp
constexpr scaled_tensor_view() noexcept=default;
```

```cpp
constexpr scaled_tensor_view(
    element_view_type elements,
    scale_view_type block_scales,
    f32_t tensor_scale = 1.0f) noexcept;
```

## *

Number of dimensions.

```cpp
size_type rank() const noexcept;
```

## extent

Logical extent along dimension i.

```cpp
size_type extent(size_type i) const noexcept;
```

## numel

Total number of logical elements.

```cpp
size_type numel() const noexcept;
```

## *

True if empty.

```cpp
bool empty() const noexcept;
```

## elements

Immutable view of the packed micro-float elements, DLPack/CAI-exportable.

```cpp
element_view_type elements() const noexcept;
```

## block_scales

Immutable view of the per-block scales, one per `block_size` on the last axis.

```cpp
scale_view_type block_scales() const noexcept;
```

## tensor_scale

Per-tensor multiplier, NVFP4 only; the call is absent for the MX family.

```cpp
requires (format_::has_tensor_scale())
f32_t tensor_scale() const noexcept;
```

## slice_leading

Slice along the leading axis, rank-reducing; shares the per-tensor scale.

```cpp
template <std::integral index_type_>
scaled_tensor_view slice_leading(index_type_ i) const noexcept;
```

## *

Row access, an alias for [`slice_leading`](#slice_leading).

```cpp
template <std::integral index_type_>
scaled_tensor_view row(index_type_ i) const noexcept;
```

## columns

Block-aligned last-axis (column) range; preserves every leading axis.

```cpp
scaled_tensor_view columns(
    size_type start,
    size_type stop) const noexcept;
```

Zero-copy.

`start` and `stop` must be multiples of `block_size` so both the element and the scale offsets stay integral and land on container boundaries, essential for packed sub-byte elements. Returns an empty view otherwise; materialize sub-block ranges with `cast()` first.

## row_iterator_t

Forward iterator over leading-axis row views.

```cpp
struct row_iterator_t
```

- `parent` `scaled_tensor_view`
- `index` `size_type`

## rows_views_t

Range of leading-axis row views, each carries the per-tensor scale.

```cpp
struct rows_views_t
```

- `parent` `scaled_tensor_view`

## tensor

Owning, N-dimensional tensor: allocated once, reshaped freely within its capacity.

```cpp
template <typename value_type_,
          typename allocator_type_ = aligned_allocator<value_type_>,
          std::size_t max_rank_ = 8>
struct tensor
```

`resize()` adjusts the _shape_ within the allocated `capacity()` and fails beyond it, so `data()` is stable across resizes — the contract capture-replaying GPU code depends on. `reserve()` is the explicit opt-in that may reallocate to grow `capacity()`, and thus move `data()`. Allocate at the worst-case extents, or `reserve()` up front, then `resize()` to each step's live extents; `clear()` drops back to an empty shape while keeping the buffer.

## tensor

```cpp
tensor() noexcept=default;
```

```cpp
constexpr tensor(allocator_type_ const & alloc) noexcept;
```

```cpp
constexpr tensor(tensor && other) noexcept;
```

```cpp
tensor(tensor const &)=delete;
```

## ~tensor

```cpp
~tensor() noexcept;
```

## operator=

```cpp
tensor & operator=(tensor && other) noexcept;
```

```cpp
tensor & operator=(tensor const &)=delete;
```

## capacity

Allocated values — the ceiling `resize()` honors; at least `numel()`.

```cpp
size_type capacity() const noexcept;
```

## resize

Reshape in place to contiguous `extents`, without reallocating: succeeds iff the new volume fits `capacity()`, the rank fits `max_rank_` and the last extent is a whole number of storage values, so `data()` never moves — resizing to a step's live extents is safe under captured GPU graphs.

```cpp
status_t resize(std::initializer_list<size_type> extents) noexcept;
```

```cpp
status_t resize(size_type const *extents, size_type rank) noexcept;
```

Reshape in place from an `extents` array of [`rank`](#rank) dims, mirroring the list overload.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) Leaving the shape untouched.

## reserve

Grow the allocated `capacity()` to at least [`values`](#values) elements.

```cpp
status_t reserve(size_type values) noexcept;
```

Unlike `resize()`, this may reallocate and move `data()`; the live `numel()`-storage elements are preserved. No-op when `capacity() >= [values](#values)`.

A failed growth leaves the state unchanged.

## clear

Reset to a logically empty shape, `empty()` becomes true, while keeping `capacity()`, so the buffer can be refilled via `resize()` without reallocating.

```cpp
void clear() noexcept;
```

Storage only frees when the tensor is destroyed.

## swap

Swap contents: data, shape, capacity, and allocator if it propagates on swap.

```cpp
void swap(tensor & other) noexcept;
```

## extent

Extent along dimension i.

```cpp
size_type extent(size_type i) const noexcept;
```

## stride_bytes

Stride in bytes along dimension i, signed.

```cpp
difference_type stride_bytes(size_type i) const noexcept;
```

## *

Total number of elements.

```cpp
size_type numel() const noexcept;
```

## data

Typed pointer to data.

```cpp
pointer data() noexcept;
```

```cpp
value_type const * data() const noexcept;
```

## raw_values_data

The storage as C kernels take it: `raw_t` for NumKong's types, else the type itself.

```cpp
raw_value_type * raw_values_data() noexcept;
```

```cpp
raw_value_type const * raw_values_data() const noexcept;
```

## shape

Shape storage.

```cpp
shape_storage_<max_rank_> const & shape() const noexcept;
```

## get_allocator

Allocator.

```cpp
allocator_type get_allocator() const noexcept;
```

## *

Create an immutable view.

```cpp
view_type view() const noexcept;
```

## *

Create a mutable span.

```cpp
span_type span() noexcept;
```

## rows_views

Iterate rows as immutable views.

```cpp
rows_views_t rows_views() const noexcept;
```

## rows_spans

Iterate rows as mutable spans.

```cpp
rows_spans_t rows_spans() noexcept;
```

## rows

Iterate rows as immutable views, a convenience alias for rows_views.

```cpp
view_type::rows_views_t rows() const noexcept;
```

```cpp
span_type::rows_spans_t rows() noexcept;
```

Iterate rows as mutable spans, a convenience alias for rows_spans.

## begin

Const element iterator, begin.

```cpp
tensor_view_iterator_<view_type> begin() const noexcept;
```

```cpp
tensor_span_iterator_<span_type> begin() noexcept;
```

Mutable element iterator, begin.

## end

Const element iterator, end.

```cpp
tensor_view_iterator_<view_type> end() const noexcept;
```

```cpp
tensor_span_iterator_<span_type> end() noexcept;
```

Mutable element iterator, end.

## *

Number of logical scalar elements.

```cpp
size_type size() const noexcept;
```

## dims

Const dimension-only view.

```cpp
tensor_dims_view_<tensor_view_iterator_<view_type>> dims() const noexcept;
```

```cpp
tensor_dims_view_<tensor_span_iterator_<span_type>> dims() noexcept;
```

Mutable dimension-only view.

## as_matrix_view

Reinterpret as a 2D immutable matrix view.

```cpp
tensor_view<value_type_, 2> as_matrix_view() const noexcept;
```

Requires rank >= 2.

## as_matrix_span

Reinterpret as a 2D mutable matrix span.

```cpp
tensor_span<value_type_, 2> as_matrix_span() noexcept;
```

Requires rank >= 2.

## transpose

Transpose: reverse dimension order, immutable view.

```cpp
view_type transpose() const noexcept;
```

```cpp
span_type transpose() noexcept;
```

Transpose: reverse dimension order, mutable span.

## reshape

Reshape, immutable view.

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_view<value_type_, out_rank_> reshape(
    std::initializer_list<size_type> new_extents) const noexcept;
```

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_span<value_type_, out_rank_> reshape(
    std::initializer_list<size_type> new_extents) noexcept;
```

Reshape, mutable span.

The output rank may differ from the source; pass it as the template argument when narrowing or widening, given contiguous layout and matching element counts.

## is_*_contiguous

Check if contiguous in memory.

```cpp
bool is__contiguous() const noexcept;
```

Always true for freshly-constructed tensors.

## values

Storage values as a contiguous span, refused like `[tensor_view::values](#values)`.

```cpp
expected<std::span<value_type const>> values() const noexcept;
```

```cpp
expected<std::span<value_type>> values() noexcept;
```

Mutable storage values as a contiguous span, refused like `[tensor_span::values](#values)`.

## slice_leading

Slice along leading dimension, immutable view.

```cpp
template <std::integral index_type_>
view_type slice_leading(index_type_ idx) const noexcept;
```

```cpp
template <std::integral index_type_>
span_type slice_leading(index_type_ idx) noexcept;
```

Slice along leading dimension, mutable span.

## row

Row access, immutable view, an alias for slice_leading.

```cpp
template <std::integral index_type_>
view_type row(index_type_ i) const noexcept;
```

```cpp
template <std::integral index_type_>
span_type row(index_type_ i) noexcept;
```

Row access, mutable span, an alias for slice_leading.

## operator[]

Flat logical scalar access.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) noexcept;
```

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

Const flat logical scalar access.

```cpp
span_type operator[](tensor_slice_t) noexcept;
```

Trailing `slice` returns the same tensor view/span category.

```cpp
view_type operator[](tensor_slice_t) const noexcept;
```

## operator()

Exact multi-dimensional scalar lookup via call syntax, C++20-portable.

```cpp
template <std::integral... index_types_>
requires (sizeof...(index_types_) >= 2)
decltype(auto) operator()(index_types_... idxs) noexcept;
```

```cpp
template <std::integral... index_types_>
requires (sizeof...(index_types_) >= 2)
decltype(auto) operator()(index_types_... idxs) const noexcept;
```

Const multidimensional lookup via call syntax.

```cpp
template <typename first_type_, typename second_type_, typename... rest_types_>
requires (trailing_tensor_slice_args_v<first_type_, second_type_, rest_types_...>)
auto operator()(
    first_type_ first,
    second_type_ second,
    rest_types_... rest) noexcept;
```

Prefix leading-axis slicing via call syntax, C++20-portable, narrowed like the span's.

```cpp
template <typename first_type_, typename second_type_, typename... rest_types_>
requires (trailing_tensor_slice_args_v<first_type_, second_type_, rest_types_...>)
auto operator()(
    first_type_ first,
    second_type_ second,
    rest_types_... rest) const noexcept;
```

Const prefix leading-axis slicing via call syntax.

## scalar_*_ref

Rank-0 mutable scalar access.

```cpp
decltype(auto) scalar__ref() noexcept;
```

## *

Rank-0 const scalar access.

```cpp
decltype(auto) scalar() const noexcept;
```

## as_vector_view

Convert to [vector_view](#vector_view); requires rank == 1.

```cpp
vector_view<value_type> as_vector_view() const noexcept;
```

## as_vector_span

Convert to [vector_span](#vector_span); requires rank == 1.

```cpp
vector_span<value_type> as_vector_span() noexcept;
```

## flatten

Flatten, immutable view.

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_view<value_type_, out_rank_> flatten() const noexcept;
```

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_span<value_type_, out_rank_> flatten() noexcept;
```

Flatten, mutable span.

Requires contiguous layout.

## squeeze

Squeeze, immutable view.

```cpp
view_type squeeze() const noexcept;
```

```cpp
span_type squeeze() noexcept;
```

Squeeze, mutable span.

Removes size-1 dimensions.

## fill_*_zeros

Zero-fill every element.

```cpp
status_t fill__zeros() noexcept;
```

memset on the contiguous fast path, one memset per element on the strided slow path.

Statuses: - [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) A strided sub-byte span.

## *

Fill every element with `value`.

```cpp
status_t fill(value_type value) noexcept;
```

## copy_from

Copy from a same-shape view.

```cpp
status_t copy_from(view_type input) noexcept;
```

## uninitialized

Factory: allocate an uninitialized tensor from an `extents` array of [`rank`](#rank) dims.

```cpp
expected<tensor> uninitialized(
    size_type const *extents,
    size_type rank,
    allocator_type_ alloc = {}) noexcept;
```

```cpp
expected<tensor> uninitialized(
    std::initializer_list<size_type> extents,
    allocator_type_ alloc = {}) noexcept;
```

Factory: allocate an uninitialized tensor.

Warnings: Contents are uninitialized. Caller must fill before reading.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) [`rank`](#rank) exceeds `max_rank_` or the last extent is not a whole number of storage values.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As the pointer overload reports.

## zeros

Factory: zero-initialized tensor from an `extents` array; fails like [`uninitialized`](#uninitialized).

```cpp
expected<tensor> zeros(
    size_type const *extents,
    size_type rank,
    allocator_type_ alloc = {}) noexcept;
```

```cpp
expected<tensor> zeros(
    std::initializer_list<size_type> extents,
    allocator_type_ alloc = {}) noexcept;
```

Factory: allocate a zero-initialized tensor with the given extents.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As [`uninitialized`](#uninitialized) reports.

## full

Factory: tensor filled with `val` from an `extents` array; fails like [`uninitialized`](#uninitialized).

```cpp
expected<tensor> full(
    size_type const *extents,
    size_type rank,
    value_type_ val,
    allocator_type_ alloc = {}) noexcept;
```

```cpp
expected<tensor> full(
    std::initializer_list<size_type> extents,
    value_type_ val,
    allocator_type_ alloc = {}) noexcept;
```

Factory: allocate a tensor filled with a given value.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As [`uninitialized`](#uninitialized) reports.

## ones

Factory: allocate a tensor filled with ones.

```cpp
expected<tensor> ones(
    std::initializer_list<size_type> extents,
    allocator_type_ alloc = {}) noexcept;
```

- `extents` (in): Extents, one per dimension, e.g. `{3, 4}`.
- `alloc` (in): Allocator instance.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As [`uninitialized`](#uninitialized) reports.

## from

Factory: create a rank-1 tensor from an initializer list of values.

```cpp
expected<tensor> from(
    std::initializer_list<value_type_> values,
    allocator_type_ alloc = {}) noexcept;
```

```cpp
requires (max_rank_ >= 2)
expected<tensor> from(
    std::initializer_list<std::initializer_list<value_type_>> rows,
    allocator_type_ alloc = {}) noexcept;
```

Factory: create a rank-2 tensor from a nested initializer list.

- `values` (in): Values to fill the tensor with.
- `alloc` (in): Allocator instance.
- `rows` (in): Each inner list is a row. All rows must have the same length.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As [`uninitialized`](#uninitialized) reports.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) Ragged rows, or as [`uninitialized`](#uninitialized) reports.

## from_raw

Factory: adopt raw memory, whose [`shape`](#shape) must end in a whole number of storage values.

```cpp
tensor from_raw(
    pointer ptr,
    shape_storage_<max_rank_> const & shape,
    allocator_type_ alloc = {}) noexcept;
```

## rows_views_t

Range of immutable row views, slicing along the leading dimension.

```cpp
struct rows_views_t
```

- `parent` `view_type`

## rows_spans_t

Range of mutable row spans, slicing along the leading dimension.

```cpp
struct rows_spans_t
```

- `parent` `span_type`

## tensor_span

Non-owning, mutable, N-dimensional view.

```cpp
template <typename value_type_,
          std::size_t max_rank_ = 8>
struct tensor_span
```

## tensor_span

Convenience constructor for rank-2 spans from typed pointer, rows, and columns.

```cpp
constexpr tensor_span() noexcept=default;
```

```cpp
constexpr tensor_span(
    char *data,
    shape_storage_<max_rank_> const & shape) noexcept;
```

```cpp
requires (max_rank_ >= 2)
constexpr tensor_span(
    value_type *data,
    size_type rows,
    size_type columns) noexcept;
```

Convenience constructor for rank-2 spans from typed pointer, rows, and columns.

```cpp
requires (max_rank_ >= 1)
constexpr tensor_span(value_type *data, size_type count) noexcept;
```

Convenience constructor for a rank-1 span from a typed pointer and element [`count`](https://www.unum.cloud/docs/numkong/cpp/runtime-dispatch.md#count).

```cpp
template <std::size_t span_extent_>
requires (max_rank_ >= 1)
constexpr tensor_span(
    std::span<value_type, span_extent_> values) noexcept;
```

Spans contiguous storage values as a rank-1 tensor of every logical dimension they hold, the inverse of [values](#values).

```cpp
constexpr tensor_span(
    value_type *data,
    std::initializer_list<size_type> extents) noexcept;
```

Convenience constructor from a typed pointer and an explicit `extents` list, where rank equals the list size.

```cpp
template <std::size_t array_rank_>
requires (array_rank_ <= max_rank_)
constexpr tensor_span(
    value_type *data,
    std::array<size_type, array_rank_> const & extents) noexcept;
```

Convenience constructor from a typed pointer and a fixed-size `extents` array, where rank equals `array_rank_`.

An out-of-range rank, empty or greater than `max_rank_`, yields an empty handle rather than overflowing the fixed-capacity shape storage.

## *

Extent along the i-th dimension.

```cpp
size_type extent(size_type i) const noexcept;
```

## stride_*_bytes

Stride in bytes along the i-th dimension, signed.

```cpp
difference_type stride__bytes(size_type i) const noexcept;
```

## byte_*_data

Raw byte pointer.

```cpp
char * byte__data() const noexcept;
```

## *

Typed pointer, assumes data is contiguous from this pointer.

```cpp
value_type * data() const noexcept;
```

## raw_values_*_values_data

The storage as C kernels take it: `raw_t` for NumKong's types, else the type itself.

```cpp
raw_value_type * raw_values__values_data() const noexcept;
```

## *

Access the shape storage.

```cpp
shape_storage_<max_rank_> const & shape() const noexcept;
```

## slice_leading

Slice along leading dimension.

```cpp
template <std::integral index_type_>
tensor_span slice_leading(index_type_ idx) const noexcept;
```

## row

Mutable row access, an alias for slice_leading.

```cpp
template <std::integral index_type_>
tensor_span row(index_type_ i) const noexcept;
```

## operator[]

Flat logical scalar access — `constexpr` like the other accessors, so it stays device-callable.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

```cpp
tensor_span operator[](tensor_slice_t) const noexcept;
```

Trailing `slice` returns the same span.

## operator()

Exact multi-dimensional scalar lookup via call syntax, C++20-portable.

```cpp
template <std::integral... index_types_>
requires (sizeof...(index_types_) >= 2)
decltype(auto) operator()(index_types_... idxs) const noexcept;
```

```cpp
template <typename first_type_, typename second_type_, typename... rest_types_>
requires (trailing_tensor_slice_args_v<first_type_, second_type_, rest_types_...>)
auto operator()(
    first_type_ first,
    second_type_ second,
    rest_types_... rest) const noexcept;
```

Prefix leading-axis slicing via call syntax, C++20-portable.

Every integral index drops one static rank.

## with_max_rank

The same span under the static rank `out_rank_`, which must hold its runtime rank; an empty span otherwise.

```cpp
template <std::size_t out_rank_>
tensor_span<value_type_, out_rank_> with_max_rank() const noexcept;
```

## as_vector

Convert to [vector_span](#vector_span); requires rank == 1.

```cpp
vector_span<value_type> as_vector() const noexcept;
```

## as_*_matrix

Narrow an already-2D handle to a rank-2 type.

```cpp
tensor_span<value_type_, 2> as__matrix() const noexcept;
```

Requires rank == 2; use reshape<2>({...}) to collapse a higher-rank tensor.

## values

Storage values as a contiguous span; [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) for a strided span or one whose last extent ends mid-value.

```cpp
expected<std::span<value_type>> values() const noexcept;
```

## *

Transpose: reverse the order of all dimensions, swapping extents and strides.

```cpp
tensor_span transpose() const noexcept;
```

## *

Reshape to new extents, requires contiguous layout and matching element count.

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_span<value_type_, out_rank_> reshape(
    std::initializer_list<size_type> new_extents) const noexcept;
```

The output rank may differ from the source; pass it as the template argument when narrowing or widening. Returns an empty span if not contiguous, if element counts don't match, or if the last extent is not a whole number of storage values.

The output rank may differ from the source; pass it as the template argument when narrowing or widening. Returns an empty view when not contiguous, when element counts disagree, or when the last extent is not a whole number of storage values.

## begin

Mutable element iterator, begin: yields ____(position,ref_or_proxy) pairs.

```cpp
tensor_span_iterator_<tensor_span> begin() const noexcept;
```

## end

Mutable element iterator, end.

```cpp
tensor_span_iterator_<tensor_span> end() const noexcept;
```

## dims

Mutable dimension-only view.

```cpp
tensor_dims_view_<tensor_span_iterator_<tensor_span>> dims() const noexcept;
```

## flatten

Flatten to 1D span, requires contiguous layout.

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_span<value_type_, out_rank_> flatten() const noexcept;
```

Returns empty span if not contiguous.

## fill_zeros

Zero-fill every element; declared here, defined after the free [`fill_zeros`](#fill_zeros).

```cpp
status_t fill_zeros() noexcept;
```

## fill

Fill every element with `value`; declared here, defined after the free [`fill`](#fill).

```cpp
status_t fill(value_type value) noexcept;
```

## copy_from

Copy from a same-shape view; declared here, defined after the free [`copy`](#copy).

```cpp
status_t copy_from(tensor_view<value_type_, max_rank_> input) noexcept;
```

## *

Remove dimensions of size 1.

```cpp
tensor_span squeeze() const noexcept;
```

## rows_spans_t

Range of mutable sub-spans along the leading dimension.

```cpp
struct rows_spans_t
```

- `parent` `tensor_span`

## tensor_view

Non-owning, immutable, N-dimensional view.

```cpp
template <typename value_type_,
          std::size_t max_rank_ = 8>
struct tensor_view
```

## tensor_view

Convenience constructor for rank-2 views from typed pointer, rows, and columns.

```cpp
constexpr tensor_view() noexcept=default;
```

```cpp
constexpr tensor_view(
    char const *data,
    shape_storage_<max_rank_> const & shape) noexcept;
```

```cpp
requires (max_rank_ >= 2)
constexpr tensor_view(
    value_type const *data,
    size_type rows,
    size_type columns) noexcept;
```

Convenience constructor for rank-2 views from typed pointer, rows, and columns.

```cpp
requires (max_rank_ >= 1)
constexpr tensor_view(value_type const *data, size_type count) noexcept;
```

Convenience constructor for a rank-1 view from a typed pointer and element [`count`](https://www.unum.cloud/docs/numkong/cpp/runtime-dispatch.md#count).

```cpp
template <typename span_value_type_, std::size_t span_extent_>
requires (max_rank_ >= 1 && std::is_same_v<std::remove_const_t<span_value_type_>, value_type>)
constexpr tensor_view(
    std::span<span_value_type_, span_extent_> values) noexcept;
```

Views contiguous storage values as a rank-1 tensor of every logical dimension they hold, the inverse of [values](#values).

```cpp
constexpr tensor_view(
    value_type const *data,
    std::initializer_list<size_type> extents) noexcept;
```

Convenience constructor from a typed pointer and an explicit `extents` list, where rank equals the list size.

```cpp
template <std::size_t array_rank_>
requires (array_rank_ <= max_rank_)
constexpr tensor_view(
    value_type const *data,
    std::array<size_type, array_rank_> const & extents) noexcept;
```

Convenience constructor from a typed pointer and a fixed-size `extents` array, where rank equals `array_rank_`.

An out-of-range rank, empty or greater than `max_rank_`, yields an empty handle rather than overflowing the fixed-capacity shape storage.

## slice_leading

Slice along the leading dimension.

```cpp
template <std::integral index_type_>
tensor_view<value_type_, max_rank_> slice_leading(
    index_type_ idx) const noexcept;
```

## operator[]

Rank-0 scalar access — `constexpr` like the accessors, so it stays device-callable.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

```cpp
tensor_view operator[](tensor_slice_t) const noexcept;
```

Trailing `slice` returns the same view.

## operator()

Exact multi-dimensional scalar lookup via call syntax, C++20-portable.

```cpp
template <std::integral... index_types_>
requires (sizeof...(index_types_) >= 2)
decltype(auto) operator()(index_types_... idxs) const noexcept;
```

```cpp
template <typename first_type_, typename second_type_, typename... rest_types_>
requires (trailing_tensor_slice_args_v<first_type_, second_type_, rest_types_...>)
auto operator()(
    first_type_ first,
    second_type_ second,
    rest_types_... rest) const noexcept;
```

Prefix leading-axis slicing with a trailing `slice` marker, call syntax, C++20-portable.

Every integral index drops one static rank.

## with_max_rank

The same view under the static rank `out_rank_`, which must hold its runtime rank; an empty view otherwise.

```cpp
template <std::size_t out_rank_>
tensor_view<value_type_, out_rank_> with_max_rank() const noexcept;
```

## scalar

Rank-0 scalar access.

```cpp
decltype(auto) scalar() const noexcept;
```

## as_vector

Convert to [vector_view](#vector_view); requires rank == 1.

```cpp
vector_view<value_type> as_vector() const noexcept;
```

## is_contiguous

Check if the tensor is contiguous in memory.

```cpp
bool is_contiguous() const noexcept;
```

## values

Storage values as a contiguous span; [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) for a strided view or one whose last extent ends mid-value.

```cpp
expected<std::span<value_type const>> values() const noexcept;
```

## begin

Element iterator, begin: yields ____(position,scalar) pairs.

```cpp
tensor_view_iterator_<tensor_view> begin() const noexcept;
```

## end

Element iterator, end.

```cpp
tensor_view_iterator_<tensor_view> end() const noexcept;
```

## dims

Dimension-only view: iterate scalars without positions.

```cpp
tensor_dims_view_<tensor_view_iterator_<tensor_view>> dims() const noexcept;
```

## flatten

Flatten to 1D view, requires contiguous layout.

```cpp
template <std::size_t out_rank_ = max_rank_>
tensor_view<value_type_, out_rank_> flatten() const noexcept;
```

Returns empty view if not contiguous.

## rows_views_t

Range of sub-views along the leading dimension.

```cpp
struct rows_views_t
```

- `parent` `tensor_view`

## vector

Owning, resizable-within-capacity, SIMD-aligned vector.

```cpp
template <typename value_type_,
          typename allocator_type_ = aligned_allocator<value_type_>>
struct vector
```

Use the `zeros()`/`uninitialized()` factories for non-throwing construction, which return the vector with the `[status_t](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#status_t)` explaining a failure, or `from_raw()` to adopt existing memory. `resize()` changes the size within the allocated `capacity()` without moving `values_data()`; `reserve()` is the explicit opt-in that may reallocate to grow capacity.

Supports signed indexing (`v[-1]`), sub-byte types via proxy references, and slicing via `operator[](range_t)`.

## vector

Default constructor — empty vector with default allocator.

```cpp
vector() noexcept=default;
```

```cpp
constexpr vector(allocator_type_ const & alloc) noexcept;
```

Construct with custom allocator.

```cpp
constexpr vector(vector && other) noexcept;
```

Move constructor.

```cpp
vector(vector const &)=delete;
```

## ~vector

Destructor — deallocates memory.

```cpp
~vector() noexcept;
```

## operator=

Move assignment with allocator propagation.

```cpp
vector & operator=(vector && other) noexcept;
```

```cpp
vector & operator=(vector const &)=delete;
```

## swap

Swap with another vector.

```cpp
void swap(vector & other) noexcept;
```

## capacity

Allocated storage-value capacity — the ceiling `resize()` honors.

```cpp
size_type capacity() const noexcept;
```

## resize

Resize in place to [`dims`](#dims) dimensions without reallocating: succeeds iff [`dims`](#dims) is a whole number of storage values that fits `capacity()`, so `values_data()` never moves.

```cpp
status_t resize(size_type dims) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) Leaving the size untouched.

## reserve

Grow the allocated `capacity()` to at least [`values`](#values) storage values.

```cpp
status_t reserve(size_type values) noexcept;
```

Unlike `resize()`, this may reallocate and move `values_data()`; the live elements are preserved. No-op when already large enough.

A failed growth leaves the state unchanged.

## clear

Reset to an empty size while keeping `capacity()`; storage frees on destruction.

```cpp
void clear() noexcept;
```

## *

Number of logical dimensions.

```cpp
size_type size() const noexcept;
```

## *

Check if empty.

```cpp
bool empty() const noexcept;
```

## operator bool

Contextual-bool: truthy when the vector owns storage.

```cpp
constexpr operator bool() const noexcept;
```

Enables the `if(!v)` empty-check idiom.

## size_values

Number of storage values.

```cpp
size_type size_values() const noexcept;
```

## size_bytes

Size in bytes.

```cpp
size_type size_bytes() const noexcept;
```

## values_data

Pointer to underlying data.

```cpp
value_type * values_data() noexcept;
```

```cpp
value_type const * values_data() const noexcept;
```

## data

Pointer to underlying data, so the vector satisfies `vector_of` through [`std::data`](https://www.unum.cloud/docs/numkong/cpp/mesh-alignment.md#data).

```cpp
value_type * data() noexcept;
```

```cpp
value_type const * data() const noexcept;
```

## get_allocator

Get a copy of the allocator.

```cpp
allocator_type get_allocator() const noexcept;
```

## operator[]

Signed dimension access.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) noexcept;
```

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

```cpp
vector_span<value_type> operator[](range_t r) noexcept;
```

Slice via [range_t](#range_t), returns a [vector_span](#vector_span).

```cpp
vector_view<value_type> operator[](range_t r) const noexcept;
```

Slice via [range_t](#range_t) (const), returns a [vector_view](#vector_view).

```cpp
vector_span<value_type> operator[](all_t) noexcept;
```

Select all elements as a span.

```cpp
vector_view<value_type> operator[](all_t) const noexcept;
```

Select all elements as a view.

Negative indices wrap from end.

## begin

Dimension iterator to beginning.

```cpp
iterator begin() noexcept;
```

```cpp
const_iterator begin() const noexcept;
```

## end

Dimension iterator to end.

```cpp
iterator end() noexcept;
```

```cpp
const_iterator end() const noexcept;
```

## copy_*_from

Copy from a same-size view.

```cpp
status_t copy__from(vector_view<value_type> input) noexcept;
```

memcpy on the contiguous fast path, per-element copy on the strided slow path.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) A size mismatch.
- [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) Strided sub-byte operands.

## zeros

Factory: allocate a zero-initialized vector with [`dims`](#dims) dimensions.

```cpp
expected<vector> zeros(
    size_type dims,
    allocator_type_ alloc = {}) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) [`dims`](#dims) is not a whole number of storage values.

## ones

Factory: allocate a vector filled with ones.

```cpp
expected<vector> ones(
    size_type dims,
    allocator_type_ alloc = {}) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) As [`full`](#full) reports.

## full

Factory: allocate a vector filled with `val`.

```cpp
expected<vector> full(
    size_type dims,
    value_type_ val,
    allocator_type_ alloc = {}) noexcept;
```

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) [`dims`](#dims) is not a whole number of storage values.

## uninitialized

Factory: allocate an uninitialized vector.

```cpp
expected<vector> uninitialized(
    size_type dims,
    allocator_type_ alloc = {}) noexcept;
```

Warnings: Contents are uninitialized. Caller must fill before reading.

Statuses: - [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) [`dims`](#dims) is not a whole number of storage values.

## from_raw

Factory: adopt raw memory.

```cpp
vector from_raw(
    pointer ptr,
    size_type dims,
    allocator_type_ alloc = {}) noexcept;
```

Caller transfers ownership.

- `ptr` (in): Pointer to data (must have been allocated by `alloc`).
- `dims` (in): Number of logical dimensions, a whole number of storage values.
- `alloc` (in): Allocator instance.

## vector_span

Non-owning, mutable, strided view into a vector.

```cpp
template <typename value_type_>
struct vector_span
```

Same as `[vector_view](#vector_view)` but allows mutation. Implicitly converts to `[vector_view](#vector_view)`.

## vector_span

Construct from contiguous typed pointer.

```cpp
constexpr vector_span() noexcept=default;
```

```cpp
template <std::unsigned_integral dims_type_, std::integral stride_type_>
constexpr vector_span(
    char *data,
    dims_type_ dims,
    stride_type_ stride) noexcept;
```

```cpp
template <std::unsigned_integral dims_type_>
constexpr vector_span(value_type *data, dims_type_ dims) noexcept;
```

Construct from contiguous typed pointer.

```cpp
template <std::size_t span_extent_>
constexpr vector_span(
    std::span<value_type, span_extent_> values) noexcept;
```

Spans contiguous storage values as every logical dimension they hold, the inverse of [values](#values).

## stride_bytes

Stride in bytes.

```cpp
difference_type stride_bytes() const noexcept;
```

## is_contiguous

True if contiguous.

```cpp
bool is_contiguous() const noexcept;
```

## *

Typed pointer (only valid if contiguous).

```cpp
value_type * data() const noexcept;
```

## values

Storage values as a contiguous span; [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) for a strided span or one ending mid-value.

```cpp
expected<std::span<value_type>> values() const noexcept;
```

## operator vector_view< value_type >

Implicit conversion to const view.

```cpp
constexpr operator vector_view< value_type >() const noexcept;
```

## operator[]

Mutable integral indexing.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

```cpp
vector_span operator[](range_t r) const noexcept;
```

Sub-slice via range.

```cpp
vector_span operator[](all_t) const noexcept;
```

Select all elements.

Signed negatives wrap from end.

## *

Dimension iterator to beginning.

```cpp
iterator begin() const noexcept;
```

The handle is shallow-const, so iteration yields mutable refs.

## *

Dimension iterator to end.

```cpp
iterator end() const noexcept;
```

## fill

Fill every element with `value`, mirroring the free [`fill`](#fill) on [tensor_span](#tensor_span): 1-byte storage uses a single byte_pattern memset, multi-byte storage a typed broadcast loop.

```cpp
status_t fill(value_type value) noexcept;
```

Statuses: - [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) A strided sub-byte span.

## vector_view

Non-owning, immutable, strided view into a vector.

```cpp
template <typename value_type_>
struct vector_view
```

Supports signed indexing (`v[-1]` = last element) and strided access. For sub-byte types, only contiguous views are meaningful.

## vector_view

Construct from contiguous typed pointer.

```cpp
constexpr vector_view() noexcept=default;
```

```cpp
template <std::unsigned_integral dims_type_, std::integral stride_type_>
constexpr vector_view(
    char const *data,
    dims_type_ dims,
    stride_type_ stride) noexcept;
```

```cpp
template <std::unsigned_integral dims_type_>
constexpr vector_view(value_type const *data, dims_type_ dims) noexcept;
```

Construct from contiguous typed pointer.

```cpp
template <typename span_value_type_, std::size_t span_extent_>
requires std::is_same_v<std::remove_const_t<span_value_type_>, value_type>
constexpr vector_view(
    std::span<span_value_type_, span_extent_> values) noexcept;
```

Views contiguous storage values as every logical dimension they hold, the inverse of [values](#values).

## stride_bytes

Stride in bytes between consecutive elements.

```cpp
difference_type stride_bytes() const noexcept;
```

## is_contiguous

True if elements are stored contiguously.

```cpp
bool is_contiguous() const noexcept;
```

## byte_data

Raw byte pointer to the first element.

```cpp
char const * byte_data() const noexcept;
```

## values

Storage values as a contiguous span; [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) for a strided view or one ending mid-value.

```cpp
expected<std::span<value_type const>> values() const noexcept;
```

## operator[]

Integral indexing: signed negatives wrap from end.

```cpp
template <std::integral index_type_>
decltype(auto) operator[](index_type_ idx) const noexcept;
```

```cpp
vector_view operator[](range_t r) const noexcept;
```

Sub-slice via range.

```cpp
vector_view operator[](all_t) const noexcept;
```

Select all elements (identity).

## rev

Create a reversed view by negating the stride and pointing to the last element.

```cpp
vector_view rev() const noexcept;
```

Iterating the returned view visits elements in reverse order.

## clamp

Lightweight clamp to avoid pulling in `<algorithm>` for [`std::clamp`](#clamp).

```cpp
template <typename scalar_type_>
scalar_type_ clamp(
    scalar_type_ val,
    scalar_type_ low,
    scalar_type_ high) noexcept;
```

## fill_uniform

Fill array with uniform random values.

```cpp
template <typename value_type_, typename generator_type_, typename component_type_ = typename value_type_::component_t>
void fill_uniform(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count,
    component_type_ min_val,
    component_type_ max_val) noexcept;
```

```cpp
template <typename value_type_, typename generator_type_>
void fill_uniform(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count) noexcept;
```

Fill array with uniform random values within specified range.

- `generator` (inout): The random number generator.
- `values_ptr` (out): Pointer to the array to fill.
- `values_count` (in): Number of storage values to fill, not dimensions for sub-byte types.
- `min_val` (in): Lowest value drawn.
- `max_val` (in): Highest value drawn.

## fill_lognormal

Fill array with lognormal distribution, good for detecting numerical edge cases.

```cpp
template <typename value_type_, typename generator_type_>
void fill_lognormal(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count,
    double mean = 0.0,
    double stddev = 0.5) noexcept;
```

Probability Density Function (PDF):

```
f(x; μ, σ) = 1 / (x · σ · √(2π)) · exp(−(ln x − μ)² / (2σ²)),  x > 0
```

Equivalently, if X ~ 𝒩(μ, σ²), then eˣ ~ LogNormal(μ, σ). Values span many orders of magnitude, which is useful for exercising overflow/underflow paths in low-precision arithmetic. Common in modeling latencies, file sizes, and NLP token frequencies.

## fill_cauchy

Fill array with Cauchy distribution, heavy tails for stress testing.

```cpp
template <typename value_type_, typename generator_type_>
void fill_cauchy(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count,
    double location = 0.0,
    double scale = 1.0) noexcept;
```

Probability Density Function (PDF):

```
f(x; x₀, γ) = 1 / (π · γ · (1 + ((x − x₀) / γ)²))
```

The Cauchy distribution has no defined mean or variance, as all its moments diverge, making it ideal for stress-testing numerical stability with extreme outliers. Common in robust Bayesian priors, half-Cauchy, metaheuristic Levy flights, and adversarial robustness evaluation.

## fill_coordinates

Fill arrays with latitude and longitude coordinate values in radians.

```cpp
template <typename value_type_, typename generator_type_>
void fill_coordinates(
    generator_type_ & generator,
    value_type_ *lats_ptr,
    value_type_ *lons_ptr,
    std::size_t values_count) noexcept;
```

## fill_nearby_coordinates

Fill destination coordinate arrays within a max angular separation of origin coordinates.

```cpp
template <typename value_type_, typename generator_type_>
void fill_nearby_coordinates(
    generator_type_ & generator,
    value_type_ const *origin_lats_ptr,
    value_type_ const *origin_lons_ptr,
    value_type_ *dest_lats_ptr,
    value_type_ *dest_lons_ptr,
    std::size_t values_count,
    double max_separation_rad) noexcept;
```

Uses the great-circle destination formula to place each destination point at a random angular distance (uniform in [0, `max_separation_rad`]) and random bearing from the corresponding origin point. Coordinates are in radians.

## fill_probability

Fill array as a probability distribution (sums to 1.0).

```cpp
template <typename value_type_, typename generator_type_>
void fill_probability(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count) noexcept;
```

## fill_sorted_unique

Fill array with sorted unique random integer values, in-place.

```cpp
template <typename value_type_, typename generator_type_>
void fill_sorted_unique(
    generator_type_ & generator,
    value_type_ *values_ptr,
    std::size_t values_count,
    value_type_ max_val) noexcept;
```

Draws `values_count` values from [0, `max_val` - values_count], sorts once, then adds each element's index. Duplicates become distinct, which guarantees uniqueness and keeps sorted order in O(n log n) with one sort and no retry loop. Requires `max_val` ≥ `values_count`.

## *

Non-member swap.

```cpp
template <typename V, typename A, std::size_t R>
void swap(tensor<V, A, R> & a, tensor<V, A, R> & b) noexcept;
```

- `swap`: a, b `tensor<V, A, R> &`
- `swap`: a, b `vector<value_type_, allocator_type_> &`

## fill_zeros

Zero-fill every element of `output` with one memset per maximal contiguous run, valid for every dtype as `is_memset_zero_safe_v` holds for all of them; returns [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) on a layout that no contiguous run can cover.

```cpp
template <typename value_type_, std::size_t max_rank_>
status_t fill_zeros(
    tensor_span<value_type_, max_rank_> output) noexcept;
```

## fill

Fill every element of `output` with `value`.

```cpp
template <typename value_type_, std::size_t max_rank_>
status_t fill(
    tensor_span<value_type_, max_rank_> output,
    value_type_ value) noexcept;
```

Two-step strategy: first memsets the buffer to binary zero, avoiding NaN/inf propagation from uninitialised memory, then overlays the value via memset for 1-byte storage or a typed scalar broadcast loop for multi-byte storage. Returns [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) on an unsupported layout.

## copy

Copy `input` element-by-element into `output`.

```cpp
template <typename value_type_, std::size_t max_rank_>
status_t copy(
    tensor_view<value_type_, max_rank_> input,
    tensor_span<value_type_, max_rank_> output) noexcept;
```

```cpp
template <typename value_type_, std::size_t max_rank_ = 8, typename allocator_type_ = aligned_allocator<value_type_>>
expected<tensor<value_type_, allocator_type_, max_rank_>> copy(
    tensor_view<value_type_, max_rank_> input,
    allocator_type_ alloc = {}) noexcept;
```

Allocating copy: returns a fresh contiguous tensor with the same shape and contents as `input`, empty for an empty `input`, or the allocation's or the copy's failure.

Recursive traversal collapses contiguous tail dims into one memcpy per leaf, and a strided last dim, as in a transposed view, copies value by value. Returns [`unexpected_dimensions_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#unexpected_dimensions_k) on a shape mismatch and [`misaligned_k`](https://www.unum.cloud/docs/numkong/cpp/quickstart.md#misaligned_k) on a layout it does not support.

## range

Builds a `[range_t](#range_t)`, so slices read `v[nk::range(1, 4)]`.

```cpp
template <std::integral start_type_, std::integral stop_type_, std::integral step_type_ = int>
range_t range(
    start_type_ start,
    stop_type_ stop,
    step_type_ step = 1) noexcept;
```

## enumerate

Returns a view yielding (index, value) pairs over a vector, view, or span.

```cpp
template <typename container_type_>
enumerate_view_<container_type_> enumerate(
    container_type_ & c) noexcept;
```

## all

Global instance of `[all_t](#all_t)` for use in slicing expressions.

```cpp
all_t all;
```

