Skip to content

Commit

Permalink
Break: Generalizing from "metrics" to "kernels"
Browse files Browse the repository at this point in the history
This commit changes the low-level naming convention
to make it more friendly to upcoming matrix-multiplication
kernels.
  • Loading branch information
ashvardanian committed Oct 28, 2024
1 parent 58ec221 commit 9910b2a
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 170 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@
"format": "c",
"execution": "cpp",
"math.h": "c",
"float.h": "c"
"float.h": "c",
"text_encoding": "cpp",
"stdio.h": "c"
},
"cSpell.words": [
"allclose",
Expand Down
29 changes: 29 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,35 @@ bun test
swift build && swift test -v
```
Running Swift on Linux requires a couple of extra steps, as the Swift compiler is not available in the default repositories.
Please get the most recent Swift tarball from the [official website](https://www.swift.org/install/).
At the time of writing, for 64-bit Arm CPU running Ubuntu 22.04, the following commands would work:
```bash
wget https://download.swift.org/swift-5.9.2-release/ubuntu2204-aarch64/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04-aarch64.tar.gz
tar xzf swift-5.9.2-RELEASE-ubuntu22.04-aarch64.tar.gz
sudo mv swift-5.9.2-RELEASE-ubuntu22.04-aarch64 /usr/share/swift
echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
source ~/.bashrc
```
You can check the available images on [`swift.org/download` page](https://www.swift.org/download/#releases).
For x86 CPUs, the following commands would work:
```bash
wget https://download.swift.org/swift-5.9.2-release/ubuntu2204/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04.tar.gz
tar xzf swift-5.9.2-RELEASE-ubuntu22.04.tar.gz
sudo mv swift-5.9.2-RELEASE-ubuntu22.04 /usr/share/swift
echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
source ~/.bashrc
```
Alternatively, on Linux, the official Swift Docker image can be used for builds and tests:
```bash
sudo docker run --rm -v "$PWD:/workspace" -w /workspace swift:5.9 /bin/bash -cl "swift build -c release --static-swift-stdlib && swift test -c release --enable-test-discovery"
```
## GoLang
```sh
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,15 @@ matrix1 = np.packbits(np.random.randint(2, size=(10_000, ndim)).astype(np.uint8)
matrix2 = np.packbits(np.random.randint(2, size=(1_000, ndim)).astype(np.uint8))

distances = simsimd.cdist(matrix1, matrix2,
metric="hamming", # Unlike SciPy, SimSIMD doesn't divide by the number of dimensions
out_dtype="u8", # so we can use `u8` instead of `f64` to save memory.
threads=0, # Use all CPU cores with OpenMP.
dtype="b8", # Override input argument type to `b8` eight-bit words.
metric="hamming", # Unlike SciPy, SimSIMD doesn't divide by the number of dimensions
out_dtype="uint8", # so we can use `uint8` instead of `float64` to save memory.
threads=0, # Use all CPU cores with OpenMP.
dtype="bin8", # Override input argument type to `bin8` eight-bit words.
)
```

By default, the output distances will be stored in double-precision `f64` floating-point numbers.
That behavior may not be space-efficient, especially if you are computing the hamming distance between short binary vectors, that will generally fit into 8x smaller `u8` or `u16` types.
By default, the output distances will be stored in double-precision `float64` floating-point numbers.
That behavior may not be space-efficient, especially if you are computing the hamming distance between short binary vectors, that will generally fit into 8x smaller `uint8` or `uint16` types.
To override this behavior, use the `dtype` argument.

### Helper Functions
Expand Down Expand Up @@ -636,7 +636,7 @@ Simplest of all, you can include the headers, and the compiler will automaticall
int main() {
simsimd_f32_t vector_a[1536];
simsimd_f32_t vector_b[1536];
simsimd_metric_punned_t distance_function = simsimd_metric_punned(
simsimd_kernel_punned_t distance_function = simsimd_metric_punned(
simsimd_metric_cos_k, // Metric kind, like the angular cosine distance
simsimd_datatype_f32_k, // Data type, like: f16, f32, f64, i8, b8, and complex variants
simsimd_cap_any_k); // Which CPU capabilities are we allowed to use
Expand Down Expand Up @@ -1149,7 +1149,7 @@ All of the function names follow the same pattern: `simsimd_{function}_{type}_{b
- The type can be `f64`, `f32`, `f16`, `bf16`, `f64c`, `f32c`, `f16c`, `bf16c`, `i8`, or `b8`.
- The function can be `dot`, `vdot`, `cos`, `l2sq`, `hamming`, `jaccard`, `kl`, `js`, or `intersect`.

To avoid hard-coding the backend, you can use the `simsimd_metric_punned_t` to pun the function pointer and the `simsimd_capabilities` function to get the available backends at runtime.
To avoid hard-coding the backend, you can use the `simsimd_kernel_punned_t` to pun the function pointer and the `simsimd_capabilities` function to get the available backends at runtime.
To match all the function names, consider a RegEx:

```regex
Expand Down
51 changes: 26 additions & 25 deletions c/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,21 @@ extern "C" {
// If no metric is found, it returns NaN. We can obtain NaN by dividing 0.0 by 0.0, but that annoys
// the MSVC compiler. Instead we can directly write-in the signaling NaN (0x7FF0000000000001)
// or the qNaN (0x7FF8000000000000).
#define SIMSIMD_DECLARATION_DENSE(name, extension, type) \
SIMSIMD_DYNAMIC void simsimd_##name##_##extension(simsimd_##type##_t const *a, simsimd_##type##_t const *b, \
simsimd_size_t n, simsimd_distance_t *results) { \
static simsimd_metric_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, &metric, &used_capability); \
if (!metric) { \
*(simsimd_u64_t *)results = 0x7FF0000000000001ull; \
return; \
} \
} \
metric(a, b, n, results); \
#define SIMSIMD_DECLARATION_DENSE(name, extension, type) \
SIMSIMD_DYNAMIC void simsimd_##name##_##extension(simsimd_##type##_t const *a, simsimd_##type##_t const *b, \
simsimd_size_t n, simsimd_distance_t *results) { \
static simsimd_metric_dense_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_kernel_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, (simsimd_kernel_punned_t *)&metric, \
&used_capability); \
if (!metric) { \
*(simsimd_u64_t *)results = 0x7FF0000000000001ull; \
return; \
} \
} \
metric(a, b, n, results); \
}

#define SIMSIMD_DECLARATION_SPARSE(name, extension, type) \
Expand All @@ -78,9 +79,9 @@ extern "C" {
static simsimd_metric_sparse_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_find_kernel_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, \
(simsimd_metric_punned_t *)(&metric), &used_capability); \
(simsimd_kernel_punned_t *)(&metric), &used_capability); \
if (!metric) { \
*(simsimd_u64_t *)result = 0x7FF0000000000001ull; \
return; \
Expand All @@ -96,9 +97,9 @@ extern "C" {
static simsimd_metric_curved_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_find_kernel_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, \
(simsimd_metric_punned_t *)(&metric), &used_capability); \
(simsimd_kernel_punned_t *)(&metric), &used_capability); \
if (!metric) { \
*(simsimd_u64_t *)result = 0x7FF0000000000001ull; \
return; \
Expand All @@ -114,9 +115,9 @@ extern "C" {
static simsimd_kernel_fma_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_find_kernel_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, \
(simsimd_metric_punned_t *)(&metric), &used_capability); \
(simsimd_kernel_punned_t *)(&metric), &used_capability); \
} \
metric(a, b, c, n, alpha, beta, result); \
}
Expand All @@ -128,9 +129,9 @@ extern "C" {
static simsimd_kernel_wsum_punned_t metric = 0; \
if (metric == 0) { \
simsimd_capability_t used_capability; \
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_find_kernel_punned(simsimd_metric_##name##_k, simsimd_datatype_##extension##_k, \
simsimd_capabilities(), simsimd_cap_any_k, \
(simsimd_metric_punned_t *)(&metric), &used_capability); \
(simsimd_kernel_punned_t *)(&metric), &used_capability); \
} \
metric(a, b, n, alpha, beta, result); \
}
Expand Down Expand Up @@ -326,14 +327,14 @@ SIMSIMD_DYNAMIC simsimd_capability_t simsimd_capabilities(void) {
return static_capabilities;
}

SIMSIMD_DYNAMIC void simsimd_find_metric_punned( //
SIMSIMD_DYNAMIC void simsimd_find_kernel_punned( //
simsimd_metric_kind_t kind, //
simsimd_datatype_t datatype, //
simsimd_capability_t supported, //
simsimd_capability_t allowed, //
simsimd_metric_punned_t *metric_output, //
simsimd_kernel_punned_t *kernel_output, //
simsimd_capability_t *capability_output) {
_simsimd_find_metric_punned_implementation(kind, datatype, supported, allowed, metric_output, capability_output);
_simsimd_find_kernel_punned_implementation(kind, datatype, supported, allowed, kernel_output, capability_output);
}

#ifdef __cplusplus
Expand Down
4 changes: 2 additions & 2 deletions include/simsimd/elementwise.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
* x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
* Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
*/
#ifndef SIMSIMD_FMA_H
#define SIMSIMD_FMA_H
#ifndef SIMSIMD_ELEMENTWISE_H
#define SIMSIMD_ELEMENTWISE_H

#include "types.h"

Expand Down
Loading

0 comments on commit 9910b2a

Please sign in to comment.