vkML 0.1.0

Comparison

7 functions — 7 documented.

equal

equal(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input == other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

Every comparison against NaN is false, including NaN == NaN, which is IEEE-754 and matches torch. The input dtype and the output dtype are tracked separately — a comparison's output is always bool, and the shader reads the input dtype to decide how to load, a distinction the CPU kernel originally got wrong by checking the output dtype and reading f32 regardless.

Example

>>> vkml.equal(vkml.tensor(np.array([1.0, 2.0], dtype=np.float32)),
...            vkml.tensor(np.array([1.0, 3.0], dtype=np.float32))).numpy()
array([ True, False])

Implementation

Declared ininclude/vkml/api/ops.h:29
Graph nodeOpKind::Equal
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:292
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Tests (≥1)test_vulkan_kernels.py

See also not_equal, less, where

not_equal

not_equal(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input != other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

NaN != NaN is true — the only comparison a NaN satisfies, since every other comparison against NaN is false.

Example

>>> vkml.not_equal(vkml.tensor(np.array([1.0, float('nan')], dtype=np.float32)),
...                vkml.tensor(np.array([1.0, float('nan')], dtype=np.float32))).numpy()
array([False,  True])

Implementation

Declared ininclude/vkml/api/ops.h:34
Graph nodeOpKind::NotEqual
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:312
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Testsnone found by name

See also equal, where

less

less(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input < other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

Every comparison against NaN is false, including NaN == NaN, which is IEEE-754 and matches torch. The input dtype and the output dtype are tracked separately — a comparison's output is always bool, and the shader reads the input dtype to decide how to load, a distinction the CPU kernel originally got wrong by checking the output dtype and reading f32 regardless.

Example

>>> vkml.less(vkml.tensor(np.array([1.0, 3.0], dtype=np.float32)),
...           vkml.tensor(np.array([2.0, 2.0], dtype=np.float32))).numpy()
array([ True, False])

Implementation

Declared ininclude/vkml/api/ops.h:30
Graph nodeOpKind::Less
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:296
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Tests (≥1)test_vulkan_kernels.py

See also less_equal, greater, where

less_equal

less_equal(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input <= other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

Every comparison against NaN is false, including NaN == NaN, which is IEEE-754 and matches torch. The input dtype and the output dtype are tracked separately — a comparison's output is always bool, and the shader reads the input dtype to decide how to load, a distinction the CPU kernel originally got wrong by checking the output dtype and reading f32 regardless.

Example

>>> vkml.less_equal(vkml.tensor(np.array([2.0, 3.0], dtype=np.float32)),
...                 vkml.tensor(np.array([2.0, 2.0], dtype=np.float32))).numpy()
array([ True, False])

Implementation

Declared ininclude/vkml/api/ops.h:32
Graph nodeOpKind::LessEqual
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:304
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Testsnone found by name

See also less, greater_equal, relu

greater

greater(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input > other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

Every comparison against NaN is false, including NaN == NaN, which is IEEE-754 and matches torch. The input dtype and the output dtype are tracked separately — a comparison's output is always bool, and the shader reads the input dtype to decide how to load, a distinction the CPU kernel originally got wrong by checking the output dtype and reading f32 regardless.

Example

>>> vkml.greater(vkml.tensor(np.array([3.0, 1.0], dtype=np.float32)),
...              vkml.tensor(np.array([2.0, 2.0], dtype=np.float32))).numpy()
array([ True, False])

Implementation

Declared ininclude/vkml/api/ops.h:31
Graph nodeOpKind::Greater
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:300
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Tests (≥2)test_ops_vs_torch.py test_vulkan_kernels.py

See also greater_equal, less, where

greater_equal

greater_equal(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise input >= other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Arithmetic and comparison share a single shader. The operation is a specialisation constant, so the driver folds the switch away at pipeline creation and each variant is as tight as a dedicated shader. Comparisons live there too because everything except the final store is identical — same broadcast indexing, same operand layout, same bounds check — and only the destination element type differs, which is also decided at pipeline creation.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A bool tensor of the broadcast shape.

ⓘ Note

Every comparison against NaN is false, including NaN == NaN, which is IEEE-754 and matches torch. The input dtype and the output dtype are tracked separately — a comparison's output is always bool, and the shader reads the input dtype to decide how to load, a distinction the CPU kernel originally got wrong by checking the output dtype and reading f32 regardless.

Example

>>> vkml.greater_equal(vkml.tensor(np.array([2.0, 1.0], dtype=np.float32)),
...                    vkml.tensor(np.array([2.0, 2.0], dtype=np.float32))).numpy()
array([ True, False])

Implementation

Declared ininclude/vkml/api/ops.h:33
Graph nodeOpKind::GreaterEqual
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:308
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient rulenone — backward through it raises
Historycommits touching the CPU kernel
Testsnone found by name

See also greater, less_equal

where

where(condition: Tensor, x: Tensor, y: Tensor) → Tensor
CPUVulkan

Select element-wise from two tensors according to a condition.

condition ? a : b, broadcast across all three operands.

Both branches are always evaluated. That is what element-wise selection means: where chooses between two values that already exist, it does not avoid computing one. Where a branch would produce inf or NaN, the arithmetic still happens and the result is discarded — kl_div relies on exactly this, computing log(0) = -inf and throwing the poisoned product away.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

condition (Tensor)
A bool tensor.
input (Tensor)
Taken where condition is true.
other (Tensor)
Taken where condition is false.

Returns

A tensor of the broadcast shape, with input's dtype.

ⓘ Note

Its push-constant block was repacked to fit the 128-byte guarantee by storing shared extents once instead of per operand — the three operands of a where usually agree on shape, which is what made that possible.

Example

>>> c = vkml.greater(vkml.tensor(np.array([1.0, 3.0], dtype=np.float32)),
...                  vkml.tensor(np.array([2.0, 2.0], dtype=np.float32)))
>>> vkml.where(c, vkml.tensor(np.array([10.0, 20.0], dtype=np.float32)),
...            vkml.tensor(np.array([-1.0, -2.0], dtype=np.float32))).numpy()
array([-1., 20.], dtype=float32)

From the header

[[nodiscard]] Tensor where(const Tensor& cond, const Tensor& a, const Tensor& b);include/vkml/api/ops.h:87

Elementwise select. cond must be Bool; all three broadcast together.

Implementation

Declared ininclude/vkml/api/ops.h:87
Graph nodeOpKind::Where
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:370
Vulkan shadershaders/where.comp (64 lines · 2 specialisation constants)
Gradient ruleautograd.cpp:263
DecisionsADR 0009 ADR 0013
Historycommits touching the CPU kernel
Tests (≥8)test_f16.py test_operand_packing.py test_ops_vs_torch.py test_vulkan_kernels.py

See also greater, masked_fill, clamp, kl_div

vkML — Vulkan-first machine learning in C++20. Apache-2.0. Signatures on this page are generated from the installed module.