usearch 2.8.0 → 2.8.2

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.
@@ -56,6 +56,7 @@ jobs:
56
56
  runs-on: ubuntu-22.04
57
57
  needs: versioning
58
58
  strategy:
59
+ fail-fast: false
59
60
  matrix:
60
61
  arch: ["linux/amd64", "linux/arm64"]
61
62
  steps:
@@ -110,6 +111,7 @@ jobs:
110
111
  runs-on: windows-2022
111
112
  needs: versioning
112
113
  strategy:
114
+ fail-fast: false
113
115
  matrix:
114
116
  arch: [x64, x86]
115
117
  steps:
@@ -158,6 +160,7 @@ jobs:
158
160
  runs-on: macos-12
159
161
  needs: versioning
160
162
  strategy:
163
+ fail-fast: false
161
164
  matrix:
162
165
  arch: [arm64, x86_64]
163
166
  steps:
@@ -196,6 +199,7 @@ jobs:
196
199
  runs-on: ${{ matrix.os }}
197
200
  needs: versioning
198
201
  strategy:
202
+ fail-fast: false
199
203
  matrix:
200
204
  os: [ubuntu-22.04, macOS-11, windows-2022]
201
205
  steps:
@@ -346,6 +350,7 @@ jobs:
346
350
  needs: versioning
347
351
  runs-on: ${{ matrix.os }}
348
352
  strategy:
353
+ fail-fast: false
349
354
  matrix:
350
355
  os: [ubuntu-22.04, macOS-11, windows-2022]
351
356
 
@@ -537,12 +542,14 @@ jobs:
537
542
  name: Build C Dependencies for C#
538
543
  needs: versioning
539
544
  strategy:
545
+ fail-fast: false
540
546
  matrix:
541
547
  os: [ubuntu-22.04, macos-12, windows-2022]
542
548
  runs-on: ${{ matrix.os }}
543
549
  defaults:
544
550
  run:
545
551
  shell: bash
552
+
546
553
  steps:
547
554
  - uses: actions/checkout@v3
548
555
  with:
@@ -554,6 +561,8 @@ jobs:
554
561
  run: |
555
562
  sudo apt update
556
563
  sudo apt install -y cmake build-essential libjemalloc-dev libomp-dev gcc-12 g++-12
564
+ export CC=gcc-12
565
+ export CXX=g++-12
557
566
  cmake -B build_artifacts -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_TEST_C=0 -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1 -DUSEARCH_USE_JEMALLOC=1
558
567
  cmake --build build_artifacts --config Release
559
568
  mkdir -p "${{ github.workspace }}/csharp/lib/runtimes/linux-x64/native"
@@ -577,7 +586,6 @@ jobs:
577
586
  cmake --build build_artifacts --config Release
578
587
  mkdir -p "${{ github.workspace }}\csharp\lib\runtimes\win-x64\native"
579
588
  cp "${{ github.workspace }}\build_artifacts\libusearch_c.dll" "${{ github.workspace }}\csharp\lib\runtimes\win-x64\native"
580
- shell: bash
581
589
 
582
590
  - name: Upload Artifacts
583
591
  uses: actions/upload-artifact@v3
package/CITATION.cff CHANGED
@@ -5,7 +5,7 @@ authors:
5
5
  given-names: "Ash"
6
6
  orcid: "https://orcid.org/0000-0002-4882-1815"
7
7
  title: "USearch by Unum Cloud"
8
- version: 2.8.0
8
+ version: 2.8.2
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.0"
3
+ version = "2.8.2"
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
@@ -392,7 +392,7 @@ doi = {10.5281/zenodo.7949416},
392
392
  author = {Vardanian, Ash},
393
393
  title = {{USearch by Unum Cloud}},
394
394
  url = {https://github.com/unum-cloud/usearch},
395
- version = {2.8.0},
395
+ version = {2.8.2},
396
396
  year = {2023},
397
397
  month = oct,
398
398
  }
package/conanfile.py CHANGED
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
7
7
  class USearchConan(ConanFile):
8
8
 
9
9
  name = "usearch"
10
- version = '2.8.0'
10
+ version = '2.8.2'
11
11
  license = "Apache-2.0"
12
12
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
13
13
  homepage = "https://github.com/unum-cloud/usearch"
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <Project>
3
3
  <PropertyGroup>
4
- <Version Condition="'$(Version)' == ''">2.8.0</Version>
4
+ <Version Condition="'$(Version)' == ''">2.8.2</Version>
5
5
 
6
6
  <Authors>Unum</Authors>
7
7
  <Company>Unum</Company>
@@ -11,7 +11,7 @@
11
11
 
12
12
  #define USEARCH_VERSION_MAJOR 2
13
13
  #define USEARCH_VERSION_MINOR 8
14
- #define USEARCH_VERSION_PATCH 0
14
+ #define USEARCH_VERSION_PATCH 2
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ash Vardanian (https://ashvardanian.com/)",
6
6
  "license": "Apache 2.0",
package/pyproject.toml CHANGED
@@ -8,9 +8,13 @@ addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
8
8
  xfail_strict = true
9
9
  filterwarnings = ["error"]
10
10
 
11
+ # Avoid running tests, as everything is happening in a super slow container
12
+ # We have already run all the relavent Python tests in `prerelease.yml`
13
+ # test-requires = ["pytest", "numpy"]
14
+ # test-command = "pytest {project}/python/scripts"
11
15
  [tool.cibuildwheel]
12
- test-requires = ["pytest", "numpy"]
13
- test-command = "pytest {project}/python/scripts"
16
+ test-requires = []
17
+ test-command = ""
14
18
  build-verbosity = 0
15
19
  skip = ["*musllinux*", "*i686*", "pp*", "cp36-*", "cp312-*"]
16
20
 
@@ -18,22 +22,20 @@ skip = ["*musllinux*", "*i686*", "pp*", "cp36-*", "cp312-*"]
18
22
  before-build = [
19
23
  "rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
20
24
  "mkdir -p build/usearch",
21
- "git submodule update --init --recursive"
25
+ "git submodule update --init --recursive",
22
26
  ]
23
27
  manylinux-x86_64-image = "manylinux_2_28"
24
28
  manylinux-aarch64-image = "manylinux_2_28"
25
29
 
26
30
  archs = ["x86_64", "aarch64"]
27
- before-all = [
28
- "yum install -y glibc-devel wget python3-devel"
29
- ]
31
+ before-all = ["yum install -y glibc-devel wget python3-devel"]
30
32
  repair-wheel-command = "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
31
33
 
32
34
  [tool.cibuildwheel.macos]
33
35
  before-build = [
34
36
  "rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
35
37
  "mkdir -p build/usearch",
36
- "git submodule update --init --recursive"
38
+ "git submodule update --init --recursive",
37
39
  ]
38
40
  archs = ["x86_64", "universal2", "arm64"]
39
41
  repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
@@ -43,7 +45,7 @@ repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest
43
45
  before-build = [
44
46
  "rd /s /q {project}\\CMakeCache.txt {project}\\build {project}\\build_debug {project}\\CMakeFiles.txt {project}\\_deps {project}\\.pytest_cache || echo Done",
45
47
  "md build\\usearch",
46
- "git submodule update --init --recursive"
48
+ "git submodule update --init --recursive",
47
49
  ]
48
50
  archs = ["x86", "AMD64"]
49
51
  skip = ["*win32*", "pp*", "cp36-*", "cp312-*"]
package/rust/lib.rs CHANGED
@@ -14,6 +14,7 @@ pub mod ffi {
14
14
  Cos,
15
15
  Pearson,
16
16
  Haversine,
17
+ Divergence,
17
18
  Hamming,
18
19
  Tanimoto,
19
20
  Sorensen,
@@ -61,20 +61,29 @@ jobs:
61
61
 
62
62
  test_javascript:
63
63
  name: Test JavaScript
64
- runs-on: ubuntu-latest
65
- strategy:
66
- matrix:
67
- os: [ubuntu-22.04, macOS-11, windows-2022]
68
- node-version: [18.x]
64
+ runs-on: ubuntu-22.04
65
+ env:
66
+ CC: gcc-12
67
+ CXX: g++-12
68
+
69
69
  steps:
70
70
  - uses: actions/checkout@v4
71
+ with:
72
+ ref: "main"
73
+ - run: git submodule update --init --recursive
74
+
75
+ - name: Update compilers
76
+ run: |
77
+ sudo apt update
78
+ sudo apt install -y cmake build-essential libjemalloc-dev libomp-dev gcc-12 g++-12
79
+
71
80
  - name: Set up Node.js
72
81
  uses: actions/setup-node@v3
73
82
  with:
74
- node-version: "18.x"
83
+ node-version: 18
75
84
 
76
- - name: Build locally
77
- run: npm install
78
-
79
- - name: Test
80
- run: npm test
85
+ - name: Build and Test
86
+ run: |
87
+ npm install
88
+ npm ci
89
+ npm test
@@ -18,18 +18,18 @@ permissions:
18
18
  jobs:
19
19
  versioning:
20
20
  name: Semantic Release
21
- runs-on: ubuntu-latest
21
+ runs-on: ubuntu-22.04
22
22
  steps:
23
23
  - uses: actions/checkout@v3
24
24
  with:
25
25
  persist-credentials: false
26
26
  - uses: actions/setup-node@v3
27
- - run: npm install --save-dev @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx semantic-release
27
+ - run: npm install --save-dev --prefix ./package-ci @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx --prefix ./package-ci semantic-release
28
28
 
29
29
  rebase:
30
30
  name: Rebase Dev. Branch
31
31
  needs: versioning
32
- runs-on: ubuntu-latest
32
+ runs-on: ubuntu-22.04
33
33
  steps:
34
34
  - name: Checkout the latest code
35
35
  uses: actions/checkout@v3
@@ -109,17 +109,33 @@ jobs:
109
109
  name: Publish JavaScript
110
110
  needs: versioning
111
111
  runs-on: ubuntu-22.04
112
+ env:
113
+ CC: gcc-12
114
+ CXX: g++-12
115
+
112
116
  steps:
113
117
  - uses: actions/checkout@v3
114
118
  with:
115
119
  ref: "main"
116
120
  - run: git submodule update --init --recursive
117
- - uses: actions/setup-node@v3
121
+
122
+ - name: Update compilers
123
+ run: |
124
+ sudo apt update
125
+ sudo apt install -y cmake build-essential libjemalloc-dev libomp-dev gcc-12 g++-12
126
+
127
+ - name: Set up Node.js
128
+ uses: actions/setup-node@v3
118
129
  with:
119
130
  node-version: 18
120
- - run: npm install
121
- - run: npm ci
122
- - run: npm test
123
- - uses: JS-DevTools/npm-publish@v2
131
+
132
+ - name: Build and Test
133
+ run: |
134
+ npm install
135
+ npm ci
136
+ npm test
137
+
138
+ - name: Publish
139
+ uses: JS-DevTools/npm-publish@v2
124
140
  with:
125
141
  token: ${{ secrets.NPM_TOKEN }}
@@ -46,9 +46,9 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
46
46
  if(NOT APPLE)
47
47
  add_compile_options(-march=native)
48
48
  endif()
49
- add_compile_options(-pedantic -ferror-limit=1 -ffast-math)
49
+ add_compile_options(-pedantic -ferror-limit=1)
50
50
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51
- add_compile_options(-march=native -pedantic -fmax-errors=1 -ffast-math)
51
+ add_compile_options(-march=native -pedantic -fmax-errors=1)
52
52
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
53
53
  add_compile_options(-w -ferror-limit=1)
54
54
  endif()
package/simsimd/README.md CHANGED
@@ -34,7 +34,7 @@ Given 1000 embeddings from OpenAI Ada API with 1536 dimensions, running on the A
34
34
 
35
35
  ### Intel Sapphire Rapids
36
36
 
37
- On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vectorized code using GCC 12. GCC handles single-precision `float` and `int8_t` well. However, it fails on `_Float16` arrays, which has been part of the C language since 2011.
37
+ On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vectorized code using GCC 12. GCC handles single-precision `float`, but might not be the best choice for `int8` and `_Float16` arrays, which has been part of the C language since 2011.
38
38
 
39
39
  | | GCC 12 `f32` | GCC 12 `f16` | SimSIMD `f16` | `f16` improvement |
40
40
  | :-------------- | -----------: | -----------: | ------------: | ----------------: |
@@ -3,8 +3,8 @@
3
3
 
4
4
  #include <benchmark/benchmark.h>
5
5
 
6
- #define SIMSIMD_RSQRT sqrtf
7
- #define SIMSIMD_LOG logf
6
+ #define SIMSIMD_RSQRT(x) (1 / sqrtf(x))
7
+ #define SIMSIMD_LOG(x) (logf(x))
8
8
  #include <simsimd/simsimd.h>
9
9
 
10
10
  namespace bm = benchmark;
@@ -78,7 +78,7 @@ void register_(std::string name, metric_at* distance_func, metric_at* baseline_f
78
78
  using pair_bytes_t = vectors_pair_gt<scalar_at, 1536 / sizeof(scalar_at)>;
79
79
 
80
80
  std::size_t seconds = 10;
81
- std::size_t threads = std::thread::hardware_concurrency(); // 1;
81
+ std::size_t threads = 1; // std::thread::hardware_concurrency(); // 1;
82
82
  std::string name_dims = name + "_" + std::to_string(pair_dims_t{}.dimensions()) + "d";
83
83
  std::string name_bytes = name + "_" + std::to_string(pair_bytes_t{}.size_bytes()) + "b";
84
84
 
@@ -95,7 +95,8 @@ int main(int argc, char** argv) {
95
95
  bool compiled_with_sve = false;
96
96
  bool compiled_with_neon = false;
97
97
  bool compiled_with_avx2 = false;
98
- bool compiled_with_avx512popcnt = false;
98
+ bool compiled_with_avx512vpopcntdq = false;
99
+ bool compiled_with_avx512vnni = false;
99
100
 
100
101
  #if defined(__ARM_FEATURE_SVE)
101
102
  compiled_with_sve = true;
@@ -107,7 +108,10 @@ int main(int argc, char** argv) {
107
108
  compiled_with_avx2 = true;
108
109
  #endif
109
110
  #if defined(__AVX512VPOPCNTDQ__)
110
- compiled_with_avx512popcnt = true;
111
+ compiled_with_avx512vpopcntdq = true;
112
+ #endif
113
+ #if defined(__AVX512VNNI__)
114
+ compiled_with_avx512vnni = true;
111
115
  #endif
112
116
 
113
117
  // Log supported functionality
@@ -117,7 +121,8 @@ int main(int argc, char** argv) {
117
121
  std::printf("- Arm NEON support enabled: %s\n", flags[compiled_with_neon]);
118
122
  std::printf("- Arm SVE support enabled: %s\n", flags[compiled_with_sve]);
119
123
  std::printf("- x86 AVX2 support enabled: %s\n", flags[compiled_with_avx2]);
120
- std::printf("- x86 AVX512VPOPCNTDQ support enabled: %s\n", flags[compiled_with_avx512popcnt]);
124
+ std::printf("- x86 AVX512VPOPCNTDQ support enabled: %s\n", flags[compiled_with_avx512vpopcntdq]);
125
+ std::printf("- x86 AVX512VNNI support enabled: %s\n", flags[compiled_with_avx512vnni]);
121
126
  std::printf("\n");
122
127
 
123
128
  // Run the benchmarks
@@ -133,41 +133,55 @@ simsimd_sve_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_siz
133
133
 
134
134
  #if SIMSIMD_TARGET_X86_AVX512
135
135
 
136
- __attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f"))) //
136
+ __attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f,bmi2"))) //
137
137
  inline static simsimd_f32_t
138
138
  simsimd_avx512_b8_hamming(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
139
139
  __m512i differences_vec = _mm512_setzero_si512();
140
- for (simsimd_size_t i = 0; i < n_words; i += 64) {
141
-
142
- // Compute mask for tail elements
143
- __mmask64 mask = (i + 64 <= n_words) ? 0xFFFFFFFFFFFFFFFF : (((1ull << (n_words - i)) - 1ull));
144
- __m512i a_vec = _mm512_maskz_loadu_epi8(mask, a + i);
145
- __m512i b_vec = _mm512_maskz_loadu_epi8(mask, b + i);
146
- __m512i xor_vec = _mm512_xor_si512(a_vec, b_vec);
147
-
148
- differences_vec = _mm512_add_epi64(differences_vec, _mm512_popcnt_epi64(xor_vec));
140
+ __m512i a_vec, b_vec;
141
+
142
+ simsimd_avx512_b8_hamming_cycle:
143
+ if (n_words < 64) {
144
+ __mmask64 mask = _bzhi_u64(0xFFFFFFFFFFFFFFFF, n_words);
145
+ a_vec = _mm512_maskz_loadu_epi8(mask, a);
146
+ b_vec = _mm512_maskz_loadu_epi8(mask, b);
147
+ n_words = 0;
148
+ } else {
149
+ a_vec = _mm512_loadu_epi8(a);
150
+ b_vec = _mm512_loadu_epi8(b);
151
+ a += 64, b += 64, n_words -= 64;
149
152
  }
153
+ __m512i xor_vec = _mm512_xor_si512(a_vec, b_vec);
154
+ differences_vec = _mm512_add_epi64(differences_vec, _mm512_popcnt_epi64(xor_vec));
155
+ if (n_words)
156
+ goto simsimd_avx512_b8_hamming_cycle;
150
157
 
151
158
  simsimd_size_t differences = _mm512_reduce_add_epi64(differences_vec);
152
159
  return (simsimd_f32_t)differences;
153
160
  }
154
161
 
155
- __attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f"))) //
162
+ __attribute__((target("avx512vpopcntdq,avx512vl,avx512bw,avx512f,bmi2"))) //
156
163
  inline static simsimd_f32_t
157
164
  simsimd_avx512_b8_jaccard(simsimd_b8_t const* a, simsimd_b8_t const* b, simsimd_size_t n_words) {
158
165
  __m512i intersection_vec = _mm512_setzero_si512(), union_vec = _mm512_setzero_si512();
159
- for (simsimd_size_t i = 0; i < n_words; i += 64) {
160
-
161
- // Compute mask for tail elements
162
- __mmask64 mask = (i + 64 <= n_words) ? 0xFFFFFFFFFFFFFFFF : (((1ull << (n_words - i)) - 1ull));
163
- __m512i a_vec = _mm512_maskz_loadu_epi8(mask, a + i);
164
- __m512i b_vec = _mm512_maskz_loadu_epi8(mask, b + i);
165
- __m512i and_vec = _mm512_and_si512(a_vec, b_vec);
166
- __m512i or_vec = _mm512_or_si512(a_vec, b_vec);
167
-
168
- intersection_vec = _mm512_add_epi64(intersection_vec, _mm512_popcnt_epi64(and_vec));
169
- union_vec = _mm512_add_epi64(union_vec, _mm512_popcnt_epi64(or_vec));
166
+ __m512i a_vec, b_vec;
167
+
168
+ simsimd_avx512_b8_jaccard_cycle:
169
+ if (n_words < 64) {
170
+ __mmask64 mask = _bzhi_u64(0xFFFFFFFFFFFFFFFF, n_words);
171
+ a_vec = _mm512_maskz_loadu_epi8(mask, a);
172
+ b_vec = _mm512_maskz_loadu_epi8(mask, b);
173
+ n_words = 0;
174
+ } else {
175
+ a_vec = _mm512_loadu_epi8(a);
176
+ b_vec = _mm512_loadu_epi8(b);
177
+ a += 64, b += 64, n_words -= 64;
170
178
  }
179
+ __m512i and_vec = _mm512_and_si512(a_vec, b_vec);
180
+ __m512i or_vec = _mm512_or_si512(a_vec, b_vec);
181
+ intersection_vec = _mm512_add_epi64(intersection_vec, _mm512_popcnt_epi64(and_vec));
182
+ union_vec = _mm512_add_epi64(union_vec, _mm512_popcnt_epi64(or_vec));
183
+ if (n_words)
184
+ goto simsimd_avx512_b8_jaccard_cycle;
171
185
 
172
186
  simsimd_size_t intersection = _mm512_reduce_add_epi64(intersection_vec),
173
187
  union_ = _mm512_reduce_add_epi64(union_vec);