# Vectors

### Vectors

A vector is a fixed-size group of values of the same type.

In Zig, vector types are written like this:

```zig
@Vector(length, ElementType)
```

For example:

```zig
const Vec4 = @Vector(4, i32);
```

This means:

```text
a vector with 4 i32 values
```

A value of this type holds four integers together:

```zig
const a: @Vector(4, i32) = .{ 1, 2, 3, 4 };
```

You can think of it as a small fixed-size array, but with special behavior. Vectors are designed for operations that happen on every element at once.

#### A Simple Vector Example

```zig
const std = @import("std");

pub fn main() void {
    const a: @Vector(4, i32) = .{ 1, 2, 3, 4 };
    const b: @Vector(4, i32) = .{ 10, 20, 30, 40 };

    const c = a + b;

    std.debug.print("{any}\n", .{c});
}
```

The result is:

```text
{ 11, 22, 33, 44 }
```

This line is the key:

```zig
const c = a + b;
```

For normal integers, `+` adds two numbers.

For vectors, `+` adds each pair of elements:

```text
{ 1, 2, 3, 4 }
+
{ 10, 20, 30, 40 }
=
{ 11, 22, 33, 44 }
```

The operation happens element by element.

#### Vector Length

The length of a vector is part of its type.

These are different types:

```zig
@Vector(4, i32)
@Vector(8, i32)
```

A vector of 4 integers and a vector of 8 integers are not the same type.

```zig
const a: @Vector(4, i32) = .{ 1, 2, 3, 4 };
const b: @Vector(8, i32) = .{ 1, 2, 3, 4, 5, 6, 7, 8 };
```

You cannot directly add them:

```zig
const c = a + b; // error
```

The compiler rejects this because the shapes do not match.

Both vectors must have the same length and compatible element types.

#### Vector Element Types

Vectors can use integer, floating-point, boolean, and pointer-like element types, depending on the operation.

Common examples:

```zig
@Vector(4, i32)
@Vector(8, u8)
@Vector(4, f32)
@Vector(2, f64)
@Vector(16, bool)
```

A vector type always has two important parts:

```text
how many elements it has
what type each element has
```

So:

```zig
@Vector(4, f32)
```

means:

```text
4 values, each one is an f32
```

#### Element-Wise Arithmetic

Most basic arithmetic operations work element by element.

```zig
const a: @Vector(4, i32) = .{ 8, 16, 24, 32 };
const b: @Vector(4, i32) = .{ 2, 4, 6, 8 };

const add = a + b;
const sub = a - b;
const mul = a * b;
const div = @divTrunc(a, b);
```

The results are:

```text
add = { 10, 20, 30, 40 }
sub = { 6, 12, 18, 24 }
mul = { 16, 64, 144, 256 }
div = { 4, 4, 4, 4 }
```

Notice the division example:

```zig
const div = @divTrunc(a, b);
```

For integer division in Zig, you usually use explicit division builtins such as `@divTrunc`, `@divFloor`, or `@divExact`. These can also work with vectors.

#### Floating-Point Vectors

Floating-point vectors are common in graphics, audio, physics, and numeric code.

```zig
const std = @import("std");

pub fn main() void {
    const x: @Vector(4, f32) = .{ 1.0, 2.0, 3.0, 4.0 };
    const y: @Vector(4, f32) = .{ 0.5, 0.5, 0.5, 0.5 };

    const z = x * y;

    std.debug.print("{any}\n", .{z});
}
```

The result is:

```text
{ 0.5, 1.0, 1.5, 2.0 }
```

Each element of `x` is multiplied by the matching element of `y`.

#### Accessing Vector Elements

You can access vector elements with indexing.

```zig
const v: @Vector(4, i32) = .{ 10, 20, 30, 40 };

const first = v[0];
const second = v[1];
```

Indexes start at `0`.

```text
v[0] is 10
v[1] is 20
v[2] is 30
v[3] is 40
```

Just like arrays, indexing outside the valid range is a mistake.

```zig
const bad = v[4]; // error or safety check failure
```

A vector of length 4 has valid indexes `0`, `1`, `2`, and `3`.

#### Modifying Vector Elements

If the vector variable is mutable, you can assign to individual elements.

```zig
var v: @Vector(4, i32) = .{ 1, 2, 3, 4 };

v[0] = 100;
v[3] = 400;
```

After this:

```text
v = { 100, 2, 3, 400 }
```

This makes vectors feel similar to arrays for simple storage.

But the main reason to use vectors is not indexing. The main reason is element-wise operations.

#### Vector Comparisons

Comparing two vectors produces a vector of booleans.

```zig
const a: @Vector(4, i32) = .{ 1, 5, 3, 9 };
const b: @Vector(4, i32) = .{ 2, 4, 3, 8 };

const result = a > b;
```

The comparison happens element by element:

