usearch 2.7.3 → 2.7.7

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 (57) hide show
  1. package/.github/workflows/Dockerfile.libs +4 -6
  2. package/.github/workflows/prerelease.yml +4 -1
  3. package/.github/workflows/release.yml +8 -28
  4. package/.github/workflows/update_version.sh +1 -0
  5. package/CITATION.cff +2 -2
  6. package/CMakeLists.txt +1 -1
  7. package/Cargo.toml +1 -1
  8. package/README.md +4 -4
  9. package/binding.gyp +1 -1
  10. package/build.gradle +20 -5
  11. package/conanfile.py +1 -1
  12. package/cpp/bench.cpp +1 -1
  13. package/csharp/nuget/nuget-package.props +1 -1
  14. package/docs/compilation.md +0 -2
  15. package/golang/README.md +0 -1
  16. package/include/usearch/index.hpp +1 -1
  17. package/include/usearch/index_plugins.hpp +128 -247
  18. package/package.json +1 -1
  19. package/python/lib.cpp +3 -4
  20. package/simsimd/.github/workflows/prerelease.yml +33 -58
  21. package/simsimd/.github/workflows/release.yml +22 -9
  22. package/simsimd/.github/workflows/update_version.sh +3 -1
  23. package/simsimd/.releaserc +9 -1
  24. package/simsimd/.vscode/launch.json +3 -0
  25. package/simsimd/.vscode/settings.json +15 -2
  26. package/simsimd/.vscode/tasks.json +2 -2
  27. package/simsimd/CMakeLists.txt +36 -55
  28. package/simsimd/README.md +163 -109
  29. package/simsimd/binding.gyp +18 -0
  30. package/simsimd/cpp/bench.cxx +187 -0
  31. package/simsimd/go.mod +3 -0
  32. package/simsimd/golang/bench_test.go +40 -0
  33. package/simsimd/golang/simsimd.go +47 -0
  34. package/simsimd/golang/unit_test.go +40 -0
  35. package/simsimd/include/simsimd/binary.h +186 -0
  36. package/simsimd/include/simsimd/probability.h +645 -0
  37. package/simsimd/include/simsimd/simsimd.h +335 -575
  38. package/simsimd/include/simsimd/spatial.h +924 -0
  39. package/simsimd/include/simsimd/types.h +196 -0
  40. package/simsimd/javascript/bench.js +117 -0
  41. package/simsimd/javascript/lib.c +102 -0
  42. package/simsimd/javascript/simsimd.js +45 -0
  43. package/simsimd/javascript/test.js +29 -0
  44. package/simsimd/package.json +31 -2
  45. package/simsimd/pyproject.toml +5 -6
  46. package/simsimd/python/bench.ipynb +187 -0
  47. package/simsimd/python/bench.py +268 -0
  48. package/simsimd/python/lib.c +453 -72
  49. package/simsimd/python/test.py +167 -35
  50. package/simsimd/setup.py +51 -8
  51. package/wasmer.toml +1 -1
  52. package/simsimd/bench.cxx +0 -137
  53. package/simsimd/include/simsimd/simsimd_bio.h +0 -54
  54. package/simsimd/include/simsimd/simsimd_chem.h +0 -167
  55. package/simsimd/include/simsimd/simsimd_text.h +0 -92
  56. package/simsimd/python/run.sh +0 -1
  57. package/simsimd/python/test.c +0 -109
@@ -1,3 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
- echo $1 > VERSION
3
+ echo $1 > VERSION && \
4
+ sed -i "s/\"version\": \".*\"/\"version\": \"$1\"/" package.json && \
5
+ sed -i "s/\"__version__\", \".*\"/\"__version__\", \"$1\"/" python/lib.c
@@ -11,6 +11,10 @@
11
11
  {
12
12
  "preset": "eslint",
13
13
  "releaseRules": [
14
+ {
15
+ "tag": "Break",
16
+ "release": "major"
17
+ },
14
18
  {
15
19
  "tag": "Add",
16
20
  "release": "minor"
@@ -35,6 +39,10 @@
35
39
  {
36
40
  "preset": "eslint",
37
41
  "releaseRules": [
42
+ {
43
+ "tag": "Break",
44
+ "release": "major"
45
+ },
38
46
  {
39
47
  "tag": "Add",
40
48
  "release": "minor"
@@ -68,7 +76,7 @@
68
76
  "VERSION",
69
77
  "conanfile.py",
70
78
  "package.json",
71
- "Cargo.toml",
79
+ "Cargo.toml"
72
80
  ],
73
81
  "message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
74
82
  }
@@ -10,6 +10,9 @@
10
10
  "request": "launch",
11
11
  "program": "${workspaceFolder}/build_debug/simsimd_bench",
12
12
  "cwd": "${workspaceFolder}",
13
+ "args": [
14
+ "--benchmark_filter=i8_cos"
15
+ ],
13
16
  "environment": [
14
17
  {
15
18
  "name": "ASAN_OPTIONS",
@@ -86,16 +86,29 @@
86
86
  "__nullptr": "cpp",
87
87
  "unordered_set": "cpp",
88
88
  "span": "cpp",
89
- "arm_neon.h": "c"
89
+ "arm_neon.h": "c",
90
+ "__tree": "cpp",
91
+ "filesystem": "cpp"
90
92
  },
91
93
  "cSpell.words": [
94
+ "castsi",
92
95
  "dtype",
93
96
  "dtypes",
97
+ "jaccard",
94
98
  "kann",
99
+ "Kullback",
100
+ "Leibler",
101
+ "loadu",
95
102
  "maccs",
103
+ "maskz",
104
+ "napi",
96
105
  "simd",
97
106
  "simsimd",
107
+ "sqeuclidean",
98
108
  "tanimoto",
99
- "unsw"
109
+ "typedarray",
110
+ "unsw",
111
+ "Vardanian",
112
+ "vpopcntdq"
100
113
  ]
101
114
  }
@@ -3,7 +3,7 @@
3
3
  "tasks": [
4
4
  {
5
5
  "label": "Build Benchmark: Debug",
6
- "command": "cmake -DCMAKE_BUILD_TYPE=Debug -B ./build_debug && make -j 2 -C ./build_debug",
6
+ "command": "cmake -DCMAKE_BUILD_TYPE=Debug -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build_debug && make -j 2 -C ./build_debug",
7
7
  "args": [],
8
8
  "type": "shell"
9
9
  },
@@ -15,7 +15,7 @@
15
15
  },
16
16
  {
17
17
  "label": "Build Benchmark: Release",
18
- "command": "cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B ./build_release && make -j 2 -C ./build_release",
18
+ "command": "cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build_release && make -j 2 -C ./build_release",
19
19
  "args": [],
20
20
  "type": "shell"
21
21
  }
@@ -1,18 +1,21 @@
1
+ # SimSIMD library CMakeLists.txt
1
2
  cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
2
- project(simsimd LANGUAGES CXX C)
3
+ project(simsimd LANGUAGES C CXX)
4
+
5
+ set(CMAKE_C_STANDARD 11)
6
+ set(CMAKE_C_STANDARD_REQUIRED YES)
7
+ set(CMAKE_C_EXTENSIONS NO)
8
+
3
9
  set(CMAKE_CXX_STANDARD 17)
4
10
  set(CMAKE_CXX_STANDARD_REQUIRED YES)
5
11
  set(CMAKE_CXX_EXTENSIONS NO)
6
12
 
7
- option(SIMSIMD_USE_OPENMP "Use OpenMP for Parallelism" OFF)
8
13
  option(SIMSIMD_BUILD_BENCHMARKS "Compile a micro-benchmark for current ISA" OFF)
9
14
 
10
- # Get external content: Google Benchmark, Thrust
15
+ # Fetch external dependencies
11
16
  include(FetchContent)
12
- include_directories(include/)
13
17
 
14
- # Fetch GBenchmark and surpress internal tests.
15
- # https://github.com/google/benchmark/blob/main/docs/user_guide.md#using-register-benchmark
18
+ # Suppress building tests of Google Benchmark
16
19
  set(BENCHMARK_ENABLE_TESTING OFF)
17
20
  set(BENCHMARK_ENABLE_INSTALL OFF)
18
21
  set(BENCHMARK_ENABLE_DOXYGEN OFF)
@@ -20,67 +23,45 @@ set(BENCHMARK_INSTALL_DOCS OFF)
20
23
  set(BENCHMARK_DOWNLOAD_DEPENDENCIES ON)
21
24
  set(BENCHMARK_ENABLE_GTEST_TESTS OFF)
22
25
  set(BENCHMARK_USE_BUNDLED_GTEST ON)
26
+
23
27
  FetchContent_Declare(
24
- benchmark
25
- GIT_REPOSITORY https://github.com/google/benchmark.git
26
- GIT_TAG v1.7.0
27
- )
28
+ benchmark
29
+ GIT_REPOSITORY https://github.com/google/benchmark.git
30
+ GIT_TAG v1.7.0)
28
31
  FetchContent_MakeAvailable(benchmark)
29
32
 
30
- # Make Release by default
33
+ # Default to Release build type if not set
31
34
  if(NOT CMAKE_BUILD_TYPE)
32
- set(CMAKE_BUILD_TYPE Release)
35
+ set(CMAKE_BUILD_TYPE Release)
33
36
  endif()
34
37
 
35
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fsanitize=address")
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")
38
+ # Global compiler flags for debug and release
39
+ set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address")
40
+ set(CMAKE_CXX_FLAGS_RELEASE "-O3")
41
+ set(CMAKE_C_FLAGS_DEBUG "-g -fsanitize=address")
42
+ set(CMAKE_C_FLAGS_RELEASE "-O3")
39
43
 
40
- # List of all possible compiler IDs:
41
- # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
42
- if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
44
+ # Compiler-specific flags
45
+ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
46
+ if(NOT APPLE)
47
+ add_compile_options(-march=native)
48
+ endif()
49
+ add_compile_options(-pedantic -ferror-limit=1 -ffast-math)
43
50
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
44
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
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")
48
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
49
- set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda")
50
- set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode arch=compute_86,code=sm_86")
51
-
51
+ add_compile_options(-march=native -pedantic -fmax-errors=1 -ffast-math)
52
52
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
53
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
54
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=1")
53
+ add_compile_options(-w -ferror-limit=1)
55
54
  endif()
56
55
 
57
- # Define our header-only library.
56
+ # Define the header-only library
57
+ file(GLOB SIMSIMD_SOURCES include/simsimd/*.h)
58
58
  add_library(simsimd INTERFACE)
59
- target_sources(simsimd INTERFACE include/simsimd/simsimd.h)
59
+ target_sources(simsimd INTERFACE ${SIMSIMD_SOURCES})
60
60
  target_include_directories(simsimd INTERFACE "${PROJECT_SOURCE_DIR}/include")
61
61
 
62
- # Build the benchmarks if needed.
63
- if(${SIMSIMD_BUILD_BENCHMARKS})
64
- find_package(Threads REQUIRED)
65
- add_executable(simsimd_bench bench.cxx)
66
- target_link_libraries(simsimd_bench simsimd Threads::Threads benchmark)
67
-
68
- if(${SIMSIMD_USE_OPENMP})
69
- find_package(OpenMP REQUIRED)
70
- target_link_libraries(simsimd_bench OpenMP::OpenMP_CXX)
71
- endif()
72
-
73
- if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
74
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
75
-
76
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
77
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
78
-
79
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
80
- set_property(SOURCE simsimd_bench.cpp PROPERTY LANGUAGE CUDA)
81
- set_target_properties(simsimd_bench PROPERTIES POSITION_INDEPENDENT_CODE ON)
82
- set_target_properties(simsimd_bench PROPERTIES CUDA_ARCHITECTURES "86")
83
-
84
- elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
85
- endif()
62
+ # Build benchmarks if required
63
+ if(SIMSIMD_BUILD_BENCHMARKS)
64
+ find_package(Threads REQUIRED)
65
+ add_executable(simsimd_bench cpp/bench.cxx)
66
+ target_link_libraries(simsimd_bench simsimd Threads::Threads benchmark)
86
67
  endif()
package/simsimd/README.md CHANGED
@@ -1,41 +1,129 @@
1
1
  # SimSIMD 📏
2
2
 
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.
3
+ ## Efficient Alternative to [`scipy.spatial.distance`][scipy] and [`numpy.inner`][numpy]
6
4
 
7
- | Method | Vectors | Any Length | Speed on 256b | Speed on 1024b |
8
- | :----- | :------ | :--------- | ------------: | -------------: |
9
- | Serial | `f32` | ✅ | 5 GB/s | 5 GB/s |
10
- | SVE | `f32` | ✅ | 34 GB/s | 40 GB/s |
11
- | SVE | `f16` | ✅ | 28 GB/s | 35 GB/s |
12
- | NEON | `f16` | ❌ | 16 GB/s | 18 GB/s |
5
+ SimSIMD leverages SIMD intrinsics, capabilities that only select compilers effectively utilize. This framework supports conventional AVX2 instructions on x86, NEON on Arm, as well as __rare__ AVX-512 FP16 instructions on x86 and Scalable Vector Extensions (SVE) on Arm. Designed specifically for Machine Learning contexts, it's optimized for handling high-dimensional vector embeddings.
13
6
 
14
- > The benchmarks were done on Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances.
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
- > By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
17
- > Serial versions imply auto-vectorization pragmas.
7
+ - ✅ __3-200x faster__ than NumPy and SciPy distance functions.
8
+ - ✅ Euclidean (L2), Inner Product, and Cosine (Angular) spatial distances.
9
+ - ✅ Hamming (~ Manhattan) and Jaccard (~ Tanimoto) binary distances.
10
+ - ✅ Single-precision `f32`, half-precision `f16`, `i8`, and binary vectors.
11
+ - ✅ Compatible with GCC and Clang on MacOS and Linux, and MinGW on Windows.
12
+ - ✅ Compatible with NumPy, PyTorch, TensorFlow, and other tensors.
13
+ - ✅ Has __no dependencies__, not even LibC.
14
+ - ✅ [JavaScript API](#using-simsimd-in-javascript).
15
+ - ✅ [C API](#using-simsimd-in-c).
18
16
 
19
- Need something like this in your CMake-based project?
17
+ [scipy]: https://docs.scipy.org/doc/scipy/reference/spatial.distance.html#module-scipy.spatial.distance
18
+ [numpy]: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
20
19
 
21
- ```cmake
22
- FetchContent_Declare(
23
- simsimd
24
- GIT_REPOSITORY https://github.com/ashvardanian/simsimd.git
25
- GIT_SHALLOW TRUE
26
- )
27
- FetchContent_MakeAvailable(simsimd)
28
- include_directories(${simsimd_SOURCE_DIR}/include)
20
+ ## Benchmarks
21
+
22
+ ### Apple M2 Pro
23
+
24
+ Given 1000 embeddings from OpenAI Ada API with 1536 dimensions, running on the Apple M2 Pro Arm CPU with NEON support, here's how SimSIMD performs against conventional methods:
25
+
26
+ | Conventional | SimSIMD | `f32` improvement | `f16` improvement | `i8` improvement |
27
+ | :------------------------------------- | :---------------- | ----------------: | ----------------: | ---------------: |
28
+ | `numpy.inner` | `inner` | __2 x__ | __9 x__ | __18 x__ |
29
+ | `scipy.spatial.distance.cosine` | `cosine` | __32 x__ | __79 x__ | __133 x__ |
30
+ | `scipy.spatial.distance.sqeuclidean` | `sqeuclidean` | __5 x__ | __26 x__ | __17 x__ |
31
+ | `scipy.spatial.distance.jensenshannon` | `jensenshannon` | __41 x__ | __76 x__ | |
32
+ | `scipy.special.kl_div` | `kullbackleibler` | __21 x__ | __18 x__ | |
33
+
34
+ ### Intel Sapphire Rapids
35
+
36
+ On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against autovectorized-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
+
38
+ | | GCC 12 `f32` | GCC 12 `f16` | SimSIMD `f16` | `f16` improvement |
39
+ | :------------ | -----------: | -----------: | ------------: | ----------------: |
40
+ | `cosine` | 3.28 M/s | 336.29 k/s | 6.88 M/s | __20 x__ |
41
+ | `sqeuclidean` | 4.62 M/s | 147.25 k/s | 5.32 M/s | __36 x__ |
42
+ | `inner` | 3.81 M/s | 192.02 k/s | 5.99 M/s | __31 x__ |
43
+
44
+ __Technical Insights__:
45
+
46
+ - [Uses Arm SVE and x86 AVX-512's masked loads to eliminate tail `for`-loops](https://ashvardanian.com/posts/simsimd-faster-scipy/#tails-of-the-past-the-significance-of-masked-loads).
47
+ - [Uses AVX-512 FP16 for half-precision operations, that few compilers vectorize](https://ashvardanian.com/posts/simsimd-faster-scipy/#the-challenge-of-f16).
48
+ - [Substitutes LibC's `sqrt` calls with bithacks using Jan Kadlec's constant](https://ashvardanian.com/posts/simsimd-faster-scipy/#bonus-section-bypassing-sqrt-and-libc-dependencies).
49
+ - Avoids slow PyBind11 and SWIG, directly using the CPython C API.
50
+ - Avoids slow `PyArg_ParseTuple` and manually unpacks argument tuples.
51
+
52
+ __Broader Benchmarking Results__:
53
+
54
+ - [Apple M2 Pro](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-1-performance-on-apple-m2-pro).
55
+ - [4th Gen Intel Xeon Platinum](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-2-performance-on-4th-gen-intel-xeon-platinum-8480).
56
+ - [AWS Graviton 3](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-3-performance-on-aws-graviton-3).
57
+
58
+ ## Using in Python
59
+
60
+ ### Installation
61
+
62
+ ```sh
63
+ pip install simsimd
64
+ ```
65
+
66
+ ### Distance Between 2 Vectors
67
+
68
+ ```py
69
+ import simsimd
70
+ import numpy as np
71
+
72
+ vec1 = np.random.randn(1536).astype(np.float32)
73
+ vec2 = np.random.randn(1536).astype(np.float32)
74
+ dist = simsimd.cosine(vec1, vec2)
75
+ ```
76
+
77
+ Supported functions include `cosine`, `inner`, `sqeuclidean`, `hamming`, and `jaccard`.
78
+
79
+ ### Distance Between 2 Batches
80
+
81
+ ```py
82
+ batch1 = np.random.randn(100, 1536).astype(np.float32)
83
+ batch2 = np.random.randn(100, 1536).astype(np.float32)
84
+ dist = simsimd.cosine(batch1, batch2)
85
+ ```
86
+
87
+ If either batch has more than one vector, the other batch must have one or same number of vectors.
88
+ If it contains just one, the value is broadcasted.
89
+
90
+ ### All Pairwise Distances
91
+
92
+ For calculating distances between all possible pairs of rows across two matrices (akin to [`scipy.spatial.distance.cdist`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html)):
93
+
94
+ ```py
95
+ matrix1 = np.random.randn(1000, 1536).astype(np.float32)
96
+ matrix2 = np.random.randn(10, 1536).astype(np.float32)
97
+ distances = simsimd.cdist(matrix1, matrix2, metric="cosine")
98
+ ```
99
+
100
+ ### Multithreading
101
+
102
+ By default, computations use a single CPU core. To optimize and utilize all CPU cores on Linux systems, add the `threads=0` argument. Alternatively, specify a custom number of threads:
103
+
104
+ ```py
105
+ distances = simsimd.cdist(matrix1, matrix2, metric="cosine", threads=0)
29
106
  ```
30
107
 
108
+ ### Hardware Backend Capabilities
109
+
110
+ To view a list of hardware backends that SimSIMD supports:
111
+
112
+ ```py
113
+ print(simsimd.get_capabilities())
114
+ ```
115
+
116
+ ### Using Python API with USearch
117
+
31
118
  Want to use it in Python with [USearch](https://github.com/unum-cloud/usearch)?
119
+ You can wrap the raw C function pointers SimSIMD backends into a `CompiledMetric`, and pass it to USearch, similar to how it handles Numba's JIT-compiled code.
32
120
 
33
121
  ```py
34
- from usearch import Index, CompiledMetric, MetricKind, MetricSignature
35
- from simsimd import to_int, cos_f32x4_neon
122
+ from usearch.index import Index, CompiledMetric, MetricKind, MetricSignature
123
+ from simsimd import pointer_to_sqeuclidean, pointer_to_cosine, pointer_to_inner
36
124
 
37
125
  metric = CompiledMetric(
38
- pointer=to_int(cos_f32x4_neon),
126
+ pointer=pointer_to_cosine("f16"),
39
127
  kind=MetricKind.Cos,
40
128
  signature=MetricSignature.ArrayArraySize,
41
129
  )
@@ -43,100 +131,66 @@ metric = CompiledMetric(
43
131
  index = Index(256, metric=metric)
44
132
  ```
45
133
 
46
- ## Available Metrics
47
-
48
- In the C99 interface, all functions are prepended with the `simsimd_` namespace prefix.
49
- The signature defines the number of arguments:
50
-
51
- - two pointers, and length,
52
- - two pointers.
53
-
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` |
134
+ ## Using SimSIMD in JavaScript
78
135
 
79
- ## Benchmarks
136
+ After you add `simsimd` as a dependency and `npm install`, you will be able to call SimSIMD function on various `TypedArray` variants:
137
+
138
+ ```js
139
+ const { sqeuclidean, cosine, inner, hamming, jaccard } = require('simsimd');
140
+
141
+ const vectorA = new Float32Array([1.0, 2.0, 3.0]);
142
+ const vectorB = new Float32Array([4.0, 5.0, 6.0]);
143
+
144
+ const distance = sqeuclidean(vectorA, vectorB);
145
+ console.log('Squared Euclidean Distance:', distance);
146
+ ```
147
+
148
+ ## Using SimSIMD in C
149
+
150
+ If you're aiming to utilize the `_Float16` functionality with SimSIMD, ensure your development environment is compatible with C 11. For other functionalities of SimSIMD, C 99 compatibility will suffice.
151
+
152
+ For integration within a CMake-based project, add the following segment to your `CMakeLists.txt`:
153
+
154
+ ```cmake
155
+ FetchContent_Declare(
156
+ simsimd
157
+ GIT_REPOSITORY https://github.com/ashvardanian/simsimd.git
158
+ GIT_SHALLOW TRUE
159
+ )
160
+ FetchContent_MakeAvailable(simsimd)
161
+ include_directories(${simsimd_SOURCE_DIR}/include)
162
+ ```
163
+
164
+ Stay updated with the latest advancements by always using the most recent compiler available for your platform. This ensures that you benefit from the newest intrinsics.
165
+
166
+ Should you wish to integrate SimSIMD within USearch, simply compile USearch with the flag `USEARCH_USE_SIMSIMD=1`. Notably, this is the default setting on the majority of platforms.
167
+
168
+ __To rerun experiments__ utilize the following command:
169
+
170
+ ```sh
171
+ cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build_release && make -C ./build_release && ./build_release/simsimd_bench
172
+ ```
80
173
 
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 cannot saturate all the cores.
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 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:
174
+ __To test and benchmark with Python bindings__:
117
175
 
118
176
  ```sh
119
- git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
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
177
+ pip install -e .
178
+ pytest python/test.py -s -x
179
+ python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions
123
180
  ```
124
181
 
125
- MacOS:
182
+ __To test and benchmark JavaScript bindings__:
126
183
 
127
184
  ```sh
128
- brew install llvm
129
- git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
130
- cmake -B ./build \
131
- -DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
132
- -DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
133
- -DSIMSIMD_BUILD_BENCHMARKS=1 \
134
- && \
135
- make -C ./build -j && ./build/simsimd_bench
185
+ npm install --dev
186
+ npm test
187
+ npm bench
136
188
  ```
137
189
 
138
- Install and test locally:
190
+ __To test and benchmark GoLang bindings__:
139
191
 
140
192
  ```sh
141
- pip install -e . && pytest python/test.py -s -x
193
+ cd golang
194
+ go test # To test
195
+ go test -run=^$ -bench=. -benchmem # To benchmark
142
196
  ```
@@ -0,0 +1,18 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "simsimd",
5
+ "sources": ["javascript/lib.c"],
6
+ "include_dirs": ["include"],
7
+ "cflags": [
8
+ "-std=c11",
9
+ "-ffast-math",
10
+ "-Wno-unknown-pragmas",
11
+ "-Wno-maybe-uninitialized",
12
+ "-Wno-cast-function-type",
13
+ "-Wno-switch",
14
+ "-DSIMSIMD_NATIVE_F16=0",
15
+ ],
16
+ }
17
+ ]
18
+ }