usearch 2.15.3 → 2.16.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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/cpp/test.cpp +16 -0
  3. package/include/usearch/index.hpp +21 -5
  4. package/include/usearch/index_dense.hpp +6 -1
  5. package/include/usearch/index_plugins.hpp +345 -8
  6. package/javascript/lib.cpp +17 -5
  7. package/javascript/usearch.test.js +190 -21
  8. package/package.json +1 -1
  9. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  10. package/prebuilds/linux-arm64/usearch.node +0 -0
  11. package/prebuilds/linux-x64/usearch.node +0 -0
  12. package/simsimd/.git-blame-ignore-revs +2 -0
  13. package/simsimd/CONTRIBUTING.md +71 -23
  14. package/simsimd/Cargo.lock +1 -1
  15. package/simsimd/Cargo.toml +4 -4
  16. package/simsimd/MANIFEST.in +2 -1
  17. package/simsimd/Package.swift +15 -3
  18. package/simsimd/README.md +104 -35
  19. package/simsimd/binding.gyp +6 -2
  20. package/simsimd/build.rs +2 -0
  21. package/simsimd/c/lib.c +180 -99
  22. package/simsimd/include/simsimd/binary.h +311 -102
  23. package/simsimd/include/simsimd/curved.h +134 -135
  24. package/simsimd/include/simsimd/dot.h +448 -274
  25. package/simsimd/include/simsimd/elementwise.h +1437 -0
  26. package/simsimd/include/simsimd/geospatial.h +2 -2
  27. package/simsimd/include/simsimd/mesh.h +2 -2
  28. package/simsimd/include/simsimd/probability.h +88 -88
  29. package/simsimd/include/simsimd/simsimd.h +1157 -772
  30. package/simsimd/include/simsimd/sparse.h +768 -147
  31. package/simsimd/include/simsimd/spatial.h +955 -376
  32. package/simsimd/include/simsimd/types.h +145 -71
  33. package/simsimd/javascript/lib.c +1 -2
  34. package/simsimd/package.json +4 -4
  35. package/simsimd/rust/lib.rs +14 -1
  36. package/simsimd/scripts/bench.cxx +1070 -0
  37. package/simsimd/scripts/bench.ipynb +187 -0
  38. package/simsimd/{javascript → scripts}/bench.js +1 -1
  39. package/simsimd/{rust/benches/sqeuclidean.rs → scripts/bench_sqeuclidean.rs} +6 -6
  40. package/simsimd/scripts/bench_vectors.py +700 -0
  41. package/simsimd/scripts/bench_vectors_live.py +213 -0
  42. package/simsimd/scripts/test.c +155 -0
  43. package/simsimd/{javascript → scripts}/test.mjs +2 -2
  44. package/simsimd/scripts/test.py +1410 -0
  45. package/simsimd/swift/{source/SimSIMD.swift → SimSIMD.swift} +6 -2
  46. package/simsimd/swift/{tests/SimSIMDTests.swift → Test.swift} +1 -1
  47. /package/simsimd/{rust/benches/cosine.rs → scripts/bench_cosine.rs} +0 -0
  48. /package/simsimd/{rust/benches/native.rs → scripts/bench_native.rs} +0 -0
@@ -1,5 +1,8 @@
1
1
  const test = require('node:test');
2
2
  const assert = require('node:assert');
3
+ const fs = require('node:fs');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
3
6
  const usearch = require('./dist/cjs/usearch.js');
4
7
 
5
8
  function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
@@ -12,38 +15,84 @@ function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
12
15
  }
13
16
 
14
17
 
15
- test('Single-entry operations', () => {
16
- const index = new usearch.Index(2, 'l2sq');
18
+ test('Single-entry operations', async (t) => {
19
+ await t.test('index info', () => {
20
+ const index = new usearch.Index(2, 'l2sq');
17
21
 
18
- assert.equal(index.connectivity(), 16, 'connectivity should be 16');
19
- assert.equal(index.dimensions(), 2, 'dimensions should be 2');
20
- assert.equal(index.size(), 0, 'initial size should be 0');
22
+ assert.equal(index.connectivity(), 16, 'connectivity should be 16');
23
+ assert.equal(index.dimensions(), 2, 'dimensions should be 2');
24
+ assert.equal(index.size(), 0, 'initial size should be 0');
25
+ });
26
+
27
+ await t.test('add', () => {
28
+ const index = new usearch.Index(2, 'l2sq');
29
+
30
+ index.add(15n, new Float32Array([10, 20]));
31
+ index.add(16n, new Float32Array([10, 25]));
32
+
33
+ assert.equal(index.size(), 2, 'size after adding elements should be 2');
34
+ assert.equal(index.contains(15), true, 'entry must be present after insertion');
35
+
36
+ const results = index.search(new Float32Array([13, 14]), 2);
37
+
38
+ assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
39
+ assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
40
+ });
41
+
42
+ await t.test('remove', () => {
43
+ const index = new usearch.Index(2, 'l2sq');
44
+
45
+ index.add(15n, new Float32Array([10, 20]));
46
+ index.add(16n, new Float32Array([10, 25]));
47
+ index.add(25n, new Float32Array([20, 40]));
48
+ index.add(26n, new Float32Array([20, 45]));
21
49
 
22
- index.add(15n, new Float32Array([10, 20]));
23
- index.add(16n, new Float32Array([10, 25]));
50
+ assert.equal(index.remove(15n), 1);
24
51
 
25
- assert.equal(index.size(), 2, 'size after adding elements should be 2');
26
- assert.equal(index.contains(15), true, 'entry must be present after insertion');
52
+ assert.equal(index.size(), 3, 'size after remoing elements should be 3');
53
+ assert.equal(index.contains(15), false, 'entry must be absent after insertion');
27
54
 
28
- const results = index.search(new Float32Array([13, 14]), 2);
55
+ const results = index.search(new Float32Array([13, 14]), 2);
29
56
 
30
- assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
31
- assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
57
+ assert.deepEqual(results.keys, new BigUint64Array([16n, 25n]), 'keys should not include 15');
58
+ });
32
59
  });
33
60
 
34
- test('Batch operations', () => {
35
- const indexBatch = new usearch.Index(2, 'l2sq');
61
+ test('Batch operations', async (t) => {
62
+ await t.test('add', () => {
63
+ const indexBatch = new usearch.Index(2, 'l2sq');
36
64
 
37
- const keys = [15n, 16n];
38
- const vectors = [new Float32Array([10, 20]), new Float32Array([10, 25])];
65
+ const keys = [15n, 16n];
66
+ const vectors = [new Float32Array([10, 20]), new Float32Array([10, 25])];
39
67
 
40
- indexBatch.add(keys, vectors);
41
- assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
68
+ indexBatch.add(keys, vectors);
69
+ assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
42
70
 
43
- const results = indexBatch.search(new Float32Array([13, 14]), 2);
71
+ const results = indexBatch.search(new Float32Array([13, 14]), 2);
44
72
 
45
- assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
46
- assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
73
+ assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
74
+ assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
75
+ });
76
+
77
+ await t.test('remove', () => {
78
+ const indexBatch = new usearch.Index(2, 'l2sq');
79
+
80
+ const keys = [15n, 16n, 25n, 26n];
81
+ const vectors = [
82
+ new Float32Array([10, 20]),
83
+ new Float32Array([10, 25]),
84
+ new Float32Array([20, 40]),
85
+ new Float32Array([20, 45])
86
+ ];
87
+ indexBatch.add(keys, vectors);
88
+
89
+ assert.deepEqual(indexBatch.remove([15n, 25n]), [1, 1])
90
+ assert.equal(indexBatch.size(), 2, 'size after removing batch should be 2');
91
+
92
+ const results = indexBatch.search(new Float32Array([13, 14]), 2);
93
+
94
+ assert.deepEqual(results.keys, new BigUint64Array([16n, 26n]), 'keys should not include 15 and 25');
95
+ });
47
96
  });
48
97
 
49
98
  test("Expected results", () => {
@@ -60,7 +109,27 @@ test("Expected results", () => {
60
109
  assertAlmostEqual(results.distances[0], new Float32Array([0]));
61
110
  });
62
111
 
112
+ test('Expected count()', async (t) => {
113
+ const index = new usearch.Index({
114
+ metric: 'l2sq',
115
+ connectivity: 16,
116
+ dimensions: 3,
117
+ });
118
+ index.add(
119
+ [42n, 43n],
120
+ [new Float32Array([0.2, 0.6, 0.4]), new Float32Array([0.2, 0.6, 0.4])]
121
+ );
63
122
 
123
+ await t.test('Argument is a number', () => {
124
+ assert.equal(1, index.count(43n));
125
+ });
126
+ await t.test('Argument is a number (does not exist)', () => {
127
+ assert.equal(0, index.count(44n));
128
+ });
129
+ await t.test('Argument is an array', () => {
130
+ assert.deepEqual([1, 1, 0], index.count([42n, 43n, 44n]));
131
+ });
132
+ });
64
133
 
65
134
  test('Operations with invalid values', () => {
66
135
  const indexBatch = new usearch.Index(2, 'l2sq');
@@ -84,3 +153,103 @@ test('Operations with invalid values', () => {
84
153
  }
85
154
  );
86
155
  });
156
+
157
+ test('Invalid operations', async (t) => {
158
+ await t.test('Add the same keys', () => {
159
+ const index = new usearch.Index({
160
+ metric: "l2sq",
161
+ connectivity: 16,
162
+ dimensions: 3,
163
+ });
164
+ index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
165
+ assert.throws(
166
+ () => index.add(42n, new Float32Array([0.2, 0.6, 0.4])),
167
+ {
168
+ name: 'Error',
169
+ message: 'Duplicate keys not allowed in high-level wrappers'
170
+ }
171
+ );
172
+ });
173
+ });
174
+
175
+
176
+ test('Serialization', async (t) => {
177
+ const indexPath = path.join(os.tmpdir(), 'usearch.test.index')
178
+
179
+ t.beforeEach(() => {
180
+ const index = new usearch.Index({
181
+ metric: "l2sq",
182
+ connectivity: 16,
183
+ dimensions: 3,
184
+ });
185
+ index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
186
+ index.save(indexPath);
187
+ });
188
+
189
+ t.afterEach(() => {
190
+ fs.unlinkSync(indexPath);
191
+ });
192
+
193
+ await t.test('load', () => {
194
+ const index = new usearch.Index({
195
+ metric: "l2sq",
196
+ connectivity: 16,
197
+ dimensions: 3,
198
+ });
199
+ index.load(indexPath);
200
+ const results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
201
+
202
+ assert.equal(index.size(), 1);
203
+ assert.deepEqual(results.keys, new BigUint64Array([42n]));
204
+ assertAlmostEqual(results.distances[0], new Float32Array([0]));
205
+ });
206
+
207
+ // todo: Skip as the test fails only on windows.
208
+ // The following error in afterEach().
209
+ // `error: "EBUSY: resource busy or locked, unlink`
210
+ await t.test('view: Read data', {skip: process.platform === 'win32'}, () => {
211
+ const index = new usearch.Index({
212
+ metric: "l2sq",
213
+ connectivity: 16,
214
+ dimensions: 3,
215
+ });
216
+ index.view(indexPath);
217
+ const results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
218
+
219
+ assert.equal(index.size(), 1);
220
+ assert.deepEqual(results.keys, new BigUint64Array([42n]));
221
+ assertAlmostEqual(results.distances[0], new Float32Array([0]));
222
+ });
223
+
224
+ await t.test('view: Invalid operations: add', {skip: process.platform === 'win32'}, () => {
225
+ const index = new usearch.Index({
226
+ metric: "l2sq",
227
+ connectivity: 16,
228
+ dimensions: 3,
229
+ });
230
+ index.view(indexPath);
231
+ assert.throws(
232
+ () => index.add(43n, new Float32Array([0.2, 0.6, 0.4])),
233
+ {
234
+ name: 'Error',
235
+ message: "Can't add to an immutable index"
236
+ }
237
+ );
238
+ });
239
+
240
+ await t.test('view: Invalid operations: remove', {skip: process.platform === 'win32'}, () => {
241
+ const index = new usearch.Index({
242
+ metric: "l2sq",
243
+ connectivity: 16,
244
+ dimensions: 3,
245
+ });
246
+ index.view(indexPath);
247
+ assert.throws(
248
+ () => index.remove(42n),
249
+ {
250
+ name: 'Error',
251
+ message: "Can't remove from an immutable index"
252
+ }
253
+ );
254
+ });
255
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.15.3",
3
+ "version": "2.16.0",
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",
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ a4022a988287e527757ecc9bc16a4f2e7dc4770e
2
+ 750c59f5116a2000507a0cec09db009fd7d31232
@@ -1,5 +1,11 @@
1
1
  # Contributing
2
2
 
3
+ To keep the quality of the code high, we have a set of [guidelines](https://github.com/unum-cloud).
4
+
5
+ - [What's the procedure?](https://github.com/unum-cloud/awesome/blob/main/Workflow.md#organizing-software-development)
6
+ - [How to organize branches?](https://github.com/unum-cloud/awesome/blob/main/Workflow.md#branches)
7
+ - [How to style commits?](https://github.com/unum-cloud/awesome/blob/main/Workflow.md#commits)
8
+
3
9
  ## C and C++
4
10
 
5
11
  To rerun experiments utilize the following command:
@@ -23,15 +29,37 @@ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
23
29
  sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
24
30
  ```
25
31
 
26
- On MacOS it's recommended to use Homebrew and install Clang, as opposed to "Apple Clang".
27
- Replacing the default compiler is not recommended, as it may break the system, but you can pass it as an environment variable:
32
+ To compile with the default Apple Clang on MacOS, use:
28
33
 
29
34
  ```sh
30
- brew install llvm
31
- cmake -D CMAKE_BUILD_TYPE=Release -D SIMSIMD_BUILD_TESTS=1 \
32
- -D CMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" \
33
- -D CMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \
34
- -B build_release
35
+ brew install openblas
36
+ cmake -D CMAKE_BUILD_TYPE=Release \
37
+ -D SIMSIMD_BUILD_TESTS=1 \
38
+ -D SIMSIMD_BUILD_BENCHMARKS=1 \
39
+ -D SIMSIMD_BUILD_BENCHMARKS_WITH_CBLAS=1 \
40
+ -D CMAKE_PREFIX_PATH="$(brew --prefix openblas)" \
41
+ -D CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES="$(brew --prefix openblas)/include" \
42
+ -B build_release
43
+ cmake --build build_release --config Release
44
+ ```
45
+
46
+ On MacOS it's recommended to use Homebrew and install Clang, as opposed to "Apple Clang".
47
+ Replacing the default compiler across the entire system is not recommended on MacOS, as it may break the system, but you can pass it as an environment variable:
48
+
49
+ ```sh
50
+ brew install llvm openblas
51
+ cmake -D CMAKE_BUILD_TYPE=Release \
52
+ -D SIMSIMD_BUILD_TESTS=1 \
53
+ -D SIMSIMD_BUILD_BENCHMARKS=1 \
54
+ -D SIMSIMD_BUILD_BENCHMARKS_WITH_CBLAS=1 \
55
+ -D CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES="$(brew --prefix openblas)/include" \
56
+ -D CMAKE_C_LINK_FLAGS="-L$(xcrun --sdk macosx --show-sdk-path)/usr/lib" \
57
+ -D CMAKE_EXE_LINKER_FLAGS="-L$(xcrun --sdk macosx --show-sdk-path)/usr/lib" \
58
+ -D CMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" \
59
+ -D CMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \
60
+ -D CMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
61
+ -D CMAKE_OSX_DEPLOYMENT_TARGET=$(sw_vers -productVersion) \
62
+ -B build_release
35
63
  cmake --build build_release --config Release
36
64
  ```
37
65
 
@@ -42,7 +70,7 @@ Testing:
42
70
  ```sh
43
71
  pip install -e . # to install the package in editable mode
44
72
  pip install pytest pytest-repeat tabulate # testing dependencies
45
- pytest python/test.py -s -x -Wd # to run tests
73
+ pytest scripts/test.py -s -x -Wd # to run tests
46
74
 
47
75
  # to check supported SIMD instructions:
48
76
  python -c "import simsimd; print(simsimd.get_capabilities())"
@@ -62,28 +90,42 @@ CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ pip ins
62
90
  Benchmarking:
63
91
 
64
92
  ```sh
65
- pip install numpy scipy scikit-learn # for comparison baselines
66
- python python/bench.py # to run default benchmarks
67
- python python/bench.py --n 1000 --ndim 1536 # batch size and dimensions
93
+ pip install numpy scipy scikit-learn # for comparison baselines
94
+ python scripts/bench_vectors.py # to run default benchmarks
95
+ python scripts/bench_vectors.py --n 1000 --ndim 1536 # batch size and dimensions
68
96
  ```
69
97
 
70
- You can also benchmark against other libraries:
98
+ You can also benchmark against other libraries, filter the numeric types, and distance metrics:
71
99
 
72
100
  ```sh
73
- $ python python/bench.py --help
74
- > usage: bench.py [-h] [--n N] [--ndim NDIM] [--scipy] [--scikit] [--torch] [--tf] [--jax]
101
+ $ python scripts/bench_vectors.py --help
102
+ > usage: bench.py [-h] [--ndim NDIM] [-n COUNT]
103
+ > [--metric {all,dot,spatial,binary,probability,sparse}]
104
+ > [--dtype {all,bits,int8,uint16,uint32,float16,float32,float64,bfloat16,complex32,complex64,complex128}]
105
+ > [--scipy] [--scikit] [--torch] [--tf] [--jax]
75
106
  >
76
107
  > Benchmark SimSIMD vs. other libraries
77
108
  >
78
- > options:
79
- > -h, --help show this help message and exit
80
- > --n N Number of vectors (default: 1000)
81
- > --ndim NDIM Number of dimensions (default: 1536)
82
- > --scipy Profile SciPy
83
- > --scikit Profile scikit-learn
84
- > --torch Profile PyTorch
85
- > --tf Profile TensorFlow
86
- > --jax Profile JAX
109
+ > optional arguments:
110
+ > -h, --help show this help message and exit
111
+ > --ndim NDIM Number of dimensions in vectors (default: 1536) For binary vectors (e.g., Hamming, Jaccard), this is the number of bits. In
112
+ > case of SimSIMD, the inputs will be treated at the bit-level. Other packages will be matching/comparing 8-bit integers. The
113
+ > volume of exchanged data will be identical, but the results will differ.
114
+ > -n COUNT, --count COUNT
115
+ > Number of vectors per batch (default: 1) By default, when set to 1 the benchmark will generate many vectors of size (ndim, )
116
+ > and call the functions on pairs of single vectors: both directly, and through `cdist`. Alternatively, for larger batch sizes
117
+ > the benchmark will generate two matrices of size (n, ndim) and compute: - batch mode: (n) distances between vectors in
118
+ > identical rows of the two matrices, - all-pairs mode: (n^2) distances between all pairs of vectors in the two matrices via
119
+ > `cdist`.
120
+ > --metric {all,dot,spatial,binary,probability,sparse}
121
+ > Distance metric to use, profiles everything by default
122
+ > --dtype {all,bits,int8,uint16,uint32,float16,float32,float64,bfloat16,complex32,complex64,complex128}
123
+ > Defines numeric types to benchmark, profiles everything by default
124
+ > --scipy Profile SciPy, must be installed
125
+ > --scikit Profile scikit-learn, must be installed
126
+ > --torch Profile PyTorch, must be installed
127
+ > --tf Profile TensorFlow, must be installed
128
+ > --jax Profile JAX, must be installed
87
129
  ```
88
130
 
89
131
 
@@ -155,6 +197,12 @@ npm install -g bun
155
197
  bun test
156
198
  ```
157
199
 
200
+ ## Swift
201
+
202
+ ```sh
203
+ swift build && swift test -v
204
+ ```
205
+
158
206
  ## GoLang
159
207
 
160
208
  ```sh
@@ -496,7 +496,7 @@ dependencies = [
496
496
 
497
497
  [[package]]
498
498
  name = "simsimd"
499
- version = "5.6.4"
499
+ version = "5.9.6"
500
500
  dependencies = [
501
501
  "cc",
502
502
  "criterion",
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "simsimd"
3
- description = "Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm"
4
- version = "5.6.4"
3
+ description = "Portable mixed-precision BLAS-like vector math library for x86 and ARM"
4
+ version = "5.9.6"
5
5
  edition = "2021"
6
6
  license = "Apache-2.0"
7
7
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
@@ -30,12 +30,12 @@ cc = "1.0.83"
30
30
  [[bench]]
31
31
  name = "cosine"
32
32
  harness = false
33
- path = "rust/benches/cosine.rs"
33
+ path = "scripts/bench_cosine.rs"
34
34
 
35
35
  [[bench]]
36
36
  name = "sqeuclidean"
37
37
  harness = false
38
- path = "rust/benches/sqeuclidean.rs"
38
+ path = "scripts/bench_sqeuclidean.rs"
39
39
 
40
40
  [profile.bench]
41
41
  opt-level = 3 # Corresponds to -O3
@@ -1,2 +1,3 @@
1
1
  include include/simsimd/*.h
2
- include include/*
2
+ include include/*
3
+ include VERSION
@@ -9,8 +9,20 @@ let package = Package(
9
9
  .library(name: "SimSIMD", targets: ["SimSIMD"]),
10
10
  ],
11
11
  targets: [
12
- .testTarget(name: "SimSIMDTests", dependencies: ["SimSIMD"], path: "swift/tests"),
13
- .target(name: "SimSIMD", dependencies: ["CSimSIMD"], path: "swift/source"),
14
- .systemLibrary(name: "CSimSIMD", path: "include")
12
+ .testTarget(name: "Test", dependencies: ["SimSIMD"], path: "swift", exclude:["SimSIMD.swift"]),
13
+ .target(name: "SimSIMD", dependencies: ["CSimSIMD"], path: "swift", exclude:["Test.swift"]),
14
+ .target(
15
+ name: "CSimSIMD",
16
+ path: "include/simsimd/", // Adjust the path to include your C source files
17
+ sources: ["../../c/lib.c"], // Include the source file here
18
+ publicHeadersPath: ".",
19
+ cSettings: [
20
+ .define("SIMSIMD_DYNAMIC_DISPATCH", to: "1"), // Define a C macro
21
+ .define("SIMSIMD_NATIVE_F16", to: "0"), // Define a C macro
22
+ .define("SIMSIMD_NATIVE_BF16", to: "0"), // Define a C macro
23
+ .headerSearchPath("include/"), // Specify header search paths
24
+ .unsafeFlags(["-Wall"]) // Use with caution: specify custom compiler flags
25
+ ]
26
+ ),
15
27
  ]
16
28
  )