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.
Files changed (88) hide show
  1. pipnn-0.1.0/.dockerignore +12 -0
  2. pipnn-0.1.0/.github/workflows/ann-isorecall-x86.yml +85 -0
  3. pipnn-0.1.0/.github/workflows/ci.yml +31 -0
  4. pipnn-0.1.0/.github/workflows/pyglass-portable-wheels.yml +62 -0
  5. pipnn-0.1.0/.github/workflows/release.yml +107 -0
  6. pipnn-0.1.0/.gitignore +30 -0
  7. pipnn-0.1.0/Cargo.lock +461 -0
  8. pipnn-0.1.0/Cargo.toml +27 -0
  9. pipnn-0.1.0/LICENSE +21 -0
  10. pipnn-0.1.0/PKG-INFO +107 -0
  11. pipnn-0.1.0/README.md +466 -0
  12. pipnn-0.1.0/README_pypi.md +65 -0
  13. pipnn-0.1.0/RELEASING.md +47 -0
  14. pipnn-0.1.0/bench/ann_isorecall_sift.json +76 -0
  15. pipnn-0.1.0/bench/ann_isorecall_sift.png +0 -0
  16. pipnn-0.1.0/bench/ann_isorecall_sift_x86.json +108 -0
  17. pipnn-0.1.0/bench/ann_isorecall_sift_x86.png +0 -0
  18. pipnn-0.1.0/bench/bench_ann_isorecall.py +306 -0
  19. pipnn-0.1.0/bench/bench_lib.py +183 -0
  20. pipnn-0.1.0/bench/bench_matched_recall.py +180 -0
  21. pipnn-0.1.0/bench/bench_pipnn_vs_hnsw.py +132 -0
  22. pipnn-0.1.0/bench/bench_scaling.py +206 -0
  23. pipnn-0.1.0/bench/bench_scaling_all.py +159 -0
  24. pipnn-0.1.0/bench/bench_tahoe.py +214 -0
  25. pipnn-0.1.0/bench/bench_xcompare.py +94 -0
  26. pipnn-0.1.0/bench/matched_recall.json +46 -0
  27. pipnn-0.1.0/bench/matched_recall.png +0 -0
  28. pipnn-0.1.0/bench/pipnn_vs_hnsw.json +66 -0
  29. pipnn-0.1.0/bench/pipnn_vs_hnsw.png +0 -0
  30. pipnn-0.1.0/bench/scaling.png +0 -0
  31. pipnn-0.1.0/bench/scaling_all.json +162 -0
  32. pipnn-0.1.0/bench/scaling_all.png +0 -0
  33. pipnn-0.1.0/bench/scaling_results.json +74 -0
  34. pipnn-0.1.0/bench/scaling_results_before.json +74 -0
  35. pipnn-0.1.0/bench/tahoe_bench.json +117 -0
  36. pipnn-0.1.0/bench/tahoe_bench.png +0 -0
  37. pipnn-0.1.0/bench/tahoe_dashboard.png +0 -0
  38. pipnn-0.1.0/bench/tahoe_plot_all.py +80 -0
  39. pipnn-0.1.0/bench/tahoe_prep.py +154 -0
  40. pipnn-0.1.0/bench/tahoe_pynndescent.py +70 -0
  41. pipnn-0.1.0/bench/xcompare.json +47 -0
  42. pipnn-0.1.0/bench/xcompare.png +0 -0
  43. pipnn-0.1.0/build_notebook.py +199 -0
  44. pipnn-0.1.0/crates/pipnn-core/Cargo.toml +23 -0
  45. pipnn-0.1.0/crates/pipnn-core/src/batch_query.rs +247 -0
  46. pipnn-0.1.0/crates/pipnn-core/src/bruteforce.rs +66 -0
  47. pipnn-0.1.0/crates/pipnn-core/src/build.rs +268 -0
  48. pipnn-0.1.0/crates/pipnn-core/src/dataset.rs +90 -0
  49. pipnn-0.1.0/crates/pipnn-core/src/graph.rs +67 -0
  50. pipnn-0.1.0/crates/pipnn-core/src/hashprune/hyperplanes.rs +80 -0
  51. pipnn-0.1.0/crates/pipnn-core/src/hashprune/mod.rs +10 -0
  52. pipnn-0.1.0/crates/pipnn-core/src/hashprune/reservoir.rs +124 -0
  53. pipnn-0.1.0/crates/pipnn-core/src/hnsw.rs +419 -0
  54. pipnn-0.1.0/crates/pipnn-core/src/leaf/build.rs +54 -0
  55. pipnn-0.1.0/crates/pipnn-core/src/leaf/gemm.rs +54 -0
  56. pipnn-0.1.0/crates/pipnn-core/src/leaf/mod.rs +8 -0
  57. pipnn-0.1.0/crates/pipnn-core/src/lib.rs +29 -0
  58. pipnn-0.1.0/crates/pipnn-core/src/metric.rs +98 -0
  59. pipnn-0.1.0/crates/pipnn-core/src/params.rs +68 -0
  60. pipnn-0.1.0/crates/pipnn-core/src/partition/ball_carving.rs +243 -0
  61. pipnn-0.1.0/crates/pipnn-core/src/partition/mod.rs +5 -0
  62. pipnn-0.1.0/crates/pipnn-core/src/robust_prune.rs +50 -0
  63. pipnn-0.1.0/crates/pipnn-core/src/search/beam_search.rs +124 -0
  64. pipnn-0.1.0/crates/pipnn-core/src/search/mod.rs +5 -0
  65. pipnn-0.1.0/crates/pipnn-core/tests/determinism.rs +60 -0
  66. pipnn-0.1.0/crates/pipnn-core/tests/recall.rs +119 -0
  67. pipnn-0.1.0/docker/Dockerfile +35 -0
  68. pipnn-0.1.0/docker/docker_compare.py +72 -0
  69. pipnn-0.1.0/notebooks/pipnn_vs_pynndescent.ipynb +518 -0
  70. pipnn-0.1.0/pyproject.toml +52 -0
  71. pipnn-0.1.0/python/pipnn/__init__.py +11 -0
  72. pipnn-0.1.0/python/pipnn/contrib/__init__.py +12 -0
  73. pipnn-0.1.0/python/pipnn/contrib/faiss.py +186 -0
  74. pipnn-0.1.0/python/pipnn/contrib/glass.py +194 -0
  75. pipnn-0.1.0/python/pipnn/contrib/hnsw.py +107 -0
  76. pipnn-0.1.0/python/pipnn/index.py +128 -0
  77. pipnn-0.1.0/python/pipnn/transformer.py +145 -0
  78. pipnn-0.1.0/src/lib.rs +447 -0
  79. pipnn-0.1.0/tests/bench_real.py +45 -0
  80. pipnn-0.1.0/tests/bench_vs_pynndescent.py +41 -0
  81. pipnn-0.1.0/tests/test_backends.py +113 -0
  82. pipnn-0.1.0/tests/test_query.py +66 -0
  83. pipnn-0.1.0/tests/test_recall_sklearn.py +63 -0
  84. pipnn-0.1.0/tests/test_scanpy_e2e.py +48 -0
  85. pipnn-0.1.0/tests/test_transformer_contract.py +73 -0
  86. pipnn-0.1.0/tools/pyglass-portable/README.md +98 -0
  87. pipnn-0.1.0/tools/pyglass-portable/build_wheel.sh +55 -0
  88. pipnn-0.1.0/tools/pyglass-portable/portable.patch +180 -0
@@ -0,0 +1,12 @@
1
+ target/
2
+ .venv/
3
+ .git/
4
+ pages/
5
+ *.pdf
6
+ *.h5ad
7
+ *.npy
8
+ __pycache__/
9
+ .pytest_cache/
10
+ .ipynb_checkpoints/
11
+ notebooks/
12
+ docker/out/
@@ -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/