pipnn 0.1.0__tar.gz
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.
- pipnn-0.1.0/.dockerignore +12 -0
- pipnn-0.1.0/.github/workflows/ann-isorecall-x86.yml +85 -0
- pipnn-0.1.0/.github/workflows/ci.yml +31 -0
- pipnn-0.1.0/.github/workflows/pyglass-portable-wheels.yml +62 -0
- pipnn-0.1.0/.github/workflows/release.yml +107 -0
- pipnn-0.1.0/.gitignore +30 -0
- pipnn-0.1.0/Cargo.lock +461 -0
- pipnn-0.1.0/Cargo.toml +27 -0
- pipnn-0.1.0/LICENSE +21 -0
- pipnn-0.1.0/PKG-INFO +107 -0
- pipnn-0.1.0/README.md +466 -0
- pipnn-0.1.0/README_pypi.md +65 -0
- pipnn-0.1.0/RELEASING.md +47 -0
- pipnn-0.1.0/bench/ann_isorecall_sift.json +76 -0
- pipnn-0.1.0/bench/ann_isorecall_sift.png +0 -0
- pipnn-0.1.0/bench/ann_isorecall_sift_x86.json +108 -0
- pipnn-0.1.0/bench/ann_isorecall_sift_x86.png +0 -0
- pipnn-0.1.0/bench/bench_ann_isorecall.py +306 -0
- pipnn-0.1.0/bench/bench_lib.py +183 -0
- pipnn-0.1.0/bench/bench_matched_recall.py +180 -0
- pipnn-0.1.0/bench/bench_pipnn_vs_hnsw.py +132 -0
- pipnn-0.1.0/bench/bench_scaling.py +206 -0
- pipnn-0.1.0/bench/bench_scaling_all.py +159 -0
- pipnn-0.1.0/bench/bench_tahoe.py +214 -0
- pipnn-0.1.0/bench/bench_xcompare.py +94 -0
- pipnn-0.1.0/bench/matched_recall.json +46 -0
- pipnn-0.1.0/bench/matched_recall.png +0 -0
- pipnn-0.1.0/bench/pipnn_vs_hnsw.json +66 -0
- pipnn-0.1.0/bench/pipnn_vs_hnsw.png +0 -0
- pipnn-0.1.0/bench/scaling.png +0 -0
- pipnn-0.1.0/bench/scaling_all.json +162 -0
- pipnn-0.1.0/bench/scaling_all.png +0 -0
- pipnn-0.1.0/bench/scaling_results.json +74 -0
- pipnn-0.1.0/bench/scaling_results_before.json +74 -0
- pipnn-0.1.0/bench/tahoe_bench.json +117 -0
- pipnn-0.1.0/bench/tahoe_bench.png +0 -0
- pipnn-0.1.0/bench/tahoe_dashboard.png +0 -0
- pipnn-0.1.0/bench/tahoe_plot_all.py +80 -0
- pipnn-0.1.0/bench/tahoe_prep.py +154 -0
- pipnn-0.1.0/bench/tahoe_pynndescent.py +70 -0
- pipnn-0.1.0/bench/xcompare.json +47 -0
- pipnn-0.1.0/bench/xcompare.png +0 -0
- pipnn-0.1.0/build_notebook.py +199 -0
- pipnn-0.1.0/crates/pipnn-core/Cargo.toml +23 -0
- pipnn-0.1.0/crates/pipnn-core/src/batch_query.rs +247 -0
- pipnn-0.1.0/crates/pipnn-core/src/bruteforce.rs +66 -0
- pipnn-0.1.0/crates/pipnn-core/src/build.rs +268 -0
- pipnn-0.1.0/crates/pipnn-core/src/dataset.rs +90 -0
- pipnn-0.1.0/crates/pipnn-core/src/graph.rs +67 -0
- pipnn-0.1.0/crates/pipnn-core/src/hashprune/hyperplanes.rs +80 -0
- pipnn-0.1.0/crates/pipnn-core/src/hashprune/mod.rs +10 -0
- pipnn-0.1.0/crates/pipnn-core/src/hashprune/reservoir.rs +124 -0
- pipnn-0.1.0/crates/pipnn-core/src/hnsw.rs +419 -0
- pipnn-0.1.0/crates/pipnn-core/src/leaf/build.rs +54 -0
- pipnn-0.1.0/crates/pipnn-core/src/leaf/gemm.rs +54 -0
- pipnn-0.1.0/crates/pipnn-core/src/leaf/mod.rs +8 -0
- pipnn-0.1.0/crates/pipnn-core/src/lib.rs +29 -0
- pipnn-0.1.0/crates/pipnn-core/src/metric.rs +98 -0
- pipnn-0.1.0/crates/pipnn-core/src/params.rs +68 -0
- pipnn-0.1.0/crates/pipnn-core/src/partition/ball_carving.rs +243 -0
- pipnn-0.1.0/crates/pipnn-core/src/partition/mod.rs +5 -0
- pipnn-0.1.0/crates/pipnn-core/src/robust_prune.rs +50 -0
- pipnn-0.1.0/crates/pipnn-core/src/search/beam_search.rs +124 -0
- pipnn-0.1.0/crates/pipnn-core/src/search/mod.rs +5 -0
- pipnn-0.1.0/crates/pipnn-core/tests/determinism.rs +60 -0
- pipnn-0.1.0/crates/pipnn-core/tests/recall.rs +119 -0
- pipnn-0.1.0/docker/Dockerfile +35 -0
- pipnn-0.1.0/docker/docker_compare.py +72 -0
- pipnn-0.1.0/notebooks/pipnn_vs_pynndescent.ipynb +518 -0
- pipnn-0.1.0/pyproject.toml +52 -0
- pipnn-0.1.0/python/pipnn/__init__.py +11 -0
- pipnn-0.1.0/python/pipnn/contrib/__init__.py +12 -0
- pipnn-0.1.0/python/pipnn/contrib/faiss.py +186 -0
- pipnn-0.1.0/python/pipnn/contrib/glass.py +194 -0
- pipnn-0.1.0/python/pipnn/contrib/hnsw.py +107 -0
- pipnn-0.1.0/python/pipnn/index.py +128 -0
- pipnn-0.1.0/python/pipnn/transformer.py +145 -0
- pipnn-0.1.0/src/lib.rs +447 -0
- pipnn-0.1.0/tests/bench_real.py +45 -0
- pipnn-0.1.0/tests/bench_vs_pynndescent.py +41 -0
- pipnn-0.1.0/tests/test_backends.py +113 -0
- pipnn-0.1.0/tests/test_query.py +66 -0
- pipnn-0.1.0/tests/test_recall_sklearn.py +63 -0
- pipnn-0.1.0/tests/test_scanpy_e2e.py +48 -0
- pipnn-0.1.0/tests/test_transformer_contract.py +73 -0
- pipnn-0.1.0/tools/pyglass-portable/README.md +98 -0
- pipnn-0.1.0/tools/pyglass-portable/build_wheel.sh +55 -0
- pipnn-0.1.0/tools/pyglass-portable/portable.patch +180 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
name: ANN iso-recall (x86, with pyglass)
|
|
2
|
+
|
|
3
|
+
# Manual-only: builds the PiPNN extension on x86_64 Linux, installs pyglass
|
|
4
|
+
# (glassppy — manylinux x86_64 / CPython 3.10 only, can't run on the arm64 dev
|
|
5
|
+
# machine) alongside FAISS, and runs bench/bench_ann_isorecall.py to produce a
|
|
6
|
+
# real PiPNN vs pyglass vs FAISS recall-QPS + build-time figure. Artifacts: the
|
|
7
|
+
# png + json. Trigger: Actions tab → this workflow → Run, or `gh workflow run`.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
dataset:
|
|
13
|
+
description: "ANN-benchmark dataset"
|
|
14
|
+
type: choice
|
|
15
|
+
options: [sift, gist]
|
|
16
|
+
default: sift
|
|
17
|
+
n_sub:
|
|
18
|
+
description: "Subsample base to this many points (0 = full 1M)"
|
|
19
|
+
type: string
|
|
20
|
+
default: "200000"
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
isorecall:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
# Informational: pyglass is built from source for the runner's own arch
|
|
29
|
+
# (-march=native), so AVX2 is enough — no AVX-512 needed.
|
|
30
|
+
- name: Runner CPU SIMD flags
|
|
31
|
+
run: |
|
|
32
|
+
echo "avx2: $(grep -c avx2 /proc/cpuinfo || true) avx512f: $(grep -c avx512f /proc/cpuinfo || true)"
|
|
33
|
+
grep -m1 -o 'model name.*' /proc/cpuinfo || true
|
|
34
|
+
|
|
35
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
36
|
+
|
|
37
|
+
# glassppy ships only as a CPython 3.10 manylinux x86_64 wheel.
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.10"
|
|
41
|
+
|
|
42
|
+
# Cache the (large) ann-benchmarks hdf5 + recomputed ground truth.
|
|
43
|
+
- name: Cache dataset
|
|
44
|
+
uses: actions/cache@v4
|
|
45
|
+
with:
|
|
46
|
+
path: bench/data
|
|
47
|
+
key: ann-data-${{ inputs.dataset }}
|
|
48
|
+
|
|
49
|
+
- name: Build extension + install backends
|
|
50
|
+
run: |
|
|
51
|
+
python -m venv .venv
|
|
52
|
+
. .venv/bin/activate
|
|
53
|
+
python -m pip install --upgrade pip maturin
|
|
54
|
+
pip install numpy scipy scikit-learn matplotlib h5py faiss-cpu pybind11 setuptools wheel
|
|
55
|
+
maturin develop --release
|
|
56
|
+
# pyglass: build FROM SOURCE (installs as `glass`), not the PyPI wheel.
|
|
57
|
+
# The wheel is compiled for AVX-512 and SIGILLs on GitHub's AMD EPYC
|
|
58
|
+
# runners (no AVX-512); the source build uses `-march=native`, so it
|
|
59
|
+
# targets the runner's own AVX2 and runs. Non-fatal — the harness still
|
|
60
|
+
# emits a PiPNN-vs-FAISS curve if this fails.
|
|
61
|
+
git clone --depth 1 https://github.com/zilliztech/pyglass.git /tmp/pyglass || true
|
|
62
|
+
if [ -d /tmp/pyglass/python ]; then
|
|
63
|
+
# build in-place (no isolation): setup.py references ../glass, ../third_party
|
|
64
|
+
( cd /tmp/pyglass/python && python setup.py bdist_wheel && pip install dist/*.whl ) \
|
|
65
|
+
|| echo "::warning::pyglass source build failed; arm will be skipped"
|
|
66
|
+
fi
|
|
67
|
+
python -c "import glass; print('glass source build OK', getattr(glass,'__version__','?'))" \
|
|
68
|
+
|| echo "::warning::pyglass ('glass') not importable; arm will be skipped"
|
|
69
|
+
|
|
70
|
+
- name: Run iso-recall harness
|
|
71
|
+
run: |
|
|
72
|
+
. .venv/bin/activate
|
|
73
|
+
# -u: unbuffered, so PiPNN/FAISS results reach the log even if the
|
|
74
|
+
# isolated pyglass child SIGILLs on an unsupported instruction set.
|
|
75
|
+
python -u bench/bench_ann_isorecall.py --dataset "${{ inputs.dataset }}" --n-sub "${{ inputs.n_sub }}"
|
|
76
|
+
|
|
77
|
+
- name: Upload results
|
|
78
|
+
if: always() # PiPNN-vs-FAISS artifact is written before the pyglass arm
|
|
79
|
+
uses: actions/upload-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: ann-isorecall-${{ inputs.dataset }}
|
|
82
|
+
if-no-files-found: warn
|
|
83
|
+
path: |
|
|
84
|
+
bench/ann_isorecall_${{ inputs.dataset }}.png
|
|
85
|
+
bench/ann_isorecall_${{ inputs.dataset }}.json
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Cargo tests (core crate)
|
|
22
|
+
run: cargo test -p pipnn-core --release
|
|
23
|
+
|
|
24
|
+
- name: Build extension + run Python tests
|
|
25
|
+
run: |
|
|
26
|
+
python -m venv .venv
|
|
27
|
+
. .venv/bin/activate
|
|
28
|
+
python -m pip install --upgrade pip maturin
|
|
29
|
+
pip install numpy scipy scikit-learn scanpy anndata igraph leidenalg pynndescent faiss-cpu pytest
|
|
30
|
+
maturin develop --release
|
|
31
|
+
pytest tests/ -q
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: pyglass-portable wheels
|
|
2
|
+
|
|
3
|
+
# Builds portable pyglass wheels (AVX2 on x86, NEON on arm64) from
|
|
4
|
+
# tools/pyglass-portable/portable.patch, across a multi-OS/arch matrix, and
|
|
5
|
+
# uploads them as artifacts. Proves one wheel per arch runs on that whole arch —
|
|
6
|
+
# unlike upstream's AVX-512-only `glassppy` wheel. Manual trigger.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
wheels:
|
|
13
|
+
name: ${{ matrix.label }}
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
include:
|
|
19
|
+
- {os: ubuntu-latest, label: "linux-x86_64 (AVX2)"}
|
|
20
|
+
- {os: macos-14, label: "macos-arm64 (NEON)"}
|
|
21
|
+
- {os: macos-13, label: "macos-x86_64 (AVX2)"}
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
|
|
29
|
+
- name: CPU SIMD flags (informational)
|
|
30
|
+
run: |
|
|
31
|
+
if [ "$(uname -s)" = "Linux" ]; then
|
|
32
|
+
echo "avx2: $(grep -c avx2 /proc/cpuinfo) avx512f: $(grep -c avx512f /proc/cpuinfo)"
|
|
33
|
+
grep -m1 -o 'model name.*' /proc/cpuinfo || true
|
|
34
|
+
else
|
|
35
|
+
sysctl -n machdep.cpu.brand_string 2>/dev/null || true
|
|
36
|
+
echo "arch: $(uname -m)"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
- name: Build portable wheel
|
|
40
|
+
run: |
|
|
41
|
+
python -m pip install --upgrade pip
|
|
42
|
+
PYTHON="$(which python)" bash tools/pyglass-portable/build_wheel.sh "$PWD/wheelhouse"
|
|
43
|
+
|
|
44
|
+
- name: Smoke-test the wheel (import + build + search)
|
|
45
|
+
run: |
|
|
46
|
+
python -m pip install numpy scikit-learn
|
|
47
|
+
python -m pip install --force-reinstall wheelhouse/glass-*.whl
|
|
48
|
+
python - <<'PY'
|
|
49
|
+
import numpy as np, glass, platform, time
|
|
50
|
+
b = np.ascontiguousarray(np.random.default_rng(0).normal(size=(20000, 96)).astype(np.float32))
|
|
51
|
+
i = glass.Index("HNSW", "L2", "FP32", 32, 200); g = i.build(b)
|
|
52
|
+
s = glass.Searcher(g, b, "L2", "FP32"); s.set_ef(64); s.optimize()
|
|
53
|
+
t = time.perf_counter(); ids, _ = s.batch_search(b[:500], 10); dt = time.perf_counter() - t
|
|
54
|
+
print(f"OK pyglass on {platform.machine()}: {500/dt:.0f} q/s")
|
|
55
|
+
PY
|
|
56
|
+
|
|
57
|
+
- name: Upload wheels
|
|
58
|
+
uses: actions/upload-artifact@v4
|
|
59
|
+
with:
|
|
60
|
+
name: pyglass-portable-${{ matrix.os }}
|
|
61
|
+
path: wheelhouse/glass-*.whl
|
|
62
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
# Builds abi3 wheels (one per platform serves Python 3.9+) for Linux, macOS, and
|
|
4
|
+
# Windows, plus an sdist, and publishes them to PyPI on a version tag via PyPI
|
|
5
|
+
# Trusted Publishing (no API token stored). Tag a release: `git tag v0.1.0 &&
|
|
6
|
+
# git push --tags`. workflow_dispatch runs the build only (no publish) as a dry run.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
linux:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
target: [x86_64, aarch64]
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
- name: Build wheels (manylinux, abi3)
|
|
29
|
+
uses: PyO3/maturin-action@v1
|
|
30
|
+
with:
|
|
31
|
+
target: ${{ matrix.target }}
|
|
32
|
+
manylinux: auto
|
|
33
|
+
args: --release --out dist
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: wheels-linux-${{ matrix.target }}
|
|
37
|
+
path: dist
|
|
38
|
+
|
|
39
|
+
macos:
|
|
40
|
+
runs-on: macos-14
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
target: [aarch64, x86_64]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
- name: Build wheel (abi3)
|
|
51
|
+
uses: PyO3/maturin-action@v1
|
|
52
|
+
with:
|
|
53
|
+
target: ${{ matrix.target }}
|
|
54
|
+
args: --release --out dist
|
|
55
|
+
- uses: actions/upload-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: wheels-macos-${{ matrix.target }}
|
|
58
|
+
path: dist
|
|
59
|
+
|
|
60
|
+
windows:
|
|
61
|
+
runs-on: windows-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
- uses: actions/setup-python@v5
|
|
65
|
+
with:
|
|
66
|
+
python-version: "3.12"
|
|
67
|
+
- name: Build wheel (abi3)
|
|
68
|
+
uses: PyO3/maturin-action@v1
|
|
69
|
+
with:
|
|
70
|
+
target: x64
|
|
71
|
+
args: --release --out dist
|
|
72
|
+
- uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: wheels-windows
|
|
75
|
+
path: dist
|
|
76
|
+
|
|
77
|
+
sdist:
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@v4
|
|
81
|
+
- name: Build sdist
|
|
82
|
+
uses: PyO3/maturin-action@v1
|
|
83
|
+
with:
|
|
84
|
+
command: sdist
|
|
85
|
+
args: --out dist
|
|
86
|
+
- uses: actions/upload-artifact@v4
|
|
87
|
+
with:
|
|
88
|
+
name: sdist
|
|
89
|
+
path: dist
|
|
90
|
+
|
|
91
|
+
publish:
|
|
92
|
+
name: Publish to PyPI
|
|
93
|
+
needs: [linux, macos, windows, sdist]
|
|
94
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
environment: pypi
|
|
97
|
+
permissions:
|
|
98
|
+
id-token: write # required for PyPI Trusted Publishing
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/download-artifact@v4
|
|
101
|
+
with:
|
|
102
|
+
path: dist
|
|
103
|
+
merge-multiple: true
|
|
104
|
+
- name: Publish
|
|
105
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
106
|
+
with:
|
|
107
|
+
packages-dir: dist
|
pipnn-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Rust
|
|
2
|
+
/target
|
|
3
|
+
**/*.rs.bk
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
.venv/
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*.so
|
|
10
|
+
*.egg-info/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.ipynb_checkpoints/
|
|
13
|
+
|
|
14
|
+
# Paper (cite arXiv:2602.21247 instead of redistributing)
|
|
15
|
+
PiPNN.pdf
|
|
16
|
+
/pages/
|
|
17
|
+
|
|
18
|
+
# Data
|
|
19
|
+
*.h5ad
|
|
20
|
+
*.npy
|
|
21
|
+
# ANN-benchmark dataset cache (SIFT/GIST hdf5, ~0.5–3.6 GB each)
|
|
22
|
+
bench/data/
|
|
23
|
+
|
|
24
|
+
# Docker bench outputs
|
|
25
|
+
docker/out/
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
# Tahoe-100M dataset cache (parquet shards + PCA embedding, multi-GB)
|
|
30
|
+
bench/tahoe_cache/
|