```text
1 > 2  is false
5 > 4  is true
3 > 3  is false
9 > 8  is true
```

So `result` is:

```zig
@Vector(4, bool)
```

with values:

```text
{ false, true, false, true }
```

This is useful when you want to make masks.

A mask is a vector of booleans that says which elements passed a condition.

#### Selecting Values with `@select`

The builtin `@select` chooses elements from two vectors using a boolean vector.

```zig
const mask: @Vector(4, bool) = .{ true, false, true, false };

const a: @Vector(4, i32) = .{ 1, 1, 1, 1 };
const b: @Vector(4, i32) = .{ 2, 2, 2, 2 };

const c = @select(i32, mask, a, b);
```

The mask controls the result:

```text
if mask element is true, choose from a
if mask element is false, choose from b
```

So the result is:

```text
{ 1, 2, 1, 2 }
```

This can replace some branches in numeric code.

#### Splatting One Value into a Vector

Sometimes you want every element of a vector to contain the same value.

Use `@splat`.

```zig
const v: @Vector(4, i32) = @splat(7);
```

This creates:

```text
{ 7, 7, 7, 7 }
```

This is useful when combining a vector with one repeated value.

```zig
const values: @Vector(4, i32) = .{ 10, 20, 30, 40 };
const offset: @Vector(4, i32) = @splat(5);

const result = values + offset;
```

The result is:

```text
{ 15, 25, 35, 45 }
```

#### Vectors and Arrays

Vectors and arrays look similar, but they have different meanings.

An array is written like this:

```zig
[4]i32
```

A vector is written like this:

```zig
@Vector(4, i32)
```

Both contain 4 integers.

But an array is a general fixed-size collection. A vector is intended for element-wise computation and possible SIMD optimization.

SIMD means “single instruction, multiple data.” The CPU may be able to process several values with one instruction.

You do not need to understand SIMD deeply to use vectors. The simple rule is this:

Use arrays for ordinary fixed-size storage.

Use vectors when you want to perform the same operation across several values.

#### Converting Between Arrays and Vectors

You can initialize a vector from a list of values:

```zig
const v: @Vector(4, i32) = .{ 1, 2, 3, 4 };
```

You can also store vector data into an array when needed.

```zig
const v: @Vector(4, i32) = .{ 1, 2, 3, 4 };
const a: [4]i32 = v;
```

Now `a` is an array:

```zig
[4]i32
```

This can be useful when you need to pass data to code that expects an array.

#### A Practical Example: Adding Two Small Buffers

Suppose you have two small groups of numbers and want to add them.

Without vectors, you might write:

```zig
fn add4(a: [4]i32, b: [4]i32) [4]i32 {
    return .{
        a[0] + b[0],
        a[1] + b[1],
        a[2] + b[2],
        a[3] + b[3],
    };
}
```

With vectors:

```zig
fn add4(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
    return a + b;
}
```

The vector version says the idea directly:

```text
add these four values to those four values
```

The compiler handles the element-wise work.

#### When Vectors Are Useful

Vectors are useful for code that processes many similar values.

Common examples include:

```text
graphics coordinates
colors
audio samples
physics calculations
matrix and vector math
parsing byte chunks
cryptography
compression
image processing
numeric kernels
```

For example, a color can be represented as four channels:

```zig
const Color = @Vector(4, f32);

const red: Color = .{ 1.0, 0.0, 0.0, 1.0 };
const darker = red * @as(Color, @splat(0.5));
```

The result is:

```text
{ 0.5, 0.0, 0.0, 0.5 }
```

Each channel is multiplied by `0.5`.

#### When Not to Use Vectors

Do not use vectors just because they look compact.

This is not always better:

```zig
const point: @Vector(2, i32) = .{ 10, 20 };
```

For simple application data, a struct may be clearer:

```zig
const Point = struct {
    x: i32,
    y: i32,
};
```

The struct has names. The vector has positions.

Use a struct when the fields have different meanings.

Use a vector when the elements are the same kind of data and you want the same operation on all of them.

#### A Common Beginner Mistake

A vector is not a growable list.

This is fixed-size:

```zig
@Vector(4, i32)
```

You cannot append to it.

You cannot make it length 5 at runtime.

The length is known at compile time and is part of the type.

For growable storage, use something like `std.ArrayList`.

For fixed storage, use an array.

For element-wise computation, use a vector.

#### The Main Idea

A vector is a fixed-size group of same-type values designed for element-wise operations.

```zig
const a: @Vector(4, i32) = .{ 1, 2, 3, 4 };
const b: @Vector(4, i32) = .{ 10, 20, 30, 40 };

const c = a + b;
```

The result is:

```text
{ 11, 22, 33, 44 }
```

Zig vectors are useful when the data is uniform and the operation is uniform.

They are not replacements for all arrays or structs. They are a specific tool for a specific kind of work: doing the same operation across several values at once.

