17个稳定版本

5.0.1 2024年8月18日
4.4.0 2024年6月20日
4.2.2 2024年3月31日
3.9.0 2024年3月4日
0.1.2 2024年1月27日

#25 in 硬件支持

Download history 46/week @ 2024-05-01 31/week @ 2024-05-08 171/week @ 2024-05-15 640/week @ 2024-05-22 380/week @ 2024-05-29 559/week @ 2024-06-05 231/week @ 2024-06-12 480/week @ 2024-06-19 91/week @ 2024-06-26 426/week @ 2024-07-03 756/week @ 2024-07-10 1081/week @ 2024-07-17 983/week @ 2024-07-24 1158/week @ 2024-07-31 684/week @ 2024-08-07 606/week @ 2024-08-14

3,598次每月下载
2 crates中使用

Apache-2.0

83KB
987

SimSIMD 📏

SimSIMD banner

在机器学习、科学计算、地理空间分析和信息检索中,计算低维和高维向量之间的点积、相似度测度和距离是普遍存在的。这些算法通常具有线性时间复杂度,空间复杂度恒定,并且是数据并行的。换句话说,它易于并行化和矢量化,通常在BLAS和LAPACK等包以及高级的numpyscipy Python库中可用。讽刺的是,尽管编译器和数值计算已经发展了几十年,大多数库即使在最流行的硬件(如64位x86和Arm CPU)上,也通常比硬件潜力慢3-200倍。SimSIMD试图填补这一空白。 1️⃣ SimSIMD函数的运行速度几乎与memcpy相同。2️⃣ SimSIMD比NumPy(105 vs 35)编译到更多平台,并且比大多数BLAS实现拥有更多的后端。

特性

SimSIMD提供了100多个针对各种距离和相似度度量的SIMD优化内核,加速了USearch和几个数据库管理系统产品的搜索。实现的距离函数包括

  • 向量搜索的空间距离(欧几里得(L2)和余弦(角度)距离)。
  • 实数和复数向量的点积,用于DSP和量子计算。
  • 汉明(~曼哈顿)和贾卡德(~坦尼托)位级距离。
  • 概率分布的Kullback-Leibler和Jensen-Shannon散度。
  • 用于地理空间分析的哈弗辛公式和文森蒂公式。
  • 对于Levenshtein、Needleman-Wunsch和其他文本度量,请查看StringZilla

此外,SimSIMD...

  • 处理f64f32f16实数和复数向量。
  • 处理i8整数和b8二进制向量。
  • 是一个零依赖的只包含头文件的C 99库。
  • 支持PythonRustJavaScript
  • 具有NEON和可伸缩向量扩展(SVE)的Arm后端。
  • 具有Haswell、Skylake、Ice Lake和Sapphire Rapids的x86后端。

由于不同x86 CPU上SIMD支持的碎片化程度很高,SimSIMD使用选定英特尔CPU代号的名称作为其后端。然而,它们也适用于AMD CPU。英特尔Haswell与AMD Zen 1/2/3兼容,而AMD Genoa Zen 4涵盖了添加到英特尔Skylake和Ice Lake的AVX-512指令。您可以在以下博客文章中了解更多有关技术实现细节的信息:

基准测试

与NumPy和SciPy进行比较

给定来自OpenAI Ada API的1000个1536维嵌入,在支持NEON的Apple M2 Pro Arm CPU上运行,以下是SimSIMD与常规方法的性能表现:

类型 f32改进 f16改进 i8改进 常规方法 SimSIMD
内积 2倍 9倍 18倍 numpy.inner inner
余弦距离 32倍 79倍 133倍 scipy.spatial.distance.cosine cosine
欧几里得距离² 5倍 26倍 17倍 scipy.spatial.distance.sqeuclidean sqeuclidean
Jensen-Shannon 散度 31倍 53倍 scipy.spatial.distance.jensenshannon jensenshannon

与GCC自动向量化进行比较

