usearch 2.11.1 → 2.13.1

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.
Files changed (50) hide show
  1. package/README.md +100 -30
  2. package/binding.gyp +11 -12
  3. package/c/README.md +3 -0
  4. package/c/lib.cpp +50 -13
  5. package/c/test.c +60 -55
  6. package/c/usearch.h +16 -0
  7. package/cpp/CMakeLists.txt +6 -0
  8. package/cpp/README.md +34 -13
  9. package/cpp/bench.cpp +99 -47
  10. package/cpp/test.cpp +947 -132
  11. package/include/usearch/index.hpp +894 -272
  12. package/include/usearch/index_dense.hpp +418 -156
  13. package/include/usearch/index_plugins.hpp +99 -49
  14. package/javascript/dist/cjs/usearch.d.ts +39 -1
  15. package/javascript/dist/cjs/usearch.js +11 -1
  16. package/javascript/dist/esm/usearch.d.ts +39 -1
  17. package/javascript/dist/esm/usearch.js +11 -1
  18. package/javascript/tsconfig-esm.json +3 -2
  19. package/javascript/usearch.ts +18 -7
  20. package/package.json +2 -2
  21. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  22. package/prebuilds/linux-arm64/usearch.node +0 -0
  23. package/prebuilds/linux-x64/usearch.node +0 -0
  24. package/simsimd/.cmake-format.py +19 -0
  25. package/simsimd/CONTRIBUTING.md +49 -8
  26. package/simsimd/Cargo.lock +1 -1
  27. package/simsimd/Cargo.toml +10 -5
  28. package/simsimd/Package.swift +16 -0
  29. package/simsimd/README.md +69 -15
  30. package/simsimd/binding.gyp +14 -19
  31. package/simsimd/build.rs +2 -0
  32. package/simsimd/c/lib.c +18 -0
  33. package/simsimd/include/module.modulemap +4 -0
  34. package/simsimd/include/simsimd/binary.h +2 -0
  35. package/simsimd/include/simsimd/dot.h +466 -32
  36. package/simsimd/include/simsimd/probability.h +20 -10
  37. package/simsimd/include/simsimd/simsimd.h +444 -98
  38. package/simsimd/include/simsimd/spatial.h +480 -44
  39. package/simsimd/include/simsimd/types.h +161 -39
  40. package/simsimd/javascript/simsimd.ts +26 -2
  41. package/simsimd/package.json +1 -1
  42. package/simsimd/rust/benches/cosine.rs +8 -2
  43. package/simsimd/rust/benches/native.rs +240 -2
  44. package/simsimd/rust/benches/sqeuclidean.rs +8 -2
  45. package/simsimd/rust/lib.rs +50 -13
  46. package/simsimd/swift/source/SimSIMD.swift +123 -0
  47. package/simsimd/swift/tests/SimSIMDTests.swift +92 -0
  48. package/prebuilds/win32-ia32/usearch.node +0 -0
  49. package/prebuilds/win32-x64/usearch.node +0 -0
  50. package/simsimd/.releaserc +0 -87
@@ -87,10 +87,17 @@ extern "C" {
87
87
  fn simsimd_kl_f64(a: *const f64, b: *const f64, c: usize, d: *mut Distance);
88
88
 
89
89
  fn simsimd_uses_neon() -> i32;
90
+ fn simsimd_uses_neon_f16() -> i32;
91
+ fn simsimd_uses_neon_bf16() -> i32;
92
+ fn simsimd_uses_neon_i8() -> i32;
90
93
  fn simsimd_uses_sve() -> i32;
94
+ fn simsimd_uses_sve_f16() -> i32;
95
+ fn simsimd_uses_sve_bf16() -> i32;
96
+ fn simsimd_uses_sve_i8() -> i32;
91
97
  fn simsimd_uses_haswell() -> i32;
92
98
  fn simsimd_uses_skylake() -> i32;
93
99
  fn simsimd_uses_ice() -> i32;
100
+ fn simsimd_uses_genoa() -> i32;
94
101
  fn simsimd_uses_sapphire() -> i32;
95
102
  }
96
103
 
@@ -100,18 +107,42 @@ pub struct f16(u16);
100
107
 
101
108
  impl f16 {}
102
109
 
103
- /// The `capabilties` module provides functions for detecting the hardware features
110
+ /// The `capabilities` module provides functions for detecting the hardware features
104
111
  /// available on the current system.
105
- pub mod capabilties {
112
+ pub mod capabilities {
106
113
 
107
114
  pub fn uses_neon() -> bool {
108
115
  unsafe { crate::simsimd_uses_neon() != 0 }
109
116
  }
110
117
 
118
+ pub fn uses_neon_f16() -> bool {
119
+ unsafe { crate::simsimd_uses_neon_f16() != 0 }
120
+ }
121
+
122
+ pub fn uses_neon_bf16() -> bool {
123
+ unsafe { crate::simsimd_uses_neon_bf16() != 0 }
124
+ }
125
+
126
+ pub fn uses_neon_i8() -> bool {
127
+ unsafe { crate::simsimd_uses_neon_i8() != 0 }
128
+ }
129
+
111
130
  pub fn uses_sve() -> bool {
112
131
  unsafe { crate::simsimd_uses_sve() != 0 }
113
132
  }
114
133
 
134
+ pub fn uses_sve_f16() -> bool {
135
+ unsafe { crate::simsimd_uses_sve_f16() != 0 }
136
+ }
137
+
138
+ pub fn uses_sve_bf16() -> bool {
139
+ unsafe { crate::simsimd_uses_sve_bf16() != 0 }
140
+ }
141
+
142
+ pub fn uses_sve_i8() -> bool {
143
+ unsafe { crate::simsimd_uses_sve_i8() != 0 }
144
+ }
145
+
115
146
  pub fn uses_haswell() -> bool {
116
147
  unsafe { crate::simsimd_uses_haswell() != 0 }
117
148
  }
@@ -124,6 +155,10 @@ pub mod capabilties {
124
155
  unsafe { crate::simsimd_uses_ice() != 0 }
125
156
  }
126
157
 
158
+ pub fn uses_genoa() -> bool {
159
+ unsafe { crate::simsimd_uses_genoa() != 0 }
160
+ }
161
+
127
162
  pub fn uses_sapphire() -> bool {
128
163
  unsafe { crate::simsimd_uses_sapphire() != 0 }
129
164
  }
@@ -552,11 +587,12 @@ mod tests {
552
587
 
553
588
  #[test]
554
589
  fn test_hardware_features_detection() {
555
- let uses_arm = capabilties::uses_neon() || capabilties::uses_sve();
556
- let uses_x86 = capabilties::uses_haswell()
557
- || capabilties::uses_skylake()
558
- || capabilties::uses_ice()
559
- || capabilties::uses_sapphire();
590
+ let uses_arm = capabilities::uses_neon() || capabilities::uses_sve();
591
+ let uses_x86 = capabilities::uses_haswell()
592
+ || capabilities::uses_skylake()
593
+ || capabilities::uses_ice()
594
+ || capabilities::uses_genoa()
595
+ || capabilities::uses_sapphire();
560
596
 
561
597
  // The CPU can't simultaneously support ARM and x86 SIMD extensions
562
598
  if uses_arm {
@@ -566,12 +602,13 @@ mod tests {
566
602
  assert!(!uses_arm);
567
603
  }
568
604
 
569
- println!("- uses_neon: {}", capabilties::uses_neon());
570
- println!("- uses_sve: {}", capabilties::uses_sve());
571
- println!("- uses_haswell: {}", capabilties::uses_haswell());
572
- println!("- uses_skylake: {}", capabilties::uses_skylake());
573
- println!("- uses_ice: {}", capabilties::uses_ice());
574
- println!("- uses_sapphire: {}", capabilties::uses_sapphire());
605
+ println!("- uses_neon: {}", capabilities::uses_neon());
606
+ println!("- uses_sve: {}", capabilities::uses_sve());
607
+ println!("- uses_haswell: {}", capabilities::uses_haswell());
608
+ println!("- uses_skylake: {}", capabilities::uses_skylake());
609
+ println!("- uses_ice: {}", capabilities::uses_ice());
610
+ println!("- uses_genoa: {}", capabilities::uses_genoa());
611
+ println!("- uses_sapphire: {}", capabilities::uses_sapphire());
575
612
  }
576
613
 
577
614
  //
@@ -0,0 +1,123 @@
1
+ import CSimSIMD
2
+
3
+ public protocol SimSIMD {
4
+ static var dataType: simsimd_datatype_t { get }
5
+ static var cosine: simsimd_metric_punned_t { get }
6
+ static var dotProduct: simsimd_metric_punned_t { get }
7
+ static var squaredEuclidean: simsimd_metric_punned_t { get }
8
+ }
9
+
10
+ extension Int8: SimSIMD {
11
+ public static let dataType = simsimd_datatype_i8_k
12
+ public static let cosine = find(kind: simsimd_metric_cosine_k, dataType: dataType)
13
+ public static let dotProduct = find(kind: simsimd_metric_dot_k, dataType: dataType)
14
+ public static let squaredEuclidean = find(kind: simsimd_metric_sqeuclidean_k, dataType: dataType)
15
+ }
16
+
17
+ @available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
18
+ extension Float16: SimSIMD {
19
+ public static let dataType = simsimd_datatype_f16_k
20
+ public static let cosine = find(kind: simsimd_metric_cosine_k, dataType: dataType)
21
+ public static let dotProduct = find(kind: simsimd_metric_dot_k, dataType: dataType)
22
+ public static let squaredEuclidean = find(kind: simsimd_metric_sqeuclidean_k, dataType: dataType)
23
+ }
24
+
25
+ extension Float32: SimSIMD {
26
+ public static let dataType = simsimd_datatype_f32_k
27
+ public static let cosine = find(kind: simsimd_metric_cosine_k, dataType: dataType)
28
+ public static let dotProduct = find(kind: simsimd_metric_inner_k, dataType: dataType)
29
+ public static let squaredEuclidean = find(kind: simsimd_metric_sqeuclidean_k, dataType: dataType)
30
+ }
31
+
32
+ extension Float64: SimSIMD {
33
+ public static let dataType = simsimd_datatype_f64_k
34
+ public static let cosine = find(kind: simsimd_metric_cosine_k, dataType: dataType)
35
+ public static let dotProduct = find(kind: simsimd_metric_dot_k, dataType: dataType)
36
+ public static let squaredEuclidean = find(kind: simsimd_metric_sqeuclidean_k, dataType: dataType)
37
+ }
38
+
39
+ extension SimSIMD {
40
+ @inlinable @inline(__always)
41
+ public static func cosine<A, B>(_ a: A, _ b: B) -> Double? where A: Sequence, B: Sequence, A.Element == Self, B.Element == Self {
42
+ perform(cosine, a: a, b: b)
43
+ }
44
+
45
+ @inlinable @inline(__always)
46
+ public static func dot<A, B>(_ a: A, _ b: B) -> Double? where A: Sequence, B: Sequence, A.Element == Self, B.Element == Self {
47
+ perform(dotProduct, a: a, b: b)
48
+ }
49
+
50
+ @inlinable @inline(__always)
51
+ public static func sqeuclidean<A, B>(_ a: A, _ b: B) -> Double? where A: Sequence, B: Sequence, A.Element == Self, B.Element == Self {
52
+ perform(squaredEuclidean, a: a, b: b)
53
+ }
54
+ }
55
+
56
+ extension RandomAccessCollection where Element: SimSIMD {
57
+ @inlinable @inline(__always)
58
+ public func cosine<B>(_ b: B) -> Double? where B: Sequence, B.Element == Element {
59
+ Element.cosine(self, b)
60
+ }
61
+
62
+ @inlinable @inline(__always)
63
+ public func dot<B>(_ b: B) -> Double? where B: Sequence, B.Element == Element {
64
+ Element.dot(self, b)
65
+ }
66
+
67
+ @inlinable @inline(__always)
68
+ public func sqeuclidean<B>(_ b: B) -> Double? where B: Sequence, B.Element == Element {
69
+ Element.sqeuclidean(self, b)
70
+ }
71
+ }
72
+
73
+ @inlinable @inline(__always)
74
+ func perform<A, B>(_ metric: simsimd_metric_punned_t, a: A, b: B) -> Double? where A: Sequence, B: Sequence, A.Element == B.Element {
75
+ var distance: simsimd_distance_t = 0
76
+ let result = a.withContiguousStorageIfAvailable { a in
77
+ b.withContiguousStorageIfAvailable { b in
78
+ guard a.count > 0 && a.count == b.count else { return false }
79
+ metric(a.baseAddress, b.baseAddress, .init(a.count), &distance)
80
+ return true
81
+ }
82
+ }
83
+ guard result == true else { return nil }
84
+ return distance
85
+ }
86
+
87
+ public typealias Capabilities = simsimd_capability_t
88
+
89
+ extension simsimd_capability_t: OptionSet, CustomStringConvertible {
90
+ public var description: String {
91
+ var components: [String] = []
92
+ if contains(.neon) { components.append(".neon") }
93
+ if contains(.sve) { components.append(".sve") }
94
+ if contains(.sve2) { components.append(".sve2") }
95
+ if contains(.haswell) { components.append(".haswell") }
96
+ if contains(.skylake) { components.append(".skylake") }
97
+ if contains(.ice) { components.append(".ice") }
98
+ if contains(.sapphire) { components.append(".sapphire") }
99
+ if contains(.genoa) { components.append(".genoa") }
100
+ return "[\(components.joined(separator: ", "))]"
101
+ }
102
+
103
+ public static let available = simsimd_capabilities()
104
+
105
+ public static let any = simsimd_cap_any_k
106
+ public static let neon = simsimd_cap_neon_k
107
+ public static let sve = simsimd_cap_sve_k
108
+ public static let sve2 = simsimd_cap_sve2_k
109
+ public static let haswell = simsimd_cap_haswell_k
110
+ public static let skylake = simsimd_cap_skylake_k
111
+ public static let ice = simsimd_cap_ice_k
112
+ public static let sapphire = simsimd_cap_sapphire_k
113
+ public static let genoa = simsimd_cap_genoa_k
114
+ }
115
+
116
+ @inline(__always)
117
+ private func find(kind: simsimd_metric_kind_t, dataType: simsimd_datatype_t) -> simsimd_metric_punned_t {
118
+ var output: simsimd_metric_punned_t?
119
+ var used = simsimd_capability_t.any
120
+ simsimd_find_metric_punned(kind, dataType, .available, .any, &output, &used)
121
+ guard let output else { fatalError("Could not find function \(kind) for \(dataType)") }
122
+ return output
123
+ }
@@ -0,0 +1,92 @@
1
+ import SimSIMD
2
+ import XCTest
3
+
4
+ class SimSIMDTests: XCTestCase {
5
+ override class func setUp() {
6
+ print("Capabilities: \(Capabilities.available)")
7
+ }
8
+
9
+ func testCosineInt8() throws {
10
+ let a: [Int8] = [3, 97, 127]
11
+ let b: [Int8] = [3, 97, 127]
12
+ let result = try XCTUnwrap(a.cosine(b))
13
+ XCTAssertEqual(result, 0.00012027938, accuracy: 0.01)
14
+ }
15
+
16
+ func testCosineFloat16() throws {
17
+ let a: [Float16] = [1.0, 2.0, 3.0]
18
+ let b: [Float16] = [1.0, 2.0, 3.0]
19
+ let result = try XCTUnwrap(a.cosine(b))
20
+ XCTAssertEqual(result, 0.004930496, accuracy: 0.01)
21
+ }
22
+
23
+ func testCosineFloat32() throws {
24
+ let a: [Float32] = [1.0, 2.0, 3.0]
25
+ let b: [Float32] = [1.0, 2.0, 3.0]
26
+ let result = try XCTUnwrap(a.cosine(b))
27
+ XCTAssertEqual(result, 0.004930496, accuracy: 0.01)
28
+ }
29
+
30
+ func testCosineFloat64() throws {
31
+ let a: [Float64] = [1.0, 2.0, 3.0]
32
+ let b: [Float64] = [1.0, 2.0, 3.0]
33
+ let result = try XCTUnwrap(a.cosine(b))
34
+ XCTAssertEqual(result, 0.004930496, accuracy: 0.01)
35
+ }
36
+
37
+ func testInnerInt8() throws {
38
+ let a: [Int8] = [1, 2, 3]
39
+ let b: [Int8] = [4, 5, 6]
40
+ let result = try XCTUnwrap(a.dot(b))
41
+ XCTAssertEqual(result, 0.029403687, accuracy: 0.01)
42
+ }
43
+
44
+ func testDotFloat16() throws {
45
+ let a: [Float16] = [1.0, 2.0, 3.0]
46
+ let b: [Float16] = [4.0, 5.0, 6.0]
47
+ let result = try XCTUnwrap(a.dot(b))
48
+ XCTAssertEqual(result, 32.0, accuracy: 0.01)
49
+ }
50
+
51
+ func testDotFloat32() throws {
52
+ let a: [Float32] = [1.0, 2.0, 3.0]
53
+ let b: [Float32] = [4.0, 5.0, 6.0]
54
+ let result = try XCTUnwrap(a.dot(b))
55
+ XCTAssertEqual(result, 32.0, accuracy: 0.01)
56
+ }
57
+
58
+ func testDotFloat64() throws {
59
+ let a: [Float64] = [1.0, 2.0, 3.0]
60
+ let b: [Float64] = [4.0, 5.0, 6.0]
61
+ let result = try XCTUnwrap(a.dot(b))
62
+ XCTAssertEqual(result, 32.0, accuracy: 0.01)
63
+ }
64
+
65
+ func testSqeuclideanInt8() throws {
66
+ let a: [Int8] = [1, 2, 3]
67
+ let b: [Int8] = [4, 5, 6]
68
+ let result = try XCTUnwrap(a.sqeuclidean(b))
69
+ XCTAssertEqual(result, 27.0, accuracy: 0.01)
70
+ }
71
+
72
+ func testSqeuclideanFloat16() throws {
73
+ let a: [Float16] = [1.0, 2.0, 3.0]
74
+ let b: [Float16] = [4.0, 5.0, 6.0]
75
+ let result = try XCTUnwrap(a.sqeuclidean(b))
76
+ XCTAssertEqual(result, 27.0, accuracy: 0.01)
77
+ }
78
+
79
+ func testSqeuclideanFloat32() throws {
80
+ let a: [Float32] = [1.0, 2.0, 3.0]
81
+ let b: [Float32] = [4.0, 5.0, 6.0]
82
+ let result = try XCTUnwrap(a.sqeuclidean(b))
83
+ XCTAssertEqual(result, 27.0, accuracy: 0.01)
84
+ }
85
+
86
+ func testSqeuclideanFloat64() throws {
87
+ let a: [Float64] = [1.0, 2.0, 3.0]
88
+ let b: [Float64] = [4.0, 5.0, 6.0]
89
+ let result = try XCTUnwrap(a.sqeuclidean(b))
90
+ XCTAssertEqual(result, 27.0, accuracy: 0.01)
91
+ }
92
+ }
Binary file
Binary file
@@ -1,87 +0,0 @@
1
- {
2
- "branches": [
3
- "main"
4
- ],
5
- "debug": true,
6
- "ci": true,
7
- "dryRun": false,
8
- "plugins": [
9
- [
10
- "@semantic-release/commit-analyzer",
11
- {
12
- "preset": "eslint",
13
- "releaseRules": [
14
- {
15
- "tag": "Break",
16
- "release": "major"
17
- },
18
- {
19
- "tag": "Add",
20
- "release": "minor"
21
- },
22
- {
23
- "tag": "Improve",
24
- "release": "patch"
25
- },
26
- {
27
- "tag": "Make",
28
- "release": "patch"
29
- },
30
- {
31
- "tag": "Refactor",
32
- "release": false
33
- }
34
- ]
35
- }
36
- ],
37
- [
38
- "@semantic-release/release-notes-generator",
39
- {
40
- "preset": "eslint",
41
- "releaseRules": [
42
- {
43
- "tag": "Break",
44
- "release": "major"
45
- },
46
- {
47
- "tag": "Add",
48
- "release": "minor"
49
- },
50
- {
51
- "tag": "Improve",
52
- "release": "patch"
53
- },
54
- {
55
- "tag": "Make",
56
- "release": "patch"
57
- },
58
- {
59
- "tag": "Refactor",
60
- "release": false
61
- }
62
- ]
63
- }
64
- ],
65
- "@semantic-release/github",
66
- [
67
- "@semantic-release/exec",
68
- {
69
- "prepareCmd": "bash .github/workflows/update_version.sh '${nextRelease.version}'"
70
- }
71
- ],
72
- [
73
- "@semantic-release/git",
74
- {
75
- "assets": [
76
- "VERSION",
77
- "package.json",
78
- "Cargo.toml",
79
- "Cargo.lock",
80
- "CMakeLists.txt",
81
- "include/simsimd/simsimd.h"
82
- ],
83
- "message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
84
- }
85
- ]
86
- ]
87
- }