# `Zvex.Vector`
[🔗](https://github.com/edlontech/zvex/blob/main/lib/zvex/vector.ex#L1)

Pure Elixir vector packing/unpacking for dense and sparse vector types.

Converts between Elixir lists and native-endian binary representations
used by zvec. Supports fp16, fp32, fp64, int4, int8, int16, binary32,
and binary64 dense vector types, as well as sparse_fp16 and sparse_fp32
sparse vector types.

## Dense Example

    iex> vector = Zvex.Vector.from_list([1.0, 2.0, 3.0], :fp32)
    iex> Zvex.Vector.to_list(vector)
    [1.0, 2.0, 3.0]
    iex> Zvex.Vector.dimension(vector)
    3

## Sparse Example

    iex> vector = Zvex.Vector.from_sparse([0, 5, 10], [1.0, 2.5, -3.0], :sparse_fp32)
    iex> Zvex.Vector.to_sparse(vector)
    {[0, 5, 10], [1.0, 2.5, -3.0]}
    iex> Zvex.Vector.sparse?(vector)
    true

# `shorthand`

```elixir
@type shorthand() ::
  :fp16
  | :fp32
  | :fp64
  | :int4
  | :int8
  | :int16
  | :binary32
  | :binary64
  | :sparse_fp16
  | :sparse_fp32
```

Shorthand alias used in `from_list/2`, `from_binary/2`, and `from_sparse/3`.

Each shorthand maps to a full type (e.g. `:fp32` -> `:vector_fp32`,
`:sparse_fp32` -> `:sparse_vector_fp32`).

# `t`

```elixir
@type t() :: %Zvex.Vector{data: binary(), type: type()}
```

# `type`

```elixir
@type type() ::
  :vector_fp16
  | :vector_fp32
  | :vector_fp64
  | :vector_int4
  | :vector_int8
  | :vector_int16
  | :vector_binary32
  | :vector_binary64
  | :sparse_vector_fp16
  | :sparse_vector_fp32
```

Full vector type atom as stored in the struct and in document fields.

# `dimension`

```elixir
@spec dimension(t()) :: non_neg_integer() | nil
```

Returns the number of elements (dimension) in a dense vector.

Returns `nil` for sparse vectors, since sparse vectors don't have a fixed
dimension. Use `nnz/1` to get the number of non-zero entries instead.

# `from_binary`

```elixir
@spec from_binary(binary(), shorthand()) :: t()
```

Wraps a pre-packed binary as a dense vector of the given `type`.

No validation is performed on the binary contents — it is assumed to
already be in the correct native-endian format for the given type.

# `from_list`

```elixir
@spec from_list([number()], shorthand()) :: t()
```

Packs a list of numbers into a dense vector binary.

The `type` is a shorthand atom (e.g. `:fp32`, `:int8`). Sparse shorthands
are not accepted — use `from_sparse/3` instead.

## Examples

    iex> vec = Zvex.Vector.from_list([1.0, 2.0, 3.0], :fp32)
    iex> Zvex.Vector.dimension(vec)
    3

# `from_sparse`

```elixir
@spec from_sparse([non_neg_integer()], [number()], type() | shorthand()) :: t()
```

Creates a sparse vector from index and value lists.

The `type` must be either `:sparse_fp32` or `:sparse_fp16`.
Indices must be non-negative, sorted in ascending order, with no duplicates.
The indices and values lists must have the same length.

The binary layout is `[nnz::uint64-little][indices::uint32-little * nnz][values::type * nnz]`.

# `nnz`

```elixir
@spec nnz(t()) :: non_neg_integer()
```

Returns the number of non-zero elements in a sparse vector.

Raises `ArgumentError` for dense vectors.

# `sparse?`

```elixir
@spec sparse?(t()) :: boolean()
```

Returns `true` if the vector is a sparse type.

# `to_list`

```elixir
@spec to_list(t()) :: [number() | :infinity | :neg_infinity | :nan]
```

Unpacks a dense vector back to a list of numbers.

For fp16 vectors, special IEEE 754 values may appear as `:infinity`,
`:neg_infinity`, or `:nan`. Sparse vectors are not supported — use
`to_sparse/1` instead.

# `to_sparse`

```elixir
@spec to_sparse(t()) :: {[non_neg_integer()], [number()]}
```

Unpacks a sparse vector back to `{indices, values}`.

Raises `ArgumentError` if the vector is not a sparse type.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