在英特尔Sapphire Rapids平台上,SimSIMD与使用GCC 12自动向量化的代码进行了基准测试。GCC处理单精度float,但对于自2011年以来一直是C语言一部分的int8_Float16数组,可能不是最佳选择。

类型 GCC 12 f32 GCC 12 f16 SimSIMD f16 f16改进
内积 3,810 K/s 192 K/s 5,990 K/s 31倍
余弦距离 3,280 K/s 336 K/s 6,880 K/s 20倍
欧几里得距离² 4,620 K/s 147 K/s 5,320 K/s 36倍
Jensen-Shannon 散度 1,180 K/s 18 K/s 2,140 K/s 118倍

更广泛的基准测试结果:

在Python中使用SimSIMD

该包旨在取代对 numpy.innernumpy.dotscipy.spatial.distance 的使用。除了显著提升性能外,SimSIMD 在混合精度配置中大幅提高了精度。NumPy 和 SciPy 处理 i8f16 向量时,将使用相同的累加器类型,而 SimSIMD 可以结合 i8 枚举、i16 乘法和 i32 累加,以完全避免溢出。同样适用于以 f32 精度处理 f16 值。

安装

使用以下代码片段安装 SimSIMD 并列出您的机器上可用的硬件加速选项

pip install simsimd
python -c "import simsimd; print(simsimd.get_capabilities())"

一对一距离

import simsimd
import numpy as np

vec1 = np.random.randn(1536).astype(np.float32)
vec2 = np.random.randn(1536).astype(np.float32)
dist = simsimd.cosine(vec1, vec2)

支持的功能包括 cosineinnersqeuclideanhammingjaccard。支持实数和复数的点积

vec1 = np.random.randn(768).astype(np.float64) + 1j * np.random.randn(768).astype(np.float64)
vec2 = np.random.randn(768).astype(np.float64) + 1j * np.random.randn(768).astype(np.float64)

dist = simsimd.dot(vec1.astype(np.complex128), vec2.astype(np.complex128))
dist = simsimd.dot(vec1.astype(np.complex64), vec2.astype(np.complex64))
dist = simsimd.vdot(vec1.astype(np.complex64), vec2.astype(np.complex64)) # conjugate, same as `np.vdot`

与 SciPy 不同,SimSIMD 允许显式声明输入向量的精度,这对于混合精度配置特别有用。

dist = simsimd.cosine(vec1, vec2, "i8")
dist = simsimd.cosine(vec1, vec2, "f16")
dist = simsimd.cosine(vec1, vec2, "f32")
dist = simsimd.cosine(vec1, vec2, "f64")

它还允许使用 SimSIMD 处理 NumPy 不支持的半精度复数。为此,将数据视为连续的偶数长度的 np.float16 向量,并用 complex32 字符串覆盖类型解析。

vec1 = np.random.randn(1536).astype(np.float16)
vec2 = np.random.randn(1536).astype(np.float16)
simd.dot(vec1, vec2, "complex32")
simd.vdot(vec1, vec2, "complex32")

一对多距离

每个距离函数不仅可以用于一对一,还可以用于一对多和多多距离计算。对于一对多

vec1 = np.random.randn(1536).astype(np.float32) # rank 1 tensor
batch1 = np.random.randn(1, 1536).astype(np.float32) # rank 2 tensor
batch2 = np.random.randn(100, 1536).astype(np.float32)

dist_rank1 = simsimd.cosine(vec1, batch2)
dist_rank2 = simsimd.cosine(batch1, batch2)

多多距离

SimSIMD 中的所有距离函数都可以用于计算多多距离。对于两个包含 100 个向量的批次计算 100 个距离,可以这样调用

batch1 = np.random.randn(100, 1536).astype(np.float32)
batch2 = np.random.randn(100, 1536).astype(np.float32)
dist = simsimd.cosine(batch1, batch2)

输入矩阵必须具有相同的形状。这种功能在 NumPy 或 SciPy 中不是原生存在的,通常需要创建中间数组,这既低效又消耗内存。

多多所有对距离

可以使用 SimSIMD 计算两个矩阵中所有可能行对之间的距离(类似于 scipy.spatial.distance.cdist)。结果对象将具有 DistancesTensor 类型,与 NumPy 和其他库零拷贝兼容。对于两个包含 10 和 1,000 个条目的数组,结果张量将有 10,000 个单元格

import numpy as np
from simsimd import cdist, DistancesTensor

matrix1 = np.random.randn(1000, 1536).astype(np.float32)
matrix2 = np.random.randn(10, 1536).astype(np.float32)
distances: DistancesTensor = simsimd.cdist(matrix1, matrix2, metric="cosine") # zero-copy
distances_array: np.ndarray = np.array(distances, copy=True) # now managed by NumPy

多线程

默认情况下,计算使用单个 CPU 核心。为了在 Linux 系统上优化并利用所有 CPU 核心,请添加 threads=0 参数。或者,指定自定义的线程数

distances = simsimd.cdist(matrix1, matrix2, metric="cosine", threads=0)

使用 USearch 与 Python API

想用 USearch 在 Python 中使用它吗?您可以包装 SimSIMD 后端的原始 C 函数指针,将其包装到 CompiledMetric 中,并将其传递给 USearch,类似于它处理 Numba 的 JIT 编译代码。

from usearch.index import Index, CompiledMetric, MetricKind, MetricSignature
from simsimd import pointer_to_sqeuclidean, pointer_to_cosine, pointer_to_inner

metric = CompiledMetric(
    pointer=pointer_to_cosine("f16"),
    kind=MetricKind.Cos,
    signature=MetricSignature.ArrayArraySize,
)

index = Index(256, metric=metric)

在 Rust 中使用 SimSIMD

要安装,请将以下内容添加到您的 Cargo.toml

[dependencies]
simsimd = "..."

在使用 SimSIMD 库之前,请确保您已将必要的特性和类型导入到 Rust 源文件中。该库为不同的距离/相似度类型提供了几个特性 - SpatialSimilarityBinarySimilarityProbabilitySimilarity

空间相似度:余弦和欧几里得距离

use simsimd::SpatialSimilarity;

fn main() {
    let vector_a: Vec<f32> = vec![1.0, 2.0, 3.0];
    let vector_b: Vec<f32> = vec![4.0, 5.0, 6.0];

    // Compute the cosine similarity between vector_a and vector_b
    let cosine_similarity = f32::cosine(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Cosine Similarity: {}", cosine_similarity);

    // Compute the squared Euclidean distance between vector_a and vector_b
    let sq_euclidean_distance = f32::sqeuclidean(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Squared Euclidean Distance: {}", sq_euclidean_distance);
}

空间相似度函数适用于 f64f32f16i8 类型。

点积:内积和复数内积

use simsimd::SpatialSimilarity;
use simsimd::ComplexProducts;

fn main() {
    let vector_a: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0];
    let vector_b: Vec<f32> = vec![5.0, 6.0, 7.0, 8.0];

    // Compute the inner product between vector_a and vector_b
    let inner_product = SpatialSimilarity::dot(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Inner Product: {}", inner_product);

    // Compute the complex inner product between complex_vector_a and complex_vector_b
    let complex_inner_product = ComplexProducts::dot(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    let complex_conjugate_inner_product = ComplexProducts::vdot(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Complex Inner Product: {:?}", complex_inner_product); // -18, 69
    println!("Complex C. Inner Product: {:?}", complex_conjugate_inner_product); // 70, -8
}

复数内积适用于 f64f32f16 类型。

概率分布:Jensen-Shannon 和 Kullback-Leibler 散度

use simsimd::SpatialSimilarity;

fn main() {
    let vector_a: Vec<f32> = vec![1.0, 2.0, 3.0];
    let vector_b: Vec<f32> = vec![4.0, 5.0, 6.0];

    let cosine_similarity = f32::jensenshannon(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Cosine Similarity: {}", cosine_similarity);

    let sq_euclidean_distance = f32::kullbackleibler(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Squared Euclidean Distance: {}", sq_euclidean_distance);
}

概率相似度函数适用于 f64f32f16 类型。

二进制相似度:汉明和贾卡德距离

类似于空间距离,可以计算无符号整数切片之间的位级距离函数

use simsimd::BinarySimilarity;

fn main() {
    let vector_a = &[0b11110000, 0b00001111, 0b10101010];
    let vector_b = &[0b11110000, 0b00001111, 0b01010101];

    // Compute the Hamming distance between vector_a and vector_b
    let hamming_distance = u8::hamming(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Hamming Distance: {}", hamming_distance);

    // Compute the Jaccard distance between vector_a and vector_b
    let jaccard_distance = u8::jaccard(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Jaccard Distance: {}", jaccard_distance);
}

二进制相似度函数仅适用于 u8 类型。

半精度浮点数

Rust 没有原生支持半精度浮点数,但 SimSIMD 提供了 f16 类型。它没有功能 - 它是 transparent 的包装器,围绕 u16,并可以与 half 或任何其他半精度库一起使用。

use simsimd::SpatialSimilarity;
use simsimd::f16 as SimF16;
use half::f16 as HalfF16;

fn main() {
    let vector_a: Vec<HalfF16> = ...
    let vector_b: Vec<HalfF16> = ...

    let buffer_a: &[SimF16] = unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const SimF16, a_half.len()) };
    let buffer_b: &[SimF16] = unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const SimF16, b_half.len()) };

    // Compute the cosine similarity between vector_a and vector_b
    let cosine_similarity = SimF16::cosine(&vector_a, &vector_b)
        .expect("Vectors must be of the same length");

    println!("Cosine Similarity: {}", cosine_similarity);
}

半精度 Brain-Float 数

"brain-float-16" 是一种流行的机器学习格式。它在硬件中得到广泛支持,非常适合机器使用,但软件支持仍然落后。与 NumPy 不同,您已经在 SimSIMD 中可以使用 bf16 数据类型。幸运的是,要将 f32 转换为 bf16,您只需要删除最后 16 位

import numpy as np
import simsimd as simd

a = np.random.randn(ndim).astype(np.float32)
b = np.random.randn(ndim).astype(np.float32)

# NumPy doesn't natively support brain-float, so we need a trick!
# Luckily, it's very easy to reduce the representation accuracy
# by simply masking the low 16-bits of our 32-bit single-precision
# numbers. We can also add `0x8000` to round the numbers.
a_f32rounded = ((a.view(np.uint32) + 0x8000) & 0xFFFF0000).view(np.float32)
b_f32rounded = ((b.view(np.uint32) + 0x8000) & 0xFFFF0000).view(np.float32)

# To represent them as brain-floats, we need to drop the second half
a_bf16 = np.right_shift(a_f32rounded.view(np.uint32), 16).astype(np.uint16)
b_bf16 = np.right_shift(b_f32rounded.view(np.uint32), 16).astype(np.uint16)

# Now we can compare the results
expected = np.inner(a_f32rounded, b_f32rounded)
result = simd.inner(a_bf16, b_bf16, "bf16")

动态分派

SimSIMD 提供了一种动态分派机制,以选择当前 CPU 的最先进的微内核。您可以查询支持的后端,并使用 SimSIMD::capabilities 函数来选择最佳选项。

println!("uses neon: {}", capabilities::uses_neon());
println!("uses sve: {}", capabilities::uses_sve());
println!("uses haswell: {}", capabilities::uses_haswell());
println!("uses skylake: {}", capabilities::uses_skylake());
println!("uses ice: {}", capabilities::uses_ice());
println!("uses genoa: {}", capabilities::uses_genoa());
println!("uses sapphire: {}", capabilities::uses_sapphire());

在 JavaScript 中使用 SimSIMD

根据您的环境选择以下选项之一进行安装

  • npm install--保存 simsimd
  • yarn add simsimd
  • pnpm add simsimd
  • bun install simsimd

该软件包附带预构建的二进制文件,但如果您的平台不受支持,您可以通过 npm run build 从源代码构建软件包。除非您使用带有 --ignore-scripts 标志安装软件包或使用 Bun,否则此操作将自动执行。安装后,您将能够调用各种 TypedArray 变体的 SimSIMD 函数

const { sqeuclidean, cosine, inner, hamming, jaccard } = require('simsimd');

const vectorA = new Float32Array([1.0, 2.0, 3.0]);
const vectorB = new Float32Array([4.0, 5.0, 6.0]);

const distance = sqeuclidean(vectorA, vectorB);
console.log('Squared Euclidean Distance:', distance);

还支持其他数字类型和精度级别。对于双精度浮点数,请使用 Float64Array

const vectorA = new Float64Array([1.0, 2.0, 3.0]);
const vectorB = new Float64Array([4.0, 5.0, 6.0]);
const distance = cosine(vectorA, vectorB);

在进行机器学习和高维向量搜索时,您可能希望将它们量化为 8 位整数。您可能需要将值从 $[-1, 1]$ 范围投影到 $[-127, 127]$ 范围,然后将它们转换为 Int8Array

const quantizedVectorA = new Int8Array(vectorA.map(v => (v * 127)));
const quantizedVectorB = new Int8Array(vectorB.map(v => (v * 127)));
const distance = cosine(quantizedVectorA, quantizedVectorB);

更极端的量化案例是使用二进制向量。您可以映射所有正值为 1,所有负值和零为 0,将八个值打包到一个字节中。之后,可以计算汉明和贾卡德距离。

const { toBinary, hamming } = require('simsimd');

const binaryVectorA = toBinary(vectorA);
const binaryVectorB = toBinary(vectorB);
const distance = hamming(binaryVectorA, binaryVectorB);

在 C 中使用 SimSIMD

为了在基于 CMake 的项目中集成,请将以下段添加到您的 CMakeLists.txt

FetchContent_Declare(
    simsimd
    GIT_REPOSITORY https://github.com/ashvardanian/simsimd.git
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(simsimd)

之后,您可以在 C 代码中以多种方式使用 SimSIMD 库。最简单的方法是包含头文件,编译器将自动选择 SimSIMD 将使用的最新 CPU 扩展。

#include <simsimd/simsimd.h>

int main() {
    simsimd_f32_t vector_a[1536];
    simsimd_f32_t vector_b[1536];
    simsimd_metric_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
    simsimd_distance_t distance;
    distance_function(vector_a, vector_b, 1536, &distance);
    return 0;
}

动态分派

为了避免硬编码后端,您可以依靠 c/lib.c 将所有可能的后端打包到一个二进制文件中,并在运行时选择最新的 CPU 功能。C 库的这个功能称为动态分派,并在 Python、JavaScript 和 Rust 绑定中广泛使用。要测试在运行时机器上可用的 CPU 功能,请使用以下 API

int uses_neon = simsimd_uses_neon();
int uses_sve = simsimd_uses_sve();
int uses_haswell = simsimd_uses_haswell();
int uses_skylake = simsimd_uses_skylake();
int uses_ice = simsimd_uses_ice();
int uses_genoa = simsimd_uses_genoa();
int uses_sapphire = simsimd_uses_sapphire();

simsimd_capability_t capabilities = simsimd_capabilities();

为了区分运行时和编译时分发,定义以下宏:

#define SIMSIMD_DYNAMIC_DISPATCH 1 // or 0

空间距离:余弦距离和欧几里得距离

#include <simsimd/simsimd.h>

int main() {
    simsimd_f64_t f64s[1536];
    simsimd_f32_t f32s[1536];
    simsimd_f16_t f16s[1536];
    simsimd_i8_t i8[1536];
    simsimd_distance_t distance;

    // Cosine distance between two vectors
    simsimd_cos_i8(i8s, i8s, 1536, &distance);
    simsimd_cos_f16(f16s, f16s, 1536, &distance);
    simsimd_cos_f32(f32s, f32s, 1536, &distance);
    simsimd_cos_f64(f64s, f64s, 1536, &distance);
    
    // Euclidean distance between two vectors
    simsimd_l2sq_i8(i8s, i8s, 1536, &distance);
    simsimd_l2sq_f16(f16s, f16s, 1536, &distance);
    simsimd_l2sq_f32(f32s, f32s, 1536, &distance);
    simsimd_l2sq_f64(f64s, f64s, 1536, &distance);

    return 0;
}

点积:内积和复数内积

#include <simsimd/simsimd.h>

int main() {
    simsimd_f64_t f64s[1536];
    simsimd_f32_t f32s[1536];
    simsimd_f16_t f16s[1536];
    simsimd_distance_t distance;

    // Inner product between two vectors
    simsimd_dot_f16(f16s, f16s, 1536, &distance);
    simsimd_dot_f32(f32s, f32s, 1536, &distance);
    simsimd_dot_f64(f64s, f64s, 1536, &distance);

    // Complex inner product between two vectors
    simsimd_dot_f16c(f16s, f16s, 1536, &distance);
    simsimd_dot_f32c(f32s, f32s, 1536, &distance);
    simsimd_dot_f64c(f64s, f64s, 1536, &distance);

    // Complex conjugate inner product between two vectors
    simsimd_vdot_f16c(f16s, f16s, 1536, &distance);
    simsimd_vdot_f32c(f32s, f32s, 1536, &distance);
    simsimd_vdot_f64c(f64s, f64s, 1536, &distance);

    return 0;
}

二进制距离:汉明距离和贾卡德距离

#include <simsimd/simsimd.h>

int main() {
    simsimd_b8_t b8s[1536 / 8]; // 8 bits per word
    simsimd_distance_t distance;

    // Hamming distance between two vectors
    simsimd_hamming_b8(b8s, b8s, 1536 / 8, &distance);

    // Jaccard distance between two vectors
    simsimd_jaccard_b8(b8s, b8s, 1536 / 8, &distance);

    return 0;
}

概率分布:Jensen-Shannon 和 Kullback-Leibler 散度

#include <simsimd/simsimd.h>

int main() {
    simsimd_f64_t f64s[1536];
    simsimd_f32_t f32s[1536];
    simsimd_f16_t f16s[1536];
    simsimd_distance_t distance;

    // Jensen-Shannon divergence between two vectors
    simsimd_js_f16(f16s, f16s, 1536, &distance);
    simsimd_js_f32(f32s, f32s, 1536, &distance);
    simsimd_js_f64(f64s, f64s, 1536, &distance);

    // Kullback-Leibler divergence between two vectors
    simsimd_kl_f16(f16s, f16s, 1536, &distance);
    simsimd_kl_f32(f32s, f32s, 1536, &distance);
    simsimd_kl_f64(f64s, f64s, 1536, &distance);

    return 0;
}

半精度浮点数

如果您想使用SimSIMD的_Float16功能,请确保您的开发环境兼容C 11。对于其他SimSIMD功能,C 99兼容性就足够了。要在导入之前显式禁用半精度支持,请定义以下宏:

#define SIMSIMD_NATIVE_F16 0 // or 1
#define SIMSIMD_NATIVE_BF16 0 // or 1
#include <simsimd/simsimd.h>

特定目标的后端

SimSIMD对所有后端都公开了所有内核,您可以选择最适合当前CPU的最先进内核,而不依赖内置的分发机制。所有函数名遵循相同的模式:simsimd_{function}_{type}_{backend}

  • 后端可以是serialhaswellskylakeicesapphireneonsve
  • 类型可以是f64f32f16f64cf32cf16ci8b8
  • 函数可以是dotvdotcosl2sqhammingjaccardkljs

为了避免硬编码后端,您可以使用simsimd_metric_punned_t来punning函数指针,以及使用simsimd_capabilities函数在运行时获取可用的后端。

simsimd_dot_f64_sve
simsimd_cos_f64_sve
simsimd_l2sq_f64_sve
simsimd_dot_f64_skylake
simsimd_cos_f64_skylake
simsimd_l2sq_f64_skylake
simsimd_dot_f64_serial
simsimd_cos_f64_serial
simsimd_l2sq_f64_serial
simsimd_js_f64_serial
simsimd_kl_f64_serial
simsimd_dot_f32_sve
simsimd_cos_f32_sve
simsimd_l2sq_f32_sve
simsimd_dot_f32_neon
simsimd_cos_f32_neon
simsimd_l2sq_f32_neon
simsimd_js_f32_neon
simsimd_kl_f32_neon
simsimd_dot_f32_skylake
simsimd_cos_f32_skylake
simsimd_l2sq_f32_skylake
simsimd_js_f32_skylake
simsimd_kl_f32_skylake
simsimd_dot_f32_serial
simsimd_cos_f32_serial
simsimd_l2sq_f32_serial
simsimd_js_f32_serial
simsimd_kl_f32_serial
simsimd_dot_f16_sve
simsimd_cos_f16_sve
simsimd_l2sq_f16_sve
simsimd_dot_f16_neon
simsimd_cos_f16_neon
simsimd_l2sq_f16_neon
simsimd_js_f16_neon
simsimd_kl_f16_neon
simsimd_dot_f16_sapphire
simsimd_cos_f16_sapphire
simsimd_l2sq_f16_sapphire
simsimd_js_f16_sapphire
simsimd_kl_f16_sapphire
simsimd_dot_f16_haswell
simsimd_cos_f16_haswell
simsimd_l2sq_f16_haswell
simsimd_js_f16_haswell
simsimd_kl_f16_haswell
simsimd_dot_f16_serial
simsimd_cos_f16_serial
simsimd_l2sq_f16_serial
simsimd_js_f16_serial
simsimd_kl_f16_serial
simsimd_cos_i8_neon
simsimd_cos_i8_neon
simsimd_l2sq_i8_neon
simsimd_cos_i8_ice
simsimd_cos_i8_ice
simsimd_l2sq_i8_ice
simsimd_cos_i8_haswell
simsimd_cos_i8_haswell
simsimd_l2sq_i8_haswell
simsimd_cos_i8_serial
simsimd_cos_i8_serial
simsimd_l2sq_i8_serial
simsimd_hamming_b8_sve
simsimd_jaccard_b8_sve
simsimd_hamming_b8_neon
simsimd_jaccard_b8_neon
simsimd_hamming_b8_ice
simsimd_jaccard_b8_ice
simsimd_hamming_b8_haswell
simsimd_jaccard_b8_haswell
simsimd_hamming_b8_serial
simsimd_jaccard_b8_serial
simsimd_dot_f32c_sve
simsimd_vdot_f32c_sve
simsimd_dot_f32c_neon
simsimd_vdot_f32c_neon
simsimd_dot_f32c_haswell
simsimd_vdot_f32c_haswell
simsimd_dot_f32c_skylake
simsimd_vdot_f32c_skylake
simsimd_dot_f32c_serial
simsimd_vdot_f32c_serial
simsimd_dot_f64c_sve
simsimd_vdot_f64c_sve
simsimd_dot_f64c_skylake
simsimd_vdot_f64c_skylake
simsimd_dot_f64c_serial
simsimd_vdot_f64c_serial
simsimd_dot_f16c_sve
simsimd_vdot_f16c_sve
simsimd_dot_f16c_neon
simsimd_vdot_f16c_neon
simsimd_dot_f16c_haswell
simsimd_vdot_f16c_haswell
simsimd_dot_f16c_sapphire
simsimd_vdot_f16c_sapphire
simsimd_dot_f16c_serial
simsimd_vdot_f16c_serial

无运行时依赖

~185KB