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.
@@ -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-20.04, macOS-11, windows-2022]
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-20.04]
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: python -m pip install .
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
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.1.2"
3
+ version = "2.1.3"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
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?style=social&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?style=social&label=Docker"> </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?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.2'
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 (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};
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ash Vardanian",
6
6
  "license": "Apache 2.0",
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-20.04, macOS-11, windows-2022]
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
- - name: Build locally
40
- run: python -m pip install .
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-20.04]
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: python -m pip install .
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 Development Branch
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, macOS-11, windows-2022]
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 != 'windows-2022'
70
- uses: crazy-max/ghaction-setup-docker@v1.0.0
71
- with:
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 != 'windows-2022'
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/stringzilla
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
  }
@@ -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(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmax-errors=1")
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
- Tuned for Machine Learning applications, mid-size vectors with 100-1024 dimensions.
5
- For Cosine (Angular) distance, the most common metric in AI, one can expect following performance.
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 vectors lengths that are multiples of 128 bits, avoiding any additional head or tail `for` loops for misaligned data.
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 function are prepended with `simsimd_` namespace prefix.
49
- Signature defines the number of arguments:
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 obviously intended for cases, where the number of dimensions is hard-coded.
55
- Constraints define the limitations on the number of dimensions that an argument vector can have.
56
-
57
- | Name | Signature | ISA Extesion | 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` |
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, if the bus bandwidth is not enough to saturate all the cores.
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 | Speed on 1024b |
87
- | :--------------------- | ------: | -------------: |
88
- | `tanimoto_maccs_naive` | 1 | 2.8 Gb/s |
89
- | `tanimoto_maccs_naive` | 32 | 1.2 Gb/s |
90
- | `cos_f32_naive` | 1 | 15.3 Gb/s |
91
- | `cos_f32_naive` | 32 | 4.5 Gb/s |
92
- | `dot_f32x4_avx2` | 1 | 96.2 Gb/s |
93
- | `dot_f32x4_avx2` | 32 | 23.6 Gb/s |
94
- | `cos_f32x4_avx2` | 1 | 56.3 Gb/s |
95
- | `cos_f32x4_avx2` | 32 | 13.9 Gb/s |
96
-
97
- To replicate on your hardware, please run following on Linux:
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 -B ./build && make -C ./build && ./build/simsimd_bench
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 defined(__ARM_FEATURE_SVE)
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 defined(__ARM_NEON)
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 defined(__AVX2__)
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 defined(__AVX512F__)
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;