Skip to main content

fpsketch

Compress molecular count fingerprints to a fixed low dimension while (approximately) preserving Tanimoto similarity as a plain dot product.

Given two count fingerprints x, x' (e.g. Morgan fingerprints with counts, {feature_id: count}), the standard chemistry similarity metric is the min-max Tanimoto:

T_MM(x, x') = sum_i min(x_i, x'_i) / sum_i max(x_i, x'_i)

T_MM isn't a dot product, so you can't drop count fingerprints straight into models (nearest-neighbor search, GPs, kernel methods, ...) that expect a plain inner product. fpsketch sketches count fingerprints into a fixed-width dense vector s = encode(x) such that

T_DP(s, s') = s.s' / (||s||^2 + ||s'||^2 - s.s')  ≈  T_MM(x, x')

i.e. an ordinary dot product on the sketch approximates T_MM on the original fingerprints.

Why this works

A unary encoding turns each count into a set of indicators, psi(x)_{i,k} = 1[x_i > k] for k = 0 .. x_i - 1. Since min(u, v) = sum_k 1[u > k] * 1[v > k], this makes T_DP(psi(x), psi(x')) exactly equal to T_MM(x, x') -- no approximation yet, just a reformulation. fpsketch then applies a CountSketch (hashing each (feature_id, level) pair into one of m signed buckets) to that unary expansion, which keeps the dot product unbiased while collapsing it to a fixed, low dimension.

Install

pip install fpsketch          # encode_sparse only, numpy-only
pip install fpsketch[chem]    # + encode_mols, pulls in rdkit

Quickstart

from fpsketch import encode_sparse

# Sparse count fingerprints you already have.
fps = [{1: 1, 2: 2, 3: 3}, {4: 4, 5: 5, 6: 6}]
sketch = encode_sparse(fps, dim=2048, seed=0)

# T_DP as a plain dot product / normalized similarity.
G = sketch @ sketch.T
sq = (sketch**2).sum(axis=1)
similarity = G / (sq[:, None] + sq[None, :] - G)
from rdkit import Chem
from fpsketch import encode_mols

mols = [Chem.MolFromSmiles(s) for s in ["CCO"]]  # your list of SMILES strings
sketch = encode_mols(mols, dim=2048, seed=0)  # defaults to a Morgan(radius=2) generator

If you already have your counts vectorized as a COO sparse array (molecules x features), encode_coo skips the per-molecule dict traversal encode_sparse does internally:

from scipy.sparse import coo_array
from fpsketch import encode_coo

counts = coo_array(...)  # shape (n_molecules, n_features)
sketch = encode_coo(counts, dim=2048, seed=0)

Two sketches are only comparable if built with the same seed.

Choosing dim and num_blocks

dim=2048 is a strong default for typical fingerprint settings. For extra safety margin, dim at 2-4x the fingerprint's effective (unfolded) dimension is a reasonable range to sweep. num_blocks (default 4) splits dim into that many disjoint sub-sketches, each an independent CountSketch; a dot product on the concatenated output is equivalent to averaging the num_blocks per-block dot-product estimates. This trades a small amount of raw accuracy for better tail concentration across single-draw sketches, which matters when a sketch is computed once and fed straight into a downstream model (e.g. a GP) rather than averaged over many random seeds.

The scale parameter

By default (scale=True), the output is divided by sqrt(num_blocks) so that raw dot products and squared norms directly approximate the true, unnormalized dot product / count mass of the original fingerprints -- useful if you compare sketches built with different num_blocks, or use the sketch for anything beyond the T_DP ratio above (cosine similarity, nearest neighbors on raw dot product, etc). That factor cancels out of the T_DP ratio itself, so if you only ever compute Tanimoto similarity through that ratio, scale=False is equivalent and skips one pass over the output array.

Performance note

Hashing is vectorized with numpy (a pure-numpy splitmix64 mixer, not hashlib per element) rather than hashing one (feature, count-level) pair at a time -- see src/fpsketch/sketching.py for details.

Development

uv sync --extra chem
uv run pytest
uv run ruff check .
uv run ruff format .
uv run mypy src
uv run pre-commit install  # run the above automatically on each commit

Releasing

Versions are derived from git tags (hatch-vcs); there is no version to bump by hand. Pushing a tag matching v* (e.g. v0.2.0) triggers .github/workflows/publish.yml, which builds and publishes to PyPI via Trusted Publishing -- no API token needed, but the pypi environment must be configured as a trusted publisher for this repo in the PyPI project settings first.

License

MIT, see LICENSE.

Metadata

Release files for fpsketch 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fpsketch 0.1.0
File Size Uploaded Provenance
fpsketch-0.1.0.tar.gz 104.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fpsketch 0.1.0
File Interpreter ABI Platform
fpsketch-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 116.8 kB

Release files / fpsketch-0.1.0.tar.gz

Download URL fpsketch-0.1.0.tar.gz
Size 104.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6d85fc34794c3f5ecec80fd40c3de06b60aa658d4080bdd697c9841f9108c244
BLAKE2b-256 checksum
How to use checksums
b0e88f16a3f9c539a9618e89523c6cfbc08c0476b2cd310b77f09f97473ae77b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / fpsketch-0.1.0-py3-none-any.whl

Download URL fpsketch-0.1.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a106f807f9d5f817922e4ec7c03fb9a72fd3c1d84ec11b05a9f18771f681f12
BLAKE2b-256 checksum
How to use checksums
33eb4cc7cb2cc8085a62721dfed377ba094f3cd81e4bc55cf5f0a36a1cb29090
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Security for fpsketch 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fpsketch-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page