usearch 2.1.2 → 2.2.0

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.
@@ -26,7 +26,8 @@ extern "C" {
26
26
  * forming 21 incomplete bytes for the MACCS fingerprints used in
27
27
  * computation chemistry.
28
28
  */
29
- inline static simsimd_f32_t simsimd_tanimoto_maccs_naive(uint8_t const* a_chars, uint8_t const* b_chars) {
29
+ inline static simsimd_f32_t //
30
+ simsimd_tanimoto_maccs_naive(uint8_t const* a_chars, uint8_t const* b_chars) {
30
31
  unsigned long a[3] = {0};
31
32
  unsigned long b[3] = {0};
32
33
  memcpy(&a[0], a_chars, 21);
@@ -36,13 +37,44 @@ inline static simsimd_f32_t simsimd_tanimoto_maccs_naive(uint8_t const* a_chars,
36
37
  return 1 - and_count / or_count;
37
38
  }
38
39
 
40
+ /**
41
+ * @brief Weird Tanimoto distance implementation for concatenated MACCS and ECFP4
42
+ * representations, forming a grand-total of 56 bytes. The last chunk is evaluated
43
+ * if only the first one matches well.
44
+ *
45
+ * - First 166 bits in 21 bytes is a MACCS vector.
46
+ * - After that 3 empty bytes of a padding are expected.
47
+ * - After which, 256 bytes (32 words) of ECFP4 follow.
48
+ */
49
+ inline static simsimd_f32_t //
50
+ simsimd_tanimoto_conditional_naive(uint8_t const* a_chars, uint8_t const* b_chars) {
51
+ float const threshold = 0.2;
52
+ unsigned long const* a = (unsigned long const*)(a_chars);
53
+ unsigned long const* b = (unsigned long const*)(b_chars);
54
+ float and_count = popcount64(a[0] & b[0]) + popcount64(a[1] & b[1]) + popcount64(a[2] & b[2]);
55
+ float or_count = popcount64(a[0] | b[0]) + popcount64(a[1] | b[1]) + popcount64(a[2] | b[2]);
56
+ float result = 1 - and_count / or_count;
57
+ if (result > threshold)
58
+ return result;
59
+
60
+ // Start comparing ECFP4
61
+ and_count = 0, or_count = 0;
62
+ for (int i = 0; i != 32; ++i)
63
+ and_count += popcount64(a[3 + i] & b[3 + i]), or_count += popcount64(a[3 + i] | b[3 + i]);
64
+ result = 1 - and_count / or_count;
65
+ return result * threshold;
66
+ }
67
+
68
+ #if SIMSIMD_TARGET_ARM
69
+ #if SIMSIMD_TARGET_ARM_NEON
70
+
39
71
  /**
40
72
  * @brief Optimized version for Tanimoto distance on @b exactly 166 bits,
41
73
  * forming 21 incomplete bytes for the MACCS fingerprints used in
42
74
  * computation chemistry, accelerated for Arm NEON ISA.
43
75
  */
44
- inline static simsimd_f32_t simsimd_tanimoto_maccs_neon(uint8_t const* a_chars, uint8_t const* b_chars) {
45
- #if defined(__ARM_NEON)
76
+ inline static simsimd_f32_t //
77
+ simsimd_tanimoto_maccs_neon(uint8_t const* a_chars, uint8_t const* b_chars) {
46
78
  unsigned char a[32] = {0};
47
79
  unsigned char b[32] = {0};
48
80
  memcpy(&a[0], a_chars, 21);
@@ -58,19 +90,19 @@ inline static simsimd_f32_t simsimd_tanimoto_maccs_neon(uint8_t const* a_chars,
58
90
  float and_populations = vaddvq_u8(vaddq_u8(vcntq_u8(a_and_b_first), vcntq_u8(a_and_b_second)));
59
91
  float or_populations = vaddvq_u8(vaddq_u8(vcntq_u8(a_or_b_first), vcntq_u8(a_or_b_second)));
60
92
  return 1 - and_populations / or_populations;
61
- #else
62
- (void)a_chars, (void)b_chars;
63
- return 0;
64
- #endif
65
93
  }
66
94
 
95
+ #endif // SIMSIMD_TARGET_ARM_NEON
96
+
97
+ #if SIMSIMD_TARGET_ARM_SVE
98
+
67
99
  /**
68
100
  * @brief Optimized version for Tanimoto distance on @b exactly 166 bits,
69
101
  * forming 21 incomplete bytes for the MACCS fingerprints used in
70
102
  * computation chemistry, accelerated for Arm NEON ISA.
71
103
  */
72
- inline static simsimd_f32_t simsimd_tanimoto_maccs_sve(uint8_t const* a_chars, uint8_t const* b_chars) {
73
- #if defined(__ARM_FEATURE_SVE)
104
+ __attribute__((target("+sve"))) inline static simsimd_f32_t //
105
+ simsimd_tanimoto_maccs_sve(uint8_t const* a_chars, uint8_t const* b_chars) {
74
106
  svbool_t pg_vec = svwhilelt_b8(0ul, 21ul);
75
107
  svuint8_t a_vec = svld1_u8(pg_vec, (uint8_t const*)a_chars);
76
108
  svuint8_t b_vec = svld1_u8(pg_vec, (uint8_t const*)b_chars);
@@ -92,11 +124,12 @@ inline static simsimd_f32_t simsimd_tanimoto_maccs_sve(uint8_t const* a_chars, u
92
124
  float and_populations = svaddv_u8(svptrue_b8(), and_populations_vec);
93
125
  float or_populations = svaddv_u8(svptrue_b8(), or_populations_vec);
94
126
  return 1 - and_populations / or_populations;
95
- #else
96
- (void)a_chars, (void)b_chars;
97
- return 0;
98
- #endif
99
127
  }
128
+ #endif
129
+ #endif // SIMSIMD_TARGET_ARM
130
+
131
+ #if SIMSIMD_TARGET_X86
132
+ #if SIMSIMD_TARGET_X86_AVX512
100
133
 
101
134
  /**
102
135
  * @brief Optimized version for Tanimoto distance on @b exactly 166 bits,
@@ -104,21 +137,29 @@ inline static simsimd_f32_t simsimd_tanimoto_maccs_sve(uint8_t const* a_chars, u
104
137
  * computation chemistry, accelerated with AVX-512 population count
105
138
  * instructions.
106
139
  */
107
- inline static simsimd_f32_t simsimd_tanimoto_maccs_avx512(uint8_t const* a, uint8_t const* b) {
108
- #if defined(__AVX512VPOPCNTDQ__)
140
+ __attribute__((target("avx512vpopcntdq"))) //
141
+ __attribute__((target("avx512vl"))) //
142
+ __attribute__((target("avx512bw"))) //
143
+ __attribute__((target("avx512f"))) inline static simsimd_f32_t //
144
+ simsimd_tanimoto_maccs_avx512(uint8_t const* a, uint8_t const* b) {
109
145
  __m256i a_vec = _mm256_maskz_loadu_epi8(0b11111111111111111111100000000000, a);
110
146
  __m256i b_vec = _mm256_maskz_loadu_epi8(0b11111111111111111111100000000000, b);
111
- __m256i and_vec _mm256_and_si256(a_vec, b_vec);
112
- __m256i or_vec _mm256_or_si256(a_vec, b_vec);
113
- __m256i and_counts = _mm256_popcnt_epi8(and_vec);
114
- __m256i or_counts = _mm256_popcnt_epi8(or_vec);
115
- return 1 - float(_mm256_reduce_add_epi8(and_counts)) / _mm256_reduce_add_epi8(or_counts);
116
- #else
117
- (void)a, (void)b;
118
- return 0;
119
- #endif
147
+ __m256i and_vec = _mm256_and_si256(a_vec, b_vec);
148
+ __m256i or_vec = _mm256_or_si256(a_vec, b_vec);
149
+ __m256i and_counts_vec = _mm256_popcnt_epi64(and_vec);
150
+ __m256i or_counts_vec = _mm256_popcnt_epi64(or_vec);
151
+
152
+ float and_counts = _mm256_extract_epi64(and_counts_vec, 0) + _mm256_extract_epi64(and_counts_vec, 1) +
153
+ _mm256_extract_epi64(and_counts_vec, 2) + _mm256_extract_epi64(and_counts_vec, 3);
154
+ float or_counts = _mm256_extract_epi64(or_counts_vec, 0) + _mm256_extract_epi64(or_counts_vec, 1) +
155
+ _mm256_extract_epi64(or_counts_vec, 2) + _mm256_extract_epi64(or_counts_vec, 3);
156
+
157
+ return 1 - and_counts / or_counts;
120
158
  }
121
159
 
160
+ #endif // SIMSIMD_TARGET_X86_AVX512
161
+ #endif // SIMSIMD_TARGET_X86
162
+
122
163
  #undef popcount64
123
164
 
124
165
  #ifdef __cplusplus
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @brief Collection of Biology-oriented Similarity Measures, SIMD-accelerated with SSE, AVX, NEON, SVE.
3
+ *
4
+ * @author Ash Vardanian
5
+ * @date August 8, 2023
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include <simsimd/simsimd_chem.h>
11
+
12
+ #ifdef _MSC_VER
13
+ #define hash32
14
+ #define hash64
15
+ #else
16
+ #define hash32
17
+ #define hash64
18
+ #endif
19
+
20
+ #ifdef __cplusplus
21
+ extern "C" {
22
+ #endif
23
+
24
+ inline static void simsimd_4gram_hash_string( //
25
+ char const* chars, size_t chars_length, //
26
+ uint8_t* hash, size_t hash_length) {
27
+
28
+ // Skip misaligned addresses in a naive fashion
29
+ char const* const chars_end = chars + chars_length;
30
+ for (; uintptr_t(chars) % 4 && chars != chars_end; ++chars) {
31
+ uint32_t word;
32
+ memcpy(&word, chars, 4);
33
+ hash;
34
+ }
35
+
36
+ uint32_t last_word = *a_chars;
37
+
38
+ for (size_t i = 0; i + 8 <= a_length; i += 8) {
39
+ uint32_t new_word = *a_chars;
40
+
41
+ size_t hash_first = hash(last_word);
42
+ size_t hash_second = hash((last_word << 8) | (new_word >> 24));
43
+ size_t hash_third = hash((last_word << 16) | (new_word >> 16));
44
+ size_t hash_fourth = hash((last_word << 16) | (new_word >> 16));
45
+
46
+ uint64_t a_word;
47
+ memcpy(&a_word, a_chars, 8);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @brief Similarity measure for different length strings, that compares them
53
+ * by hashing the N-grams first and computing the Tenimoto distance of
54
+ * hashes.
55
+ *
56
+ * By design uses a separate bit-set for every string. Those have to be of identical
57
+ * length derived from `l = max(a_length, b_length)`, as `(l + N - 1) * 2` for any
58
+ * N-gram, to have less than half of bits populated.
59
+ *
60
+ * Inspired by Rabin-Karp algorithm, and continues the approaches implemented in Stringzilla.
61
+ */
62
+ inline static simsimd_f32_t simsimd_4gram_hashes_naive( //
63
+ uint8_t const* a_chars, uint8_t const* b_chars, //
64
+ size_t a_length, size_t b_length, //
65
+ uint8_t* a_hash, uint8_t* b_hash, size_t length_hash) {
66
+
67
+ // Skip thrrough misaligned part
68
+
69
+ uint32_t last_word = *a_chars;
70
+
71
+ for (size_t i = 0; i + 8 <= a_length; i += 8) {
72
+ uint32_t new_word = *a_chars;
73
+
74
+ size_t hash_first = hash(last_word);
75
+ size_t hash_second = hash((last_word << 8) | (new_word >> 24));
76
+ size_t hash_third = hash((last_word << 16) | (new_word >> 16));
77
+ size_t hash_fourth = hash((last_word << 16) | (new_word >> 16));
78
+
79
+ uint64_t a_word;
80
+ memcpy(&a_word, a_chars, 8);
81
+ }
82
+
83
+ size_t b_words = (b_length + 7) / 8;
84
+
85
+ return simsimd_tanimoto_b1x8_naive(a_hash, b_hash, length_hash);
86
+ }
87
+
88
+ #undef popcount64
89
+
90
+ #ifdef __cplusplus
91
+ }
92
+ #endif
@@ -3,6 +3,6 @@
3
3
  "@semantic-release/exec": "^6.0.3",
4
4
  "@semantic-release/git": "^10.0.1",
5
5
  "conventional-changelog-eslint": "^4.0.0",
6
- "semantic-release": "^21.0.7"
6
+ "semantic-release": "^21.1.1"
7
7
  }
8
8
  }
@@ -30,8 +30,9 @@ repair-wheel-command = "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
30
30
  [tool.cibuildwheel.macos]
31
31
  before-build = [
32
32
  "rm -rf {project}/build",
33
+ "brew install gcc@12",
33
34
  ]
34
- archs = ["x86_64", "universal2", "arm64"]
35
+ archs = ["x86_64", "arm64"]
35
36
  repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
36
37
 
37
38
  [tool.cibuildwheel.windows]
@@ -1,11 +1,17 @@
1
1
  /**
2
2
  * @file python.c
3
- * @author Ashot Vardanian
3
+ * @author Ash Vardanian
4
4
  * @date 2023-01-30
5
5
  * @copyright Copyright (c) 2023
6
6
  *
7
- * @brief Pure CPython bindings for simsimd.
7
+ * @brief Pure CPython bindings for SimSIMD.
8
8
  */
9
+ #define SIMSIMD_TARGET_ARM_NEON 1
10
+ #define SIMSIMD_TARGET_X86_AVX2 1
11
+ #if __linux__
12
+ #define SIMSIMD_TARGET_ARM_SVE 1
13
+ #define SIMSIMD_TARGET_X86_AVX512 1
14
+ #endif
9
15
 
10
16
  #include "simsimd/simsimd.h"
11
17
  #include "simsimd/simsimd_chem.h"
@@ -51,31 +57,54 @@ PyMODINIT_FUNC PyInit_simsimd(void) {
51
57
  if (m == NULL)
52
58
  return NULL;
53
59
 
54
- PyModule_AddObject(m, "dot_f32_sve", distance(&simsimd_dot_f32_sve));
55
- PyModule_AddObject(m, "dot_f32x4_neon", distance(&simsimd_dot_f32x4_neon));
60
+ PyModule_AddObject(m, "tanimoto_b1x8_naive", distance(&simsimd_tanimoto_b1x8_naive));
56
61
 
57
- PyModule_AddObject(m, "cos_f32_sve", distance(&simsimd_cos_f32_sve));
58
- PyModule_AddObject(m, "cos_f16_sve", distance(&simsimd_cos_f16_sve));
62
+ // Specialized:
63
+ PyModule_AddObject(m, "tanimoto_maccs_naive", distance(&simsimd_tanimoto_maccs_naive));
64
+ PyModule_AddObject(m, "tanimoto_conditional_naive", distance(&simsimd_tanimoto_conditional_naive));
65
+
66
+ #if SIMSIMD_TARGET_ARM
67
+ PyModule_AddObject(m, "dot_f32x4_neon", distance(&simsimd_dot_f32x4_neon));
59
68
  PyModule_AddObject(m, "cos_f16x4_neon", distance(&simsimd_cos_f16x4_neon));
60
69
  PyModule_AddObject(m, "cos_i8x16_neon", distance(&simsimd_cos_i8x16_neon));
61
70
  PyModule_AddObject(m, "cos_f32x4_neon", distance(&simsimd_cos_f32x4_neon));
62
- PyModule_AddObject(m, "cos_f16x16_avx512", distance(&simsimd_cos_f16x16_avx512));
63
- PyModule_AddObject(m, "cos_f32x4_avx2", distance(&simsimd_cos_f32x4_avx2));
64
71
 
72
+ // Specialized:
73
+ PyModule_AddObject(m, "tanimoto_maccs_neon", distance(&simsimd_tanimoto_maccs_neon));
74
+
75
+ #if SIMSIMD_TARGET_ARM_SVE
76
+ PyModule_AddObject(m, "dot_f32_sve", distance(&simsimd_dot_f32_sve));
77
+ PyModule_AddObject(m, "cos_f32_sve", distance(&simsimd_cos_f32_sve));
78
+ PyModule_AddObject(m, "cos_f16_sve", distance(&simsimd_cos_f16_sve));
65
79
  PyModule_AddObject(m, "l2sq_f32_sve", distance(&simsimd_l2sq_f32_sve));
66
80
  PyModule_AddObject(m, "l2sq_f16_sve", distance(&simsimd_l2sq_f16_sve));
67
-
68
81
  PyModule_AddObject(m, "hamming_b1x8_sve", distance(&simsimd_hamming_b1x8_sve));
69
82
  PyModule_AddObject(m, "hamming_b1x128_sve", distance(&simsimd_hamming_b1x128_sve));
70
- PyModule_AddObject(m, "hamming_b1x128_avx512", distance(&simsimd_hamming_b1x128_avx512));
71
83
 
72
- PyModule_AddObject(m, "tanimoto_b1x8_naive", distance(&simsimd_tanimoto_b1x8_naive));
73
-
74
- // Specific vector sizes for chemistry
75
- PyModule_AddObject(m, "tanimoto_maccs_naive", distance(&simsimd_tanimoto_maccs_naive));
76
- PyModule_AddObject(m, "tanimoto_maccs_neon", distance(&simsimd_tanimoto_maccs_neon));
84
+ // Specialized:
77
85
  PyModule_AddObject(m, "tanimoto_maccs_sve", distance(&simsimd_tanimoto_maccs_sve));
86
+ #endif
87
+ #endif
88
+
89
+ #if SIMSIMD_TARGET_X86
90
+ PyModule_AddObject(m, "dot_f32x4_avx2", distance(&simsimd_dot_f32x4_avx2));
91
+ PyModule_AddObject(m, "cos_f32x4_avx2", distance(&simsimd_cos_f32x4_avx2));
92
+ PyModule_AddObject(m, "l2sq_f32x4_avx2", distance(&simsimd_l2sq_f32x4_avx2));
93
+ PyModule_AddObject(m, "dot_f16x8_avx2", distance(&simsimd_dot_f16x8_avx2));
94
+ PyModule_AddObject(m, "cos_f16x8_avx2", distance(&simsimd_cos_f16x8_avx2));
95
+ PyModule_AddObject(m, "l2sq_f16x8_avx2", distance(&simsimd_l2sq_f16x8_avx2));
96
+
97
+ #if SIMSIMD_TARGET_X86_AVX512
98
+ PyModule_AddObject(m, "dot_f16x16_avx512", distance(&simsimd_dot_f16x16_avx512));
99
+ PyModule_AddObject(m, "cos_f16x16_avx512", distance(&simsimd_cos_f16x16_avx512));
100
+ PyModule_AddObject(m, "l2sq_f16x16_avx512", distance(&simsimd_l2sq_f16x16_avx512));
101
+
102
+ PyModule_AddObject(m, "hamming_b1x128_avx512", distance(&simsimd_hamming_b1x128_avx512));
103
+
104
+ // Specialized:
78
105
  PyModule_AddObject(m, "tanimoto_maccs_avx512", distance(&simsimd_tanimoto_maccs_avx512));
106
+ #endif
107
+ #endif
79
108
 
80
109
  return m;
81
110
  }
@@ -1,23 +1,38 @@
1
- import simsimd as sisi
1
+ import platform
2
+
3
+ import simsimd as simd
2
4
 
3
5
 
4
6
  def test_non_null():
5
- assert sisi.to_int(sisi.dot_f32_sve) != 0
6
- assert sisi.to_int(sisi.dot_f32x4_neon) != 0
7
- assert sisi.to_int(sisi.cos_f32_sve) != 0
8
- assert sisi.to_int(sisi.cos_f16_sve) != 0
9
- assert sisi.to_int(sisi.cos_f16x4_neon) != 0
10
- assert sisi.to_int(sisi.cos_i8x16_neon) != 0
11
- assert sisi.to_int(sisi.cos_f32x4_neon) != 0
12
- assert sisi.to_int(sisi.cos_f16x16_avx512) != 0
13
- assert sisi.to_int(sisi.cos_f32x4_avx2) != 0
14
- assert sisi.to_int(sisi.l2sq_f32_sve) != 0
15
- assert sisi.to_int(sisi.l2sq_f16_sve) != 0
16
- assert sisi.to_int(sisi.hamming_b1x8_sve) != 0
17
- assert sisi.to_int(sisi.hamming_b1x128_sve) != 0
18
- assert sisi.to_int(sisi.hamming_b1x128_avx512) != 0
19
- assert sisi.to_int(sisi.tanimoto_b1x8_naive) != 0
20
- assert sisi.to_int(sisi.tanimoto_maccs_naive) != 0
21
- assert sisi.to_int(sisi.tanimoto_maccs_neon) != 0
22
- assert sisi.to_int(sisi.tanimoto_maccs_sve) != 0
23
- assert sisi.to_int(sisi.tanimoto_maccs_avx512) != 0
7
+ # Some distance functions are provided for every platform
8
+ assert simd.to_int(simd.tanimoto_b1x8_naive) != 0
9
+ assert simd.to_int(simd.tanimoto_maccs_naive) != 0
10
+
11
+ # Arm Neon variants should be precompiled for any 64-bit Arm machine:
12
+ if platform.machine() == "arm64":
13
+ assert simd.to_int(simd.cos_f16x4_neon) != 0
14
+ assert simd.to_int(simd.cos_i8x16_neon) != 0
15
+ assert simd.to_int(simd.cos_f32x4_neon) != 0
16
+ assert simd.to_int(simd.dot_f32x4_neon) != 0
17
+ assert simd.to_int(simd.tanimoto_maccs_neon) != 0
18
+
19
+ # Arm SVE variants should be precompiled for 64-bit Arm machines running Linux:
20
+ if platform.machine() == "arm64" and platform.system().lower() == "linux":
21
+ assert simd.to_int(simd.dot_f32_sve) != 0
22
+ assert simd.to_int(simd.cos_f32_sve) != 0
23
+ assert simd.to_int(simd.cos_f16_sve) != 0
24
+ assert simd.to_int(simd.l2sq_f32_sve) != 0
25
+ assert simd.to_int(simd.l2sq_f16_sve) != 0
26
+ assert simd.to_int(simd.hamming_b1x8_sve) != 0
27
+ assert simd.to_int(simd.hamming_b1x128_sve) != 0
28
+ assert simd.to_int(simd.tanimoto_maccs_sve) != 0
29
+
30
+ # x86 AVX2 variants are precompiled for every 64-bit x86 platform:
31
+ if platform.machine() == "x86_64":
32
+ assert simd.to_int(simd.cos_f32x4_avx2) != 0
33
+
34
+ # x86 AVX-512 variants are precompiled for 64-bit x86 machines running Linux:
35
+ if platform.machine() == "x86_64" and platform.system().lower() == "linux":
36
+ assert simd.to_int(simd.cos_f16x16_avx512) != 0
37
+ assert simd.to_int(simd.hamming_b1x128_avx512) != 0
38
+ assert simd.to_int(simd.tanimoto_maccs_avx512) != 0
package/simsimd/setup.py CHANGED
@@ -10,13 +10,10 @@ this_directory = os.path.abspath(dirname(__file__))
10
10
  with open(os.path.join(this_directory, "README.md"), "r", encoding="utf8") as f:
11
11
  long_description = f.read()
12
12
 
13
- "-march=armv8.2-a+sve"
14
- "-march=sapphirerapids"
15
-
16
13
  setup(
17
14
  name=__lib_name__,
18
15
  version=__version__,
19
- author="Ashot Vardanian",
16
+ author="Ash Vardanian",
20
17
  author_email="1983160+ashvardanian@users.noreply.github.com",
21
18
  url="https://github.com/ashvardanian/simsimd",
22
19
  description="SIMD-accelerated similarity measures for x86 and Arm",
@@ -29,14 +26,13 @@ setup(
29
26
  "Intended Audience :: Developers",
30
27
  "Intended Audience :: Information Technology",
31
28
  "License :: OSI Approved :: Apache Software License",
32
- "Operating System :: Linux",
33
29
  "Programming Language :: C",
34
30
  "Programming Language :: Python :: Implementation :: CPython",
35
31
  ],
36
32
  ext_modules=[
37
33
  Extension(
38
34
  "simsimd",
39
- sources=["python/python.c"],
35
+ sources=["python/lib.c"],
40
36
  include_dirs=["include"],
41
37
  )
42
38
  ],
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.1.2"
3
+ version="2.2.0"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"
File without changes