usearch 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/prerelease.yml +18 -3
- package/CMakeLists.txt +15 -0
- package/Cargo.toml +1 -1
- package/README.md +2 -2
- package/conanfile.py +1 -1
- package/include/usearch/index_plugins.hpp +20 -4
- package/package.json +1 -1
- package/setup.py +3 -4
- package/simsimd/.github/workflows/prerelease.yml +44 -9
- package/simsimd/.github/workflows/release.yml +7 -9
- package/simsimd/.vscode/settings.json +5 -1
- package/simsimd/CMakeLists.txt +5 -2
- package/simsimd/README.md +69 -48
- package/simsimd/bench.cxx +5 -6
- package/simsimd/include/simsimd/simsimd.h +195 -139
- package/simsimd/include/simsimd/simsimd_bio.h +54 -0
- package/simsimd/include/simsimd/simsimd_chem.h +65 -24
- package/simsimd/include/simsimd/simsimd_text.h +92 -0
- package/simsimd/package.json +1 -1
- package/simsimd/python/{python.c → lib.c} +28 -15
- package/simsimd/python/test.py +35 -20
- package/simsimd/setup.py +2 -6
- package/wasmer.toml +1 -1
- /package/{cluster.ipynb → python/scripts/cluster.ipynb} +0 -0
|
@@ -74,8 +74,9 @@ jobs:
|
|
|
74
74
|
name: Test Python
|
|
75
75
|
runs-on: ${{ matrix.os }}
|
|
76
76
|
strategy:
|
|
77
|
+
fail-fast: false
|
|
77
78
|
matrix:
|
|
78
|
-
os: [ubuntu-
|
|
79
|
+
os: [ubuntu-22.04, macOS-11, windows-2022]
|
|
79
80
|
python-version: ["3.11"]
|
|
80
81
|
|
|
81
82
|
steps:
|
|
@@ -89,8 +90,16 @@ jobs:
|
|
|
89
90
|
run: |
|
|
90
91
|
python -m pip install --upgrade pip
|
|
91
92
|
pip install pytest numpy
|
|
93
|
+
- name: Build locally on Ubuntu
|
|
94
|
+
run: |
|
|
95
|
+
export CC=/usr/bin/gcc-12
|
|
96
|
+
export CXX=/usr/bin/g++-12
|
|
97
|
+
export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:$LD_LIBRARY_PATH
|
|
98
|
+
python -m pip install .
|
|
99
|
+
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
|
92
100
|
- name: Build locally
|
|
93
101
|
run: python -m pip install .
|
|
102
|
+
if: ${{ matrix.os != 'ubuntu-22.04' }}
|
|
94
103
|
- name: Test with PyTest
|
|
95
104
|
run: pytest python/scripts/
|
|
96
105
|
|
|
@@ -99,8 +108,9 @@ jobs:
|
|
|
99
108
|
name: Test Python 3.7
|
|
100
109
|
runs-on: ${{ matrix.os }}
|
|
101
110
|
strategy:
|
|
111
|
+
fail-fast: false
|
|
102
112
|
matrix:
|
|
103
|
-
os: [ubuntu-
|
|
113
|
+
os: [ubuntu-22.04]
|
|
104
114
|
python-version: ["3.7"]
|
|
105
115
|
|
|
106
116
|
steps:
|
|
@@ -118,7 +128,12 @@ jobs:
|
|
|
118
128
|
pip install pytest numpy
|
|
119
129
|
|
|
120
130
|
- name: Build locally
|
|
121
|
-
run:
|
|
131
|
+
run: |
|
|
132
|
+
export CC=/usr/bin/gcc-12
|
|
133
|
+
export CXX=/usr/bin/g++-12
|
|
134
|
+
export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:$LD_LIBRARY_PATH
|
|
135
|
+
python -m pip install .
|
|
136
|
+
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
|
122
137
|
|
|
123
138
|
- name: Test with PyTest
|
|
124
139
|
run: pytest python/scripts/
|
package/CMakeLists.txt
CHANGED
|
@@ -49,11 +49,26 @@ else()
|
|
|
49
49
|
target_compile_features(${USEARCH_TARGET_NAME} INTERFACE cxx_std_11)
|
|
50
50
|
endif()
|
|
51
51
|
|
|
52
|
+
# Core compilation settings affecting "index.hpp"
|
|
52
53
|
target_compile_definitions(
|
|
53
54
|
${USEARCH_TARGET_NAME}
|
|
54
55
|
INTERFACE
|
|
55
56
|
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_OPENMP=0>
|
|
56
57
|
)
|
|
58
|
+
|
|
59
|
+
# Supplementary compilation settings affecting "index_plugins.hpp"
|
|
60
|
+
target_compile_definitions(
|
|
61
|
+
${USEARCH_TARGET_NAME}
|
|
62
|
+
INTERFACE
|
|
63
|
+
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_NATIVE_F16=0>
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
target_compile_definitions(
|
|
67
|
+
${USEARCH_TARGET_NAME}
|
|
68
|
+
INTERFACE
|
|
69
|
+
$<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_SIMSIMD=0>
|
|
70
|
+
)
|
|
71
|
+
|
|
57
72
|
target_include_directories(
|
|
58
73
|
${USEARCH_TARGET_NAME}
|
|
59
74
|
${USEARCH_SYSTEM_INCLUDE} INTERFACE
|
package/Cargo.toml
CHANGED
package/README.md
CHANGED
|
@@ -39,8 +39,8 @@ Linux • MacOS • Windows • iOS • Docker • WebAssembly
|
|
|
39
39
|
<a href="https://pypi.org/project/usearch/"> <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/usearch?label=pypi%20downloads"> </a>
|
|
40
40
|
<a href="https://www.npmjs.com/package/usearch"> <img alt="npm" src="https://img.shields.io/npm/dy/usearch?label=npm%20dowloads"> </a>
|
|
41
41
|
<a href="https://crates.io/crates/usearch"> <img alt="Crates.io" src="https://img.shields.io/crates/d/usearch?label=crate%20downloads"> </a>
|
|
42
|
-
<a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="Nuget" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?
|
|
43
|
-
<a href="https://hub.docker.com/r/unum/usearch"> <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/unum/usearch?
|
|
42
|
+
<a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="Nuget" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?label=NuGet"> </a>
|
|
43
|
+
<a href="https://hub.docker.com/r/unum/usearch"> <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/unum/usearch?label=Docker"> </a>
|
|
44
44
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/unum-cloud/usearch">
|
|
45
45
|
</div>
|
|
46
46
|
|
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '2.1.
|
|
7
|
+
version = '2.1.3'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
#endif
|
|
42
42
|
|
|
43
43
|
#if USEARCH_USE_SIMSIMD
|
|
44
|
+
#if __linux__
|
|
45
|
+
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
46
|
+
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
47
|
+
#define SIMSIMD_TARGET_ARM_SVE 1
|
|
48
|
+
#define SIMSIMD_TARGET_X86_AVX512 1
|
|
49
|
+
#endif
|
|
44
50
|
#include <simsimd/simsimd.h>
|
|
45
51
|
#endif
|
|
46
52
|
|
|
@@ -600,9 +606,7 @@ class aligned_allocator_gt {
|
|
|
600
606
|
using size_type = std::size_t;
|
|
601
607
|
using pointer = element_at*;
|
|
602
608
|
using const_pointer = element_at const*;
|
|
603
|
-
template <typename other_element_at> struct rebind {
|
|
604
|
-
using other = aligned_allocator_gt<other_element_at>;
|
|
605
|
-
};
|
|
609
|
+
template <typename other_element_at> struct rebind { using other = aligned_allocator_gt<other_element_at>; };
|
|
606
610
|
|
|
607
611
|
constexpr std::size_t alignment() const { return alignment_ak; }
|
|
608
612
|
|
|
@@ -1384,25 +1388,37 @@ class metric_punned_t {
|
|
|
1384
1388
|
// clang-format off
|
|
1385
1389
|
static metric_punned_t ip_metric_f32_(std::size_t bytes_per_vector) {
|
|
1386
1390
|
#if USEARCH_USE_SIMSIMD
|
|
1387
|
-
if
|
|
1391
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
1388
1392
|
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 16 == 0) return {pun_stl_<f32_t>([=](f32_t const* a, f32_t const* b) { return simsimd_dot_f32x4_neon(a, b, bytes_per_vector / 4); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f32_k, isa_kind_t::neon_k};
|
|
1393
|
+
#endif
|
|
1394
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
1395
|
+
if (hardware_supports(isa_kind_t::sve_k)) return {pun_stl_<f32_t>([=](f32_t const* a, f32_t const* b) { return simsimd_dot_f32_sve(a, b, bytes_per_vector / 4); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f32_k, isa_kind_t::sve_k};
|
|
1396
|
+
#endif
|
|
1397
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
1389
1398
|
if (hardware_supports(isa_kind_t::avx2_k) && bytes_per_vector % 16 == 0) return {pun_stl_<f32_t>([=](f32_t const* a, f32_t const* b) { return simsimd_dot_f32x4_avx2(a, b, bytes_per_vector / 4); }), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f32_k, isa_kind_t::avx2_k};
|
|
1390
1399
|
#endif
|
|
1400
|
+
#endif
|
|
1391
1401
|
return {to_stl_<metric_ip_gt<f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::ip_k, scalar_kind_t::f32_k, isa_kind_t::auto_k};
|
|
1392
1402
|
}
|
|
1393
1403
|
|
|
1394
1404
|
static metric_punned_t cos_metric_f16_(std::size_t bytes_per_vector) {
|
|
1395
1405
|
#if USEARCH_USE_SIMSIMD
|
|
1406
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
1396
1407
|
if (hardware_supports(isa_kind_t::avx512_k) && bytes_per_vector % 32 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16x16_avx512(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::avx512_k};
|
|
1408
|
+
#endif
|
|
1409
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
1397
1410
|
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 8 == 0) return {pun_stl_<simsimd_f16_t>([=](simsimd_f16_t const* a, simsimd_f16_t const* b) { return simsimd_cos_f16x4_neon(a, b, bytes_per_vector / 2); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::neon_k};
|
|
1398
1411
|
#endif
|
|
1412
|
+
#endif
|
|
1399
1413
|
return {to_stl_<metric_cos_gt<f16_t, f32_t>>(bytes_per_vector), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::f16_k, isa_kind_t::auto_k};
|
|
1400
1414
|
}
|
|
1401
1415
|
|
|
1402
1416
|
static metric_punned_t cos_metric_i8_(std::size_t bytes_per_vector) {
|
|
1403
1417
|
#if USEARCH_USE_SIMSIMD
|
|
1418
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
1404
1419
|
if (hardware_supports(isa_kind_t::neon_k) && bytes_per_vector % 16 == 0) return {pun_stl_<int8_t>([=](int8_t const* a, int8_t const* b) { return simsimd_cos_i8x16_neon(a, b, bytes_per_vector); }), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::i8_k, isa_kind_t::neon_k};
|
|
1405
1420
|
#endif
|
|
1421
|
+
#endif
|
|
1406
1422
|
return {to_stl_<cos_i8_t>(bytes_per_vector), bytes_per_vector, metric_kind_t::cos_k, scalar_kind_t::i8_k, isa_kind_t::auto_k};
|
|
1407
1423
|
}
|
|
1408
1424
|
|
package/package.json
CHANGED
package/setup.py
CHANGED
|
@@ -7,10 +7,7 @@ from pybind11.setup_helpers import Pybind11Extension
|
|
|
7
7
|
|
|
8
8
|
compile_args = []
|
|
9
9
|
link_args = []
|
|
10
|
-
macros_args = [
|
|
11
|
-
("USEARCH_USE_NATIVE_F16", "0"),
|
|
12
|
-
("USEARCH_USE_SIMSIMD", "0"),
|
|
13
|
-
]
|
|
10
|
+
macros_args = []
|
|
14
11
|
|
|
15
12
|
if sys.platform == "linux":
|
|
16
13
|
compile_args.append("-std=c++17")
|
|
@@ -18,6 +15,8 @@ if sys.platform == "linux":
|
|
|
18
15
|
compile_args.append("-g") # Simplify debugging
|
|
19
16
|
compile_args.append("-Wno-unknown-pragmas")
|
|
20
17
|
|
|
18
|
+
macros_args.append(("USEARCH_USE_NATIVE_F16", "0"))
|
|
19
|
+
macros_args.append(("USEARCH_USE_SIMSIMD", "1"))
|
|
21
20
|
macros_args.append(("USEARCH_USE_OPENMP", "1"))
|
|
22
21
|
compile_args.append("-fopenmp")
|
|
23
22
|
link_args.append("-lgomp")
|
|
@@ -21,8 +21,9 @@ jobs:
|
|
|
21
21
|
name: Test Python
|
|
22
22
|
runs-on: ${{ matrix.os }}
|
|
23
23
|
strategy:
|
|
24
|
+
fail-fast: false
|
|
24
25
|
matrix:
|
|
25
|
-
os: [ubuntu-
|
|
26
|
+
os: [ubuntu-22.04] # macOS-11, windows-2022
|
|
26
27
|
python-version: ["3.11"]
|
|
27
28
|
|
|
28
29
|
steps:
|
|
@@ -32,22 +33,54 @@ jobs:
|
|
|
32
33
|
uses: actions/setup-python@v4
|
|
33
34
|
with:
|
|
34
35
|
python-version: ${{ matrix.python-version }}
|
|
36
|
+
|
|
37
|
+
- name: Set up Clang
|
|
38
|
+
run: brew install llvm
|
|
39
|
+
if: ${{ matrix.os == 'macOS-11' }}
|
|
40
|
+
|
|
41
|
+
- name: Set up MinGW
|
|
42
|
+
uses: egor-tensin/setup-mingw@v2
|
|
43
|
+
with:
|
|
44
|
+
platform: x64
|
|
45
|
+
if: ${{ matrix.os == 'windows-2022' }}
|
|
46
|
+
|
|
35
47
|
- name: Install dependencies
|
|
36
48
|
run: |
|
|
37
49
|
python -m pip install --no-cache-dir --upgrade pip
|
|
38
50
|
pip install --no-cache-dir pytest
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
|
|
52
|
+
- name: Build locally on Ubuntu
|
|
53
|
+
run: |
|
|
54
|
+
export CC=/usr/bin/gcc-12
|
|
55
|
+
export CXX=/usr/bin/g++-12
|
|
56
|
+
export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:$LD_LIBRARY_PATH
|
|
57
|
+
python -m pip install .
|
|
58
|
+
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
|
59
|
+
|
|
60
|
+
- name: Build locally on MacOS
|
|
61
|
+
run: |
|
|
62
|
+
export LDFLAGS="-L/usr/local/opt/llvm/lib"
|
|
63
|
+
export CPPFLAGS="-I/usr/local/opt/llvm/include"
|
|
64
|
+
export CC=/usr/local/opt/llvm/bin/clang
|
|
65
|
+
export CXX=/usr/local/opt/llvm/bin/clang++
|
|
66
|
+
python -m pip install .
|
|
67
|
+
if: ${{ matrix.os == 'macOS-11' }}
|
|
68
|
+
|
|
69
|
+
- name: Build locally on Windows
|
|
70
|
+
run: |
|
|
71
|
+
python -m pip install .
|
|
72
|
+
if: ${{ matrix.os == 'windows-2022' }}
|
|
73
|
+
|
|
41
74
|
- name: Test with PyTest
|
|
42
75
|
run: pytest python/test.py
|
|
43
|
-
|
|
76
|
+
|
|
44
77
|
|
|
45
78
|
test_python_37:
|
|
46
79
|
name: Test Python 3.7
|
|
47
80
|
runs-on: ${{ matrix.os }}
|
|
48
81
|
strategy:
|
|
49
82
|
matrix:
|
|
50
|
-
os: [ubuntu-
|
|
83
|
+
os: [ubuntu-22.04]
|
|
51
84
|
python-version: ["3.7"]
|
|
52
85
|
|
|
53
86
|
steps:
|
|
@@ -65,9 +98,11 @@ jobs:
|
|
|
65
98
|
pip install --no-cache-dir pytest
|
|
66
99
|
|
|
67
100
|
- name: Build locally
|
|
68
|
-
run:
|
|
69
|
-
|
|
101
|
+
run: |
|
|
102
|
+
export CC=/usr/bin/gcc-12
|
|
103
|
+
export CXX=/usr/bin/g++-12
|
|
104
|
+
export LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/:$LD_LIBRARY_PATH
|
|
105
|
+
python -m pip install .
|
|
106
|
+
|
|
70
107
|
- name: Test with PyTest
|
|
71
108
|
run: pytest python/test.py
|
|
72
|
-
|
|
73
|
-
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
rebase:
|
|
32
|
-
name: Rebase
|
|
32
|
+
name: Rebase Dev. Branch
|
|
33
33
|
needs: versioning
|
|
34
34
|
runs-on: ubuntu-latest
|
|
35
35
|
steps:
|
|
@@ -57,7 +57,7 @@ jobs:
|
|
|
57
57
|
needs: versioning
|
|
58
58
|
strategy:
|
|
59
59
|
matrix:
|
|
60
|
-
os: [ubuntu-20.04
|
|
60
|
+
os: [ubuntu-20.04] # macOS-11, windows-2022
|
|
61
61
|
|
|
62
62
|
steps:
|
|
63
63
|
- uses: actions/checkout@v3
|
|
@@ -66,13 +66,11 @@ jobs:
|
|
|
66
66
|
- uses: actions/setup-python@v3
|
|
67
67
|
|
|
68
68
|
- name: Setup Docker
|
|
69
|
-
if: matrix.os
|
|
70
|
-
uses:
|
|
71
|
-
|
|
72
|
-
version: 23.0.1
|
|
73
|
-
|
|
69
|
+
if: matrix.os == 'ubuntu-20.04'
|
|
70
|
+
uses: docker-practice/actions-setup-docker@master
|
|
71
|
+
|
|
74
72
|
- name: Setup QEMU
|
|
75
|
-
if: matrix.os
|
|
73
|
+
if: matrix.os == 'ubuntu-20.04'
|
|
76
74
|
uses: docker/setup-qemu-action@v2.1.0
|
|
77
75
|
|
|
78
76
|
- name: Install CIBuildWheel
|
|
@@ -92,7 +90,7 @@ jobs:
|
|
|
92
90
|
runs-on: ubuntu-20.04
|
|
93
91
|
environment:
|
|
94
92
|
name: pypi
|
|
95
|
-
url: https://pypi.org/p/
|
|
93
|
+
url: https://pypi.org/p/simsimd
|
|
96
94
|
permissions:
|
|
97
95
|
id-token: write
|
|
98
96
|
|
|
@@ -85,13 +85,17 @@
|
|
|
85
85
|
"variant": "cpp",
|
|
86
86
|
"__nullptr": "cpp",
|
|
87
87
|
"unordered_set": "cpp",
|
|
88
|
-
"span": "cpp"
|
|
88
|
+
"span": "cpp",
|
|
89
|
+
"arm_neon.h": "c"
|
|
89
90
|
},
|
|
90
91
|
"cSpell.words": [
|
|
91
92
|
"dtype",
|
|
92
93
|
"dtypes",
|
|
93
94
|
"kann",
|
|
95
|
+
"maccs",
|
|
96
|
+
"simd",
|
|
94
97
|
"simsimd",
|
|
98
|
+
"tanimoto",
|
|
95
99
|
"unsw"
|
|
96
100
|
]
|
|
97
101
|
}
|
package/simsimd/CMakeLists.txt
CHANGED
|
@@ -34,14 +34,17 @@ endif()
|
|
|
34
34
|
|
|
35
35
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fsanitize=address")
|
|
36
36
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
37
|
+
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fsanitize=address")
|
|
38
|
+
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
37
39
|
|
|
38
40
|
# List of all possible compiler IDs:
|
|
39
41
|
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
|
|
40
42
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
41
43
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
42
44
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
|
43
|
-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
|
44
|
-
set(
|
|
45
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -fmax-errors=1")
|
|
46
|
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
|
|
47
|
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -fmax-errors=1")
|
|
45
48
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
|
|
46
49
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda")
|
|
47
50
|
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode arch=compute_86,code=sm_86")
|
package/simsimd/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# SimSIMD
|
|
1
|
+
# SimSIMD 📏
|
|
2
2
|
|
|
3
|
-
SIMD-accelerated similarity measures, metrics, distance functions for x86 and Arm.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
SIMD-accelerated similarity measures, metrics, and distance functions for x86 and Arm.
|
|
4
|
+
They are tuned for Machine Learning applications and mid-size vectors with 100-1024 dimensions.
|
|
5
|
+
One can expect the following performance for Cosine (Angular) distance, the most common metric in AI.
|
|
6
6
|
|
|
7
7
|
| Method | Vectors | Any Length | Speed on 256b | Speed on 1024b |
|
|
8
8
|
| :----- | :------ | :--------- | ------------: | -------------: |
|
|
@@ -12,7 +12,7 @@ For Cosine (Angular) distance, the most common metric in AI, one can expect foll
|
|
|
12
12
|
| NEON | `f16` | ❌ | 16 GB/s | 18 GB/s |
|
|
13
13
|
|
|
14
14
|
> The benchmarks were done on Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances.
|
|
15
|
-
> We only use Arm NEON implementation with
|
|
15
|
+
> We only use Arm NEON implementation with vector lengths multiples of 128 bits, avoiding additional head or tail `for` loops for misaligned data.
|
|
16
16
|
> By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
|
|
17
17
|
> Serial versions imply auto-vectorization pragmas.
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ FetchContent_MakeAvailable(simsimd)
|
|
|
28
28
|
include_directories(${simsimd_SOURCE_DIR}/include)
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Want to use in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
31
|
+
Want to use it in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
32
32
|
|
|
33
33
|
```py
|
|
34
34
|
from usearch import Index, CompiledMetric, MetricKind, MetricSignature
|
|
@@ -45,60 +45,81 @@ index = Index(256, metric=metric)
|
|
|
45
45
|
|
|
46
46
|
## Available Metrics
|
|
47
47
|
|
|
48
|
-
In the C99 interface all
|
|
49
|
-
|
|
48
|
+
In the C99 interface, all functions are prepended with the `simsimd_` namespace prefix.
|
|
49
|
+
The signature defines the number of arguments:
|
|
50
50
|
|
|
51
51
|
- two pointers, and length,
|
|
52
52
|
- two pointers.
|
|
53
53
|
|
|
54
|
-
The latter is
|
|
55
|
-
Constraints define the limitations on the number of dimensions
|
|
56
|
-
|
|
57
|
-
| Name | Signature | ISA
|
|
58
|
-
| :---------------------- | :-------: |
|
|
59
|
-
| `dot_f32_sve` | ✳️✳️📏 |
|
|
60
|
-
| `dot_f32x4_neon` | ✳️✳️📏 | Arm NEON
|
|
61
|
-
| `cos_f32_sve` | ✳️✳️📏 |
|
|
62
|
-
| `cos_f16_sve` | ✳️✳️📏 |
|
|
63
|
-
| `cos_f16x4_neon` | ✳️✳️📏 | Arm NEON
|
|
64
|
-
| `cos_i8x16_neon` | ✳️✳️📏 | Arm NEON
|
|
65
|
-
| `cos_f32x4_neon` | ✳️✳️📏 | Arm NEON
|
|
66
|
-
| `cos_f16x16_avx512` | ✳️✳️📏 |
|
|
67
|
-
| `cos_f32x4_avx2` | ✳️✳️📏 | x86 AVX2
|
|
68
|
-
| `l2sq_f32_sve` | ✳️✳️📏 |
|
|
69
|
-
| `l2sq_f16_sve` | ✳️✳️📏 |
|
|
70
|
-
| `hamming_b1x8_sve` | ✳️✳️📏 |
|
|
71
|
-
| `hamming_b1x128_sve` | ✳️✳️📏 |
|
|
72
|
-
| `hamming_b1x128_avx512` | ✳️✳️📏 |
|
|
73
|
-
| `tanimoto_b1x8_naive` | ✳️✳️📏 |
|
|
74
|
-
| `tanimoto_maccs_naive` | ✳️✳️ |
|
|
75
|
-
| `tanimoto_maccs_neon` | ✳️✳️ | Arm NEON
|
|
76
|
-
| `tanimoto_maccs_sve` | ✳️✳️ |
|
|
77
|
-
| `tanimoto_maccs_avx512` | ✳️✳️ |
|
|
54
|
+
The latter is intended for cases where the number of dimensions is hard-coded.
|
|
55
|
+
Constraints define the limitations on the number of dimensions an argument vector can have.
|
|
56
|
+
|
|
57
|
+
| Name | Signature | ISA Extension | Constraints |
|
|
58
|
+
| :---------------------- | :-------: | :-----------: | :------------: |
|
|
59
|
+
| `dot_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
60
|
+
| `dot_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
61
|
+
| `cos_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
62
|
+
| `cos_f16_sve` | ✳️✳️📏 | Arm SVE | |
|
|
63
|
+
| `cos_f16x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
64
|
+
| `cos_i8x16_neon` | ✳️✳️📏 | Arm NEON | `d % 16 == 0` |
|
|
65
|
+
| `cos_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
66
|
+
| `cos_f16x16_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 16 == 0` |
|
|
67
|
+
| `cos_f32x4_avx2` | ✳️✳️📏 | x86 AVX2 | `d % 4 == 0` |
|
|
68
|
+
| `l2sq_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
69
|
+
| `l2sq_f16_sve` | ✳️✳️📏 | Arm SVE | |
|
|
70
|
+
| `hamming_b1x8_sve` | ✳️✳️📏 | Arm SVE | `d % 8 == 0` |
|
|
71
|
+
| `hamming_b1x128_sve` | ✳️✳️📏 | Arm SVE | `d % 128 == 0` |
|
|
72
|
+
| `hamming_b1x128_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 128 == 0` |
|
|
73
|
+
| `tanimoto_b1x8_naive` | ✳️✳️📏 | | `d % 8 == 0` |
|
|
74
|
+
| `tanimoto_maccs_naive` | ✳️✳️ | | `d == 166` |
|
|
75
|
+
| `tanimoto_maccs_neon` | ✳️✳️ | Arm NEON | `d == 166` |
|
|
76
|
+
| `tanimoto_maccs_sve` | ✳️✳️ | Arm SVE | `d == 166` |
|
|
77
|
+
| `tanimoto_maccs_avx512` | ✳️✳️ | x86 AVX-512 | `d == 166` |
|
|
78
78
|
|
|
79
79
|
## Benchmarks
|
|
80
80
|
|
|
81
81
|
The benchmarks are repeated for every function with a different number of cores involved.
|
|
82
|
-
Light-weight distance functions would be memory bound, implying that multi-core performance may be lower
|
|
82
|
+
Light-weight distance functions would be memory bound, implying that multi-core performance may be lower if the bus bandwidth cannot saturate all the cores.
|
|
83
83
|
Similarly, heavy-weight distance functions running on all cores may result in CPU frequency downclocking.
|
|
84
|
-
This is well illustrated by the single-core performance of `i9-13950HX`, equipped with DDR5 memory.
|
|
85
|
-
|
|
86
|
-
| Method | Threads |
|
|
87
|
-
| :--------------------- | ------: |
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `cos_f32_naive` | 1 | 15.3
|
|
91
|
-
| `cos_f32_naive` | 32 |
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
This is well illustrated by the single-core performance of the Intel `i9-13950HX`, equipped with DDR5 memory.
|
|
85
|
+
|
|
86
|
+
| Method | Threads | Vector Size | Speed |
|
|
87
|
+
| :--------------------- | ------: | ----------: | --------: |
|
|
88
|
+
| `dot_f32x4_avx2` | 1 | 1024 b | 96.2 GB/s |
|
|
89
|
+
| `dot_f32x4_avx2` | 32 | 1024 b | 23.6 GB/s |
|
|
90
|
+
| `cos_f32_naive` | 1 | 1024 b | 15.3 GB/s |
|
|
91
|
+
| `cos_f32_naive` | 32 | 1024 b | 4.5 GB/s |
|
|
92
|
+
| `cos_f32x4_avx2` | 1 | 1024 b | 56.3 GB/s |
|
|
93
|
+
| `cos_f32x4_avx2` | 32 | 1024 b | 13.9 GB/s |
|
|
94
|
+
| `tanimoto_maccs_naive` | 1 | 21 b | 2.8 GB/s |
|
|
95
|
+
| `tanimoto_maccs_naive` | 32 | 21 b | 1.2 GB/s |
|
|
96
|
+
|
|
97
|
+
Switching to the Intel Sapphire Rapids server platform, we can also evaluate some of the AVX-512 extensions, including `VPOPCNTDQ` and `F16`.
|
|
98
|
+
|
|
99
|
+
| Method | Threads | Vector Size | Speed |
|
|
100
|
+
| :---------------------- | ------: | ----------: | ---------: |
|
|
101
|
+
| `dot_f32x4_avx2` | 1 | 1024 b | 57.8 GB/s |
|
|
102
|
+
| `dot_f32x4_avx2` | 224 | 1024 b | 16.1 GB/s |
|
|
103
|
+
| `cos_f32_naive` | 1 | 1024 b | 10.7 GB/s |
|
|
104
|
+
| `cos_f32_naive` | 224 | 1024 b | 3.0 GB/s |
|
|
105
|
+
| `cos_f32x4_avx2` | 1 | 1024 b | 39.5 GB/s |
|
|
106
|
+
| `cos_f32x4_avx2` | 224 | 1024 b | 15.1 GB/s |
|
|
107
|
+
| `cos_f16x16_avx512` | 1 | 1024 b | 50.6 GB/s |
|
|
108
|
+
| `cos_f16x16_avx512` | 224 | 1024 b | 15.9 GB/s |
|
|
109
|
+
| `hamming_b1x128_avx512` | 1 | 1024 b | 790.3 GB/s |
|
|
110
|
+
| `hamming_b1x128_avx512` | 224 | 1024 b | 259.3 GB/s |
|
|
111
|
+
| `tanimoto_maccs_naive` | 1 | 21 b | 3.0 GB/s |
|
|
112
|
+
| `tanimoto_maccs_naive` | 224 | 21 b | 1.3 GB/s |
|
|
113
|
+
| `tanimoto_maccs_avx512` | 1 | 21 b | 13.1 GB/s |
|
|
114
|
+
| `tanimoto_maccs_avx512` | 224 | 21 b | 3.7 GB/s |
|
|
115
|
+
|
|
116
|
+
To replicate this on your hardware, please run the following on Linux:
|
|
98
117
|
|
|
99
118
|
```sh
|
|
100
119
|
git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
|
|
101
|
-
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1
|
|
120
|
+
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 \
|
|
121
|
+
-DCMAKE_CXX_COMPILER="g++-12" -DCMAKE_C_COMPILER="gcc-12" \
|
|
122
|
+
-B ./build && make -C ./build && ./build/simsimd_bench
|
|
102
123
|
```
|
|
103
124
|
|
|
104
125
|
MacOS:
|
package/simsimd/bench.cxx
CHANGED
|
@@ -100,7 +100,7 @@ int main(int argc, char** argv) {
|
|
|
100
100
|
register_<std::uint8_t, 21>("tanimoto_maccs_naive", simsimd_tanimoto_maccs_naive);
|
|
101
101
|
register_<simsimd_f32_t>("cos_f32_naive", cos_f32_naive);
|
|
102
102
|
|
|
103
|
-
#if
|
|
103
|
+
#if SIMSIMD_TARGET_ARM_SVE
|
|
104
104
|
register_<simsimd_f32_t>("dot_f32_sve", simsimd_dot_f32_sve);
|
|
105
105
|
register_<simsimd_f32_t>("cos_f32_sve", simsimd_cos_f32_sve);
|
|
106
106
|
register_<std::int16_t>("cos_f16_sve", simsimd_cos_f16_sve);
|
|
@@ -111,27 +111,26 @@ int main(int argc, char** argv) {
|
|
|
111
111
|
register_<std::uint8_t, 21>("tanimoto_maccs_sve", simsimd_tanimoto_maccs_sve);
|
|
112
112
|
#endif
|
|
113
113
|
|
|
114
|
-
#if
|
|
114
|
+
#if SIMSIMD_TARGET_ARM_NEON
|
|
115
115
|
register_<simsimd_f32_t>("dot_f32x4_neon", simsimd_dot_f32x4_neon);
|
|
116
116
|
register_<std::int16_t>("cos_f16x4_neon", simsimd_cos_f16x4_neon);
|
|
117
117
|
register_<std::int8_t>("cos_i8x16_neon", simsimd_cos_i8x16_neon);
|
|
118
|
+
register_<std::int8_t>("l2sq_i8x16_neon", simsimd_l2sq_i8x16_neon);
|
|
118
119
|
register_<simsimd_f32_t>("cos_f32x4_neon", simsimd_cos_f32x4_neon);
|
|
119
120
|
register_<std::uint8_t, 21>("tanimoto_maccs_neon", simsimd_tanimoto_maccs_neon);
|
|
120
121
|
#endif
|
|
121
122
|
|
|
122
|
-
#if
|
|
123
|
+
#if SIMSIMD_TARGET_X86_AVX2
|
|
123
124
|
register_<simsimd_f32_t>("dot_f32x4_avx2", simsimd_dot_f32x4_avx2);
|
|
124
125
|
register_<simsimd_f32_t>("cos_f32x4_avx2", simsimd_cos_f32x4_avx2);
|
|
125
126
|
#endif
|
|
126
127
|
|
|
127
|
-
#if
|
|
128
|
+
#if SIMSIMD_TARGET_X86_AVX512
|
|
128
129
|
register_<std::int16_t>("cos_f16x16_avx512", simsimd_cos_f16x16_avx512);
|
|
129
130
|
register_<std::uint8_t>("hamming_b1x128_avx512", simsimd_hamming_b1x128_avx512);
|
|
130
131
|
register_<std::uint8_t, 21>("tanimoto_maccs_avx512", simsimd_tanimoto_maccs_avx512);
|
|
131
132
|
#endif
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
|
|
135
134
|
bm::RunSpecifiedBenchmarks();
|
|
136
135
|
bm::Shutdown();
|
|
137
136
|
return 0;
|