npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sroussey/simsimd

v3.6.25

Published

Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm

Downloads

35

Readme

SimSIMD 📏

Hardware-Accelerated Similarity Metrics and Distance Functions

  • Zero-dependency header-only C 99 library with bindings for Python and JavaScript.
  • Targets ARM NEON, SVE, x86 AVX2, AVX-512 (VNNI, FP16) hardware backends.
  • Zero-copy compatible with NumPy, PyTorch, TensorFlow, and other tensors.
  • Handles f64 double-, f32 single-, and f16 half-precision, i8 integral, and binary vectors.
  • Up to 200x faster than scipy.spatial.distance and numpy.inner.
  • Used in USearch and several DBMS products.

Implemented distance functions include:

  • Euclidean (L2), Inner Product, and Cosine (Angular) spatial distances.
  • Hamming (~ Manhattan) and Jaccard (~ Tanimoto) binary distances.
  • Kullback-Leibler and Jensen–Shannon divergences for probability distributions.

Technical Insights and related articles:

Benchmarks

Apple M2 Pro

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:

| Kind | f32 improvement | f16 improvement | i8 improvement | Conventional method | SimSIMD | | :------------- | ----------------: | ----------------: | ---------------: | :------------------------------------- | :-------------- | | Cosine | 32 x | 79 x | 133 x | scipy.spatial.distance.cosine | cosine | | Euclidean ² | 5 x | 26 x | 17 x | scipy.spatial.distance.sqeuclidean | sqeuclidean | | Inner Product | 2 x | 9 x | 18 x | numpy.inner | inner | | Jensen Shannon | 31 x | 53 x | | scipy.spatial.distance.jensenshannon | jensenshannon |

Intel Sapphire Rapids

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.

| Kind | GCC 12 f32 | GCC 12 f16 | SimSIMD f16 | f16 improvement | | :------------- | -----------: | -----------: | ------------: | ----------------: | | Cosine | 3.28 M/s | 336.29 k/s | 6.88 M/s | 20 x | | Euclidean ² | 4.62 M/s | 147.25 k/s | 5.32 M/s | 36 x | | Inner Product | 3.81 M/s | 192.02 k/s | 5.99 M/s | 31 x | | Jensen Shannon | 1.18 M/s | 18.13 k/s | 2.14 M/s | 118 x |

Broader Benchmarking Results:

Using SimSIMD in Python

Installation

pip install simsimd

Distance Between 2 Vectors

import simsimd
import numpy as np

vec1 = np.random.randn(1536).astype(np.float32)
vec2 = np.random.randn(1536).astype(np.float32)
dist = simsimd.cosine(vec1, vec2)

Supported functions include cosine, inner, sqeuclidean, hamming, and jaccard.

Distance Between 2 Batches

batch1 = np.random.randn(100, 1536).astype(np.float32)
batch2 = np.random.randn(100, 1536).astype(np.float32)
dist = simsimd.cosine(batch1, batch2)

If either batch has more than one vector, the other batch must have one or the same number of vectors. If it contains just one, the value is broadcasted.

All Pairwise Distances

For calculating distances between all possible pairs of rows across two matrices (akin to scipy.spatial.distance.cdist):

matrix1 = np.random.randn(1000, 1536).astype(np.float32)
matrix2 = np.random.randn(10, 1536).astype(np.float32)
distances = simsimd.cdist(matrix1, matrix2, metric="cosine")

Multithreading

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:

distances = simsimd.cdist(matrix1, matrix2, metric="cosine", threads=0)

Hardware Backend Capabilities

To view a list of hardware backends that SimSIMD supports:

print(simsimd.get_capabilities())

Using Python API with USearch

Want to use it in Python with USearch? 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.

from usearch.index import Index, CompiledMetric, MetricKind, MetricSignature
from simsimd import pointer_to_sqeuclidean, pointer_to_cosine, pointer_to_inner

metric = CompiledMetric(
    pointer=pointer_to_cosine("f16"),
    kind=MetricKind.Cos,
    signature=MetricSignature.ArrayArraySize,
)

index = Index(256, metric=metric)

Using SimSIMD in JavaScript

To install, choose one of the following options depending on your environment:

  • npm install --save simsimd
  • yarn add simsimd
  • pnpm add simsimd
  • bun install simsimd

The package is distributed with prebuilt binaries for Node.js v10 and above for Linux (x86_64, arm64), macOS (x86_64, arm64), and Windows (i386,x86_64).

If your platform is not supported, you can build the package from source via npm run build. This will automatically happen unless you install the package with --ignore-scripts flag or use Bun.

After you install it, you will be able to call the SimSIMD functions on various TypedArray variants:

const { sqeuclidean, cosine, inner, hamming, jaccard } = require('simsimd');

const vectorA = new Float32Array([1.0, 2.0, 3.0]);
const vectorB = new Float32Array([4.0, 5.0, 6.0]);

const distance = sqeuclidean(vectorA, vectorB);
console.log('Squared Euclidean Distance:', distance);

Using SimSIMD in C

For integration within a CMake-based project, add the following segment to your CMakeLists.txt:

FetchContent_Declare(
    simsimd
    GIT_REPOSITORY https://github.com/ashvardanian/simsimd.git
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(simsimd)

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. A minimal usage example would be:

#include <simsimd/simsimd.h>

int main() {
    simsimd_f32_t vector_a[1536];
    simsimd_f32_t vector_b[1536];
    simsimd_f32_t distance = simsimd_avx512_f32_cos(vector_a, vector_b, 1536);
    return 0;
}

All of the functions names follow the same pattern: simsimd_{backend}_{type}_{metric}.

  • The backend can be avx512, avx2, neon, or sve.
  • The type can be f64, f32, f16, i8, or b8.
  • The metric can be cos, ip, l2sq, hamming, jaccard, kl, or js.

In case you want to avoid hard-coding the backend, you can use the simsimd_metric_punned_t to pun the function pointer, and simsimd_capabilities function to get the available backends at runtime.

Benchmarking and Contributing

To rerun experiments utilize the following command:

cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build_release
cmake --build build_release --config Release
./build_release/simsimd_bench
./build_release/simsimd_bench --benchmark_filter=js

To test and benchmark with Python bindings:

pip install -e .
pytest python/test.py -s -x 

pip install numpy scipy scikit-learn # for comparison baselines
python python/bench.py # to run default benchmarks
python python/bench.py --n 1000 --ndim 1000000 # batch size and dimensions

To test and benchmark JavaScript bindings:

npm install --dev
npm test
npm run bench

To test and benchmark GoLang bindings:

cd golang
go test # To test
go test -run=^$ -bench=. -benchmem # To benchmark