vector-engine 1.0.2__tar.gz → 1.1.1__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 (51) hide show
  1. {vector_engine-1.0.2/vector_engine.egg-info → vector_engine-1.1.1}/PKG-INFO +29 -5
  2. vector_engine-1.0.2/PKG-INFO → vector_engine-1.1.1/README.md +14 -22
  3. vector_engine-1.1.1/pyproject.toml +50 -0
  4. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_core.py +14 -0
  5. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_dataset_benchmark_tooling.py +95 -2
  6. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_ingest_pipeline.py +16 -0
  7. vector_engine-1.1.1/tests/test_matrix_profile_advisor.py +24 -0
  8. vector_engine-1.1.1/tests/test_release_performance_workflow.py +125 -0
  9. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/__init__.py +1 -1
  10. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/backends/base.py +3 -0
  11. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/backends/bruteforce.py +14 -0
  12. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/backends/faiss_backend.py +13 -0
  13. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/index.py +31 -0
  14. vector_engine-1.0.2/README.md → vector_engine-1.1.1/vector_engine.egg-info/PKG-INFO +46 -4
  15. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine.egg-info/SOURCES.txt +2 -0
  16. vector_engine-1.0.2/pyproject.toml +0 -32
  17. {vector_engine-1.0.2 → vector_engine-1.1.1}/LICENSE +0 -0
  18. {vector_engine-1.0.2 → vector_engine-1.1.1}/setup.cfg +0 -0
  19. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_api_stability.py +0 -0
  20. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_artifact_contracts.py +0 -0
  21. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_credibility_audit.py +0 -0
  22. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_env_diagnostics.py +0 -0
  23. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_eval_surface_v1.py +0 -0
  24. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_faiss_optional.py +0 -0
  25. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_hardening.py +0 -0
  26. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_install_smoke.py +0 -0
  27. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_ml_eval.py +0 -0
  28. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_perf_smoke.py +0 -0
  29. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_persistence_compat.py +0 -0
  30. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_profile_local.py +0 -0
  31. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_rag_reliability.py +0 -0
  32. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_real_corpus_eval.py +0 -0
  33. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_release_bundle.py +0 -0
  34. {vector_engine-1.0.2 → vector_engine-1.1.1}/tests/test_v02_features.py +0 -0
  35. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/array.py +0 -0
  36. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/backends/__init__.py +0 -0
  37. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/backends/registry.py +0 -0
  38. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/eval/__init__.py +0 -0
  39. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/eval/retrieval.py +0 -0
  40. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/io/__init__.py +0 -0
  41. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/io/manifest.py +0 -0
  42. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/metric.py +0 -0
  43. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/ml/__init__.py +0 -0
  44. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/ml/clustering.py +0 -0
  45. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/ml/knn.py +0 -0
  46. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/results.py +0 -0
  47. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/training/__init__.py +0 -0
  48. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine/training/hard_negative.py +0 -0
  49. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine.egg-info/dependency_links.txt +0 -0
  50. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine.egg-info/requires.txt +0 -0
  51. {vector_engine-1.0.2 → vector_engine-1.1.1}/vector_engine.egg-info/top_level.txt +0 -0
@@ -1,9 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vector-engine
3
- Version: 1.0.2
3
+ Version: 1.1.1
4
4
  Summary: ML-first vector computation and retrieval engine.
5
5
  Author: Neel Panchal
6
6
  License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/neelpanchal11/Vector-Engine
8
+ Project-URL: Repository, https://github.com/neelpanchal11/Vector-Engine
9
+ Project-URL: Issues, https://github.com/neelpanchal11/Vector-Engine/issues
10
+ Project-URL: Documentation, https://github.com/neelpanchal11/Vector-Engine/tree/main/docs
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
7
21
  Requires-Python: >=3.10
8
22
  Description-Content-Type: text/markdown
9
23
  License-File: LICENSE
@@ -16,7 +30,7 @@ Provides-Extra: dev
16
30
  Requires-Dist: pytest<9,>=8.2; extra == "dev"
17
31
  Dynamic: license-file
18
32
 
19
- # Vector Engine v1.0.0
33
+ # Vector Engine v1.1.1
20
34
 
21
35
  Reproducibility-first vector retrieval toolkit for local ML and IR workflows.
22
36
 
@@ -95,7 +109,17 @@ results = index.search(xq, k=5)
95
109
  print(results.ids[0], results.scores[0])
96
110
  ```
97
111
 
98
- ## v1.0.0 Surface
112
+ ## Colab Demos
113
+
114
+ Each notebook opens directly from this repo, so it always matches the current release.
115
+
116
+ - Semantic search: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/01_semantic_search.ipynb)
117
+ - kNN baseline classifier: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/02_knn_baseline.ipynb)
118
+ - Item-item recommender similarity: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/03_recommender_similarity.ipynb)
119
+
120
+ `notebooks/04_stability_runs.ipynb` analyzes locally generated benchmark artifacts (see [Reproducibility and Evidence](#reproducibility-and-evidence)) and is not a standalone Colab demo.
121
+
122
+ ## v1.1.0 Surface
99
123
 
100
124
  - Core: `VectorArray`, `VectorIndex`, `Metric`, `SearchResult`
101
125
  - ML: `knn_classify`, `knn_regress`, `kmeans`, `KMeansResult`
@@ -192,8 +216,8 @@ python scripts/credibility_audit.py --matrix-summary artifacts/benchmark_matrix/
192
216
 
193
217
  ## Project Links
194
218
 
195
- - `docs/releases/v1.0.0.md`
196
- - `docs/releases/v1.0.0-checklist.md`
219
+ - `docs/releases/v1.1.0.md`
220
+ - `docs/releases/v1.1.0-checklist.md`
197
221
  - `docs/reproducibility.md`
198
222
  - `docs/use_cases.md`
199
223
  - `docs/api_stability.md`
@@ -1,22 +1,4 @@
1
- Metadata-Version: 2.4
2
- Name: vector-engine
3
- Version: 1.0.2
4
- Summary: ML-first vector computation and retrieval engine.
5
- Author: Neel Panchal
6
- License-Expression: MIT
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: numpy<2.0,>=1.26.4
11
- Provides-Extra: faiss
12
- Requires-Dist: faiss-cpu>=1.7.4; (platform_system != "Darwin" or platform_machine != "arm64") and extra == "faiss"
13
- Provides-Extra: ml
14
- Requires-Dist: scikit-learn<1.7,>=1.4; extra == "ml"
15
- Provides-Extra: dev
16
- Requires-Dist: pytest<9,>=8.2; extra == "dev"
17
- Dynamic: license-file
18
-
19
- # Vector Engine v1.0.0
1
+ # Vector Engine v1.1.1
20
2
 
21
3
  Reproducibility-first vector retrieval toolkit for local ML and IR workflows.
22
4
 
@@ -95,7 +77,17 @@ results = index.search(xq, k=5)
95
77
  print(results.ids[0], results.scores[0])
96
78
  ```
97
79
 
98
- ## v1.0.0 Surface
80
+ ## Colab Demos
81
+
82
+ Each notebook opens directly from this repo, so it always matches the current release.
83
+
84
+ - Semantic search: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/01_semantic_search.ipynb)
85
+ - kNN baseline classifier: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/02_knn_baseline.ipynb)
86
+ - Item-item recommender similarity: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/03_recommender_similarity.ipynb)
87
+
88
+ `notebooks/04_stability_runs.ipynb` analyzes locally generated benchmark artifacts (see [Reproducibility and Evidence](#reproducibility-and-evidence)) and is not a standalone Colab demo.
89
+
90
+ ## v1.1.0 Surface
99
91
 
100
92
  - Core: `VectorArray`, `VectorIndex`, `Metric`, `SearchResult`
101
93
  - ML: `knn_classify`, `knn_regress`, `kmeans`, `KMeansResult`
@@ -192,8 +184,8 @@ python scripts/credibility_audit.py --matrix-summary artifacts/benchmark_matrix/
192
184
 
193
185
  ## Project Links
194
186
 
195
- - `docs/releases/v1.0.0.md`
196
- - `docs/releases/v1.0.0-checklist.md`
187
+ - `docs/releases/v1.1.0.md`
188
+ - `docs/releases/v1.1.0-checklist.md`
197
189
  - `docs/reproducibility.md`
198
190
  - `docs/use_cases.md`
199
191
  - `docs/api_stability.md`
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vector-engine"
7
+ version = "1.1.1"
8
+ description = "ML-first vector computation and retrieval engine."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "Neel Panchal" }
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Science/Research",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ ]
27
+ dependencies = [
28
+ "numpy>=1.26.4,<2.0",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ faiss = [
33
+ "faiss-cpu>=1.7.4; platform_system != 'Darwin' or platform_machine != 'arm64'",
34
+ ]
35
+ ml = [
36
+ "scikit-learn>=1.4,<1.7",
37
+ ]
38
+ dev = [
39
+ "pytest>=8.2,<9",
40
+ ]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/neelpanchal11/Vector-Engine"
44
+ Repository = "https://github.com/neelpanchal11/Vector-Engine"
45
+ Issues = "https://github.com/neelpanchal11/Vector-Engine/issues"
46
+ Documentation = "https://github.com/neelpanchal11/Vector-Engine/tree/main/docs"
47
+
48
+ [tool.setuptools.packages.find]
49
+ where = ["."]
50
+ include = ["vector_engine*"]
@@ -37,3 +37,17 @@ def test_index_save_and_load_roundtrip(tmp_path):
37
37
  loaded = VectorIndex.load(str(path))
38
38
  second = loaded.search(xq, k=4)
39
39
  assert np.array_equal(first.ids, second.ids)
40
+
41
+
42
+ def test_index_backend_capabilities_and_runtime_stats():
43
+ xb = VectorArray.from_numpy(np.random.randn(16, 4).astype(np.float32), ids=np.arange(16))
44
+ xq = VectorArray.from_numpy(np.random.randn(2, 4).astype(np.float32))
45
+ index = VectorIndex.create(xb, metric="cosine", backend="bruteforce")
46
+ caps = index.backend_capabilities()
47
+ assert caps["supports_add"] is True
48
+ assert caps["supports_ann_tuning"] is False
49
+ index.search(xq, k=3)
50
+ stats = index.runtime_stats()
51
+ assert stats["search_calls"] == 1
52
+ assert stats["last_search_k"] == 3
53
+ assert stats["backend_stats"]["backend"] == "bruteforce"
@@ -4,8 +4,8 @@ import subprocess
4
4
  import numpy as np
5
5
  import pytest
6
6
 
7
- from scripts.benchmark_matrix import _apply_memory_limit, _parse_matrix, run_matrix
8
- from scripts.datasets import load_jsonl_bundle, load_numpy_bundle, with_deterministic_splits
7
+ from scripts.benchmark_matrix import _apply_memory_limit, _build_run_variants, _parse_matrix, run_matrix
8
+ from scripts.datasets import estimate_numpy_bundle_memory_mb, load_jsonl_bundle, load_numpy_bundle, with_deterministic_splits
9
9
 
10
10
 
11
11
  def test_parse_matrix_profile_defaults_to_dev():
@@ -14,6 +14,29 @@ def test_parse_matrix_profile_defaults_to_dev():
14
14
  assert {"name", "n", "d", "nq", "k"}.issubset(set(matrix[0].keys()))
15
15
 
16
16
 
17
+ def test_parse_matrix_profile_scale():
18
+ matrix = _parse_matrix(None, profile="scale")
19
+ assert len(matrix) >= 1
20
+ assert "ann_index_factory_options" in matrix[0]
21
+
22
+
23
+ def test_build_run_variants_ann_expands():
24
+ variants = _build_run_variants(
25
+ {
26
+ "name": "cfg",
27
+ "n": 1000,
28
+ "d": 64,
29
+ "nq": 32,
30
+ "k": 5,
31
+ "ann_index_factory_options": ["IVF64,Flat", "IVF128,Flat"],
32
+ "ann_nprobe_options": [4, 8],
33
+ },
34
+ mode="ann",
35
+ )
36
+ assert len(variants) == 5
37
+ assert any(v["faiss_ivf_nprobe"] == 8 for v in variants)
38
+
39
+
17
40
  def test_apply_memory_limit_filters_large_configs():
18
41
  matrix = [
19
42
  {"name": "a", "n": 1000, "d": 32, "nq": 64, "k": 5},
@@ -40,6 +63,24 @@ def test_load_numpy_bundle(tmp_path):
40
63
  assert bundle.metadata is not None
41
64
 
42
65
 
66
+ def test_load_numpy_bundle_memmap_mode(tmp_path):
67
+ xb = np.random.randn(6, 12).astype(np.float32)
68
+ emb = tmp_path / "emb.npy"
69
+ ids = tmp_path / "ids.json"
70
+ np.save(emb, xb)
71
+ ids.write_text(json.dumps([f"doc-{i}" for i in range(6)]), encoding="utf-8")
72
+ bundle = load_numpy_bundle(str(emb), str(ids), mmap_mode="r")
73
+ assert bundle.embeddings.shape == (6, 12)
74
+ assert bundle.ids[0] == "doc-0"
75
+
76
+
77
+ def test_estimate_numpy_bundle_memory_mb():
78
+ estimate = estimate_numpy_bundle_memory_mb(1000, 64)
79
+ assert estimate > 0.0
80
+ with pytest.raises(ValueError, match="dataset_error"):
81
+ estimate_numpy_bundle_memory_mb(0, 64)
82
+
83
+
43
84
  def test_load_numpy_bundle_with_extended_fields(tmp_path):
44
85
  xb = np.random.randn(4, 8).astype(np.float32)
45
86
  emb = tmp_path / "emb.npy"
@@ -189,3 +230,55 @@ def test_run_matrix_fails_when_overlap_gate_enabled_without_faiss(tmp_path, monk
189
230
  profile="dev",
190
231
  max_memory_mb=1024.0,
191
232
  )
233
+
234
+
235
+ def test_run_matrix_ann_sweep_invokes_multiple_configs(tmp_path, monkeypatch):
236
+ calls: list[list[str]] = []
237
+
238
+ def fake_check_call(cmd):
239
+ calls.append(cmd)
240
+ out_path = cmd[cmd.index("--output") + 1]
241
+ payload = {
242
+ "timestamp_utc": "2026-01-01T00:00:00+00:00",
243
+ "config": {"mode": "ann", "k": 5, "min_flat_overlap": None},
244
+ "environment": {"platform": "darwin", "python_version": "3.12", "machine": "arm64", "processor": "arm"},
245
+ "results": [
246
+ {
247
+ "backend": "bruteforce",
248
+ "qps": 900.0,
249
+ "latency_p50_ms": 1.1,
250
+ "latency_p95_ms": 2.2,
251
+ "overlap_vs_bruteforce": 1.0,
252
+ "memory_mb_estimate": 10.0,
253
+ }
254
+ ],
255
+ "artifact_contract_version": "1.0",
256
+ }
257
+ with open(out_path, "w", encoding="utf-8") as f:
258
+ json.dump(payload, f)
259
+
260
+ monkeypatch.setattr(subprocess, "check_call", fake_check_call)
261
+ summary = run_matrix(
262
+ matrix=[
263
+ {
264
+ "name": "tiny",
265
+ "n": 2000,
266
+ "d": 32,
267
+ "nq": 64,
268
+ "k": 5,
269
+ "ann_index_factory_options": ["IVF64,Flat"],
270
+ "ann_nprobe_options": [4, 8],
271
+ }
272
+ ],
273
+ mode="ann",
274
+ warmup=1,
275
+ loops=1,
276
+ seed=7,
277
+ min_flat_overlap=None,
278
+ out_dir=str(tmp_path / "out"),
279
+ profile="dev",
280
+ max_memory_mb=1024.0,
281
+ )
282
+ assert len(calls) == 3
283
+ assert summary["protocol"]["expanded_run_count"] == 3
284
+ assert "pareto_frontier" in summary
@@ -81,3 +81,19 @@ def test_run_ingest_rejects_duplicate_ids(tmp_path):
81
81
  embedding_dim=8,
82
82
  seed=7,
83
83
  )
84
+
85
+
86
+ def test_run_ingest_honors_memory_cap(tmp_path):
87
+ source = tmp_path / "source.jsonl"
88
+ rows = [{"id": f"d{i}", "text": f"text-{i}"} for i in range(10)]
89
+ _write_jsonl(source, rows)
90
+ with pytest.raises(ValueError, match="max_memory_mb"):
91
+ run_ingest(
92
+ input_jsonl=str(source),
93
+ output_dir=str(tmp_path / "out"),
94
+ id_field="id",
95
+ text_field="text",
96
+ embedding_dim=64,
97
+ seed=7,
98
+ max_memory_mb=0.0001,
99
+ )
@@ -0,0 +1,24 @@
1
+ import json
2
+
3
+ from scripts.matrix_profile_advisor import recommend_configs
4
+
5
+
6
+ def test_recommend_configs_returns_sorted_recommendations(tmp_path):
7
+ run_dir = tmp_path / "runs"
8
+ run_dir.mkdir(parents=True, exist_ok=True)
9
+ matrix_summary = {
10
+ "expanded_runs": ["cfg_a", "cfg_b"],
11
+ "runs_dir": str(run_dir),
12
+ }
13
+ (tmp_path / "matrix_summary.json").write_text(json.dumps(matrix_summary), encoding="utf-8")
14
+ for name, qps, p95, overlap in [("cfg_a", 1200.0, 10.0, 0.90), ("cfg_b", 1000.0, 8.0, 0.98)]:
15
+ payload = {
16
+ "results": [
17
+ {"backend": "bruteforce", "qps": 500.0, "latency_p95_ms": 12.0, "overlap_vs_bruteforce": 1.0},
18
+ {"backend": "faiss_ivf", "qps": qps, "latency_p95_ms": p95, "overlap_vs_bruteforce": overlap},
19
+ ]
20
+ }
21
+ (run_dir / f"{name}.json").write_text(json.dumps(payload), encoding="utf-8")
22
+ out = recommend_configs(str(tmp_path / "matrix_summary.json"), top_n=1)
23
+ assert len(out["recommendations"]) == 1
24
+ assert out["recommendations"][0]["run"] in {"cfg_a", "cfg_b"}
@@ -0,0 +1,125 @@
1
+ import json
2
+
3
+ from scripts.performance_gates import run_performance_gates
4
+ from scripts.publishable_results import build_publishable_summary
5
+
6
+
7
+ def _write(path, payload):
8
+ path.write_text(json.dumps(payload), encoding="utf-8")
9
+
10
+
11
+ def test_performance_gates_passes_with_reasonable_metrics(tmp_path):
12
+ matrix = {
13
+ "timestamp_utc": "2026-01-01T00:00:00+00:00",
14
+ "protocol": {"mode": "exact", "warmup": 2, "loops": 5, "seed": 7, "matrix_size": 1, "min_flat_overlap": 0.99},
15
+ "environment": {},
16
+ "matrix": [{"name": "cfg", "n": 1000, "d": 32, "nq": 64, "k": 5}],
17
+ "backend_summary": {
18
+ "bruteforce": {
19
+ "latency_p50_ms": {"mean": 1.0, "median": 1.0, "min": 1.0, "max": 1.0},
20
+ "latency_p95_ms": {"mean": 2.0, "median": 2.0, "min": 2.0, "max": 2.0},
21
+ "qps": {"mean": 100.0, "median": 100.0, "min": 90.0, "max": 110.0},
22
+ "overlap_vs_bruteforce": {"mean": 1.0, "median": 1.0, "min": 1.0, "max": 1.0},
23
+ }
24
+ },
25
+ "runs_dir": "artifacts/benchmark_matrix",
26
+ "artifact_contract_version": "1.0",
27
+ }
28
+ stability = {
29
+ "timestamp_utc": "2026-01-01T00:00:00+00:00",
30
+ "run_count": 3,
31
+ "backend": "bruteforce",
32
+ "config": {},
33
+ "environment": {},
34
+ "performance_summary": {
35
+ "latency_p50_ms": {"mean": 1.0},
36
+ "latency_p95_ms": {"mean": 2.0},
37
+ "qps": {"mean": 150.0},
38
+ },
39
+ "metric_summary": {"recall@10": {"mean": 0.95}, "ndcg@10": {"mean": 0.92}},
40
+ "check_pass_rate": {},
41
+ "input_files": {},
42
+ "runs_path": "runs.jsonl",
43
+ "artifact_contract_version": "1.0",
44
+ }
45
+ matrix_path = tmp_path / "matrix.json"
46
+ stability_path = tmp_path / "stability.json"
47
+ out_path = tmp_path / "gates.json"
48
+ _write(matrix_path, matrix)
49
+ _write(stability_path, stability)
50
+ report = run_performance_gates(
51
+ matrix_summary_path=str(matrix_path),
52
+ stability_summary_path=str(stability_path),
53
+ output_path=str(out_path),
54
+ min_recall=0.8,
55
+ min_ndcg=0.8,
56
+ max_latency_p95_ms=50.0,
57
+ min_qps=50.0,
58
+ )
59
+ assert report["status"] == "pass"
60
+ assert out_path.exists()
61
+
62
+
63
+ def test_build_publishable_summary_includes_release_delta(tmp_path):
64
+ matrix = {
65
+ "timestamp_utc": "2026-01-01T00:00:00+00:00",
66
+ "protocol": {"mode": "exact", "warmup": 2, "loops": 8, "seed": 7, "matrix_size": 1},
67
+ "environment": {},
68
+ "matrix": [{"name": "cfg", "n": 1000, "d": 32, "nq": 64, "k": 5}],
69
+ "backend_summary": {
70
+ "bruteforce": {
71
+ "latency_p50_ms": {"mean": 1.0, "median": 1.0, "min": 1.0, "max": 1.0},
72
+ "latency_p95_ms": {"mean": 2.0, "median": 2.0, "min": 2.0, "max": 2.0},
73
+ "qps": {"mean": 100.0, "median": 100.0, "min": 95.0, "max": 105.0},
74
+ "overlap_vs_bruteforce": {"mean": 1.0, "median": 1.0, "min": 1.0, "max": 1.0},
75
+ }
76
+ },
77
+ "runs_dir": "artifacts/benchmark_matrix",
78
+ "artifact_contract_version": "1.0",
79
+ }
80
+ stability = {
81
+ "timestamp_utc": "2026-01-01T00:00:00+00:00",
82
+ "run_count": 2,
83
+ "backend": "bruteforce",
84
+ "config": {"run_count": 2},
85
+ "environment": {},
86
+ "performance_summary": {
87
+ "latency_p50_ms": {"mean": 1.0, "median": 1.0, "std": 0.0, "cv": 0.0, "p02_5": 1.0, "p97_5": 1.0, "min": 1.0, "max": 1.0},
88
+ "latency_p95_ms": {"mean": 2.0, "median": 2.0, "std": 0.0, "cv": 0.0, "p02_5": 2.0, "p97_5": 2.0, "min": 2.0, "max": 2.0},
89
+ "qps": {"mean": 120.0, "median": 120.0, "std": 0.0, "cv": 0.0, "p02_5": 120.0, "p97_5": 120.0, "min": 120.0, "max": 120.0},
90
+ },
91
+ "metric_summary": {"recall@1": {"mean": 0.9}},
92
+ "check_pass_rate": {},
93
+ "input_files": {},
94
+ "runs_path": "runs.jsonl",
95
+ "artifact_contract_version": "1.0",
96
+ }
97
+ previous = {
98
+ "matrix_backend_summary": {
99
+ "bruteforce": {
100
+ "latency_p95_ms": {"mean": 3.0},
101
+ "qps": {"mean": 100.0},
102
+ "overlap_vs_bruteforce": {"mean": 1.0},
103
+ }
104
+ },
105
+ "stability_performance_summary": {
106
+ "latency_p95_ms": {"mean": 2.5},
107
+ "qps": {"mean": 100.0},
108
+ },
109
+ }
110
+ matrix_path = tmp_path / "matrix.json"
111
+ stability_path = tmp_path / "stability.json"
112
+ previous_path = tmp_path / "previous.json"
113
+ out_path = tmp_path / "publishable.json"
114
+ _write(matrix_path, matrix)
115
+ _write(stability_path, stability)
116
+ _write(previous_path, previous)
117
+ payload = build_publishable_summary(
118
+ matrix_summary_path=str(matrix_path),
119
+ stability_summary_path=str(stability_path),
120
+ out_path=str(out_path),
121
+ previous_summary_path=str(previous_path),
122
+ )
123
+ assert "release_over_release_delta" in payload
124
+ delta = payload["release_over_release_delta"]["stability_performance_delta"]
125
+ assert delta["latency_p95_ms_mean_delta"] < 0.0
@@ -1,6 +1,6 @@
1
1
  """Vector Engine public API."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.1.1"
4
4
 
5
5
  from .array import VectorArray
6
6
  from .index import VectorIndex
@@ -23,6 +23,9 @@ class BaseBackend(Protocol):
23
23
  def save(self, path: str) -> None:
24
24
  ...
25
25
 
26
+ def get_runtime_stats(self) -> dict[str, float | int | str]:
27
+ ...
28
+
26
29
  @classmethod
27
30
  def load(cls, path: str) -> "BaseBackend":
28
31
  ...
@@ -23,6 +23,8 @@ class BruteForceBackend:
23
23
  "supports_delete": False,
24
24
  "supports_custom_metric": True,
25
25
  "supports_persistence": True,
26
+ "supports_add": True,
27
+ "supports_ann_tuning": False,
26
28
  }
27
29
  )
28
30
  xb: np.ndarray | None = None
@@ -94,6 +96,18 @@ class BruteForceBackend:
94
96
  f,
95
97
  )
96
98
 
99
+ def get_runtime_stats(self) -> dict[str, float | int | str]:
100
+ count = int(self.xb.shape[0]) if self.xb is not None else 0
101
+ dim = int(self.xb.shape[1]) if self.xb is not None else 0
102
+ metric_name = self.metric.name if self.metric is not None else "unknown"
103
+ return {
104
+ "backend": self.name,
105
+ "count": count,
106
+ "dim": dim,
107
+ "metric": metric_name,
108
+ "vector_bytes": int(self.xb.nbytes) if self.xb is not None else 0,
109
+ }
110
+
97
111
  @classmethod
98
112
  def load(cls, path: str) -> "BruteForceBackend":
99
113
  with open(os.path.join(path, "backend_meta.json"), "r", encoding="utf-8") as f:
@@ -23,6 +23,8 @@ class FaissBackend:
23
23
  "supports_delete": False,
24
24
  "supports_custom_metric": False,
25
25
  "supports_persistence": True,
26
+ "supports_add": True,
27
+ "supports_ann_tuning": True,
26
28
  }
27
29
  )
28
30
  _index: object | None = None
@@ -110,6 +112,17 @@ class FaissBackend:
110
112
  f,
111
113
  )
112
114
 
115
+ def get_runtime_stats(self) -> dict[str, float | int | str]:
116
+ metric_name = self._metric.name if self._metric is not None else "unknown"
117
+ config = self._config or {}
118
+ return {
119
+ "backend": self.name,
120
+ "count": int(self._count),
121
+ "metric": metric_name,
122
+ "index_factory": str(config.get("index_factory", "Flat")),
123
+ "nprobe": int(config.get("nprobe", 0)) if config.get("nprobe") is not None else 0,
124
+ }
125
+
113
126
  @classmethod
114
127
  def load(cls, path: str) -> "FaissBackend":
115
128
  backend = cls()
@@ -55,6 +55,9 @@ class VectorIndex:
55
55
  _row_to_external: list[int | str] = field(default_factory=list)
56
56
  _metadata: list[dict[str, Any]] | None = None
57
57
  _dim: int = 0
58
+ _search_calls: int = 0
59
+ _last_search_k: int = 0
60
+ _last_search_nq: int = 0
58
61
 
59
62
  @classmethod
60
63
  def create(
@@ -121,6 +124,9 @@ class VectorIndex:
121
124
  if k <= 0:
122
125
  raise ValueError("index_error: k must be > 0")
123
126
  scores, internal_ids = self._backend.search(queries.values, k)
127
+ self._search_calls += 1
128
+ self._last_search_k = int(k)
129
+ self._last_search_nq = int(queries.shape[0])
124
130
  external_ids = _to_external_ids(internal_ids, self._row_to_external)
125
131
  md_out = None
126
132
  if return_metadata and self._metadata is not None:
@@ -136,6 +142,31 @@ class VectorIndex:
136
142
  md_out.append(items)
137
143
  return SearchResult(ids=external_ids, scores=scores, metadata=md_out)
138
144
 
145
+ def backend_capabilities(self) -> dict[str, bool]:
146
+ if self._backend is None:
147
+ raise RuntimeError("index_error: index is not initialized")
148
+ caps = getattr(self._backend, "capabilities", None)
149
+ if not isinstance(caps, dict):
150
+ return {}
151
+ return {str(k): bool(v) for k, v in caps.items()}
152
+
153
+ def runtime_stats(self) -> dict[str, Any]:
154
+ if self._backend is None:
155
+ raise RuntimeError("index_error: index is not initialized")
156
+ backend_stats: dict[str, Any] = {}
157
+ if hasattr(self._backend, "get_runtime_stats"):
158
+ backend_stats = dict(getattr(self._backend, "get_runtime_stats")())
159
+ return {
160
+ "backend": self.backend_name,
161
+ "dim": int(self._dim),
162
+ "count": int(len(self._row_to_external)),
163
+ "search_calls": int(self._search_calls),
164
+ "last_search_k": int(self._last_search_k),
165
+ "last_search_nq": int(self._last_search_nq),
166
+ "capabilities": self.backend_capabilities(),
167
+ "backend_stats": backend_stats,
168
+ }
169
+
139
170
  def save(self, path: str) -> None:
140
171
  if self._backend is None:
141
172
  raise RuntimeError("index_error: index is not initialized")
@@ -1,4 +1,36 @@
1
- # Vector Engine v1.0.0
1
+ Metadata-Version: 2.4
2
+ Name: vector-engine
3
+ Version: 1.1.1
4
+ Summary: ML-first vector computation and retrieval engine.
5
+ Author: Neel Panchal
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/neelpanchal11/Vector-Engine
8
+ Project-URL: Repository, https://github.com/neelpanchal11/Vector-Engine
9
+ Project-URL: Issues, https://github.com/neelpanchal11/Vector-Engine/issues
10
+ Project-URL: Documentation, https://github.com/neelpanchal11/Vector-Engine/tree/main/docs
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy<2.0,>=1.26.4
25
+ Provides-Extra: faiss
26
+ Requires-Dist: faiss-cpu>=1.7.4; (platform_system != "Darwin" or platform_machine != "arm64") and extra == "faiss"
27
+ Provides-Extra: ml
28
+ Requires-Dist: scikit-learn<1.7,>=1.4; extra == "ml"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest<9,>=8.2; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # Vector Engine v1.1.1
2
34
 
3
35
  Reproducibility-first vector retrieval toolkit for local ML and IR workflows.
4
36
 
@@ -77,7 +109,17 @@ results = index.search(xq, k=5)
77
109
  print(results.ids[0], results.scores[0])
78
110
  ```
79
111
 
80
- ## v1.0.0 Surface
112
+ ## Colab Demos
113
+
114
+ Each notebook opens directly from this repo, so it always matches the current release.
115
+
116
+ - Semantic search: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/01_semantic_search.ipynb)
117
+ - kNN baseline classifier: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/02_knn_baseline.ipynb)
118
+ - Item-item recommender similarity: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neelpanchal11/Vector-Engine/blob/main/notebooks/03_recommender_similarity.ipynb)
119
+
120
+ `notebooks/04_stability_runs.ipynb` analyzes locally generated benchmark artifacts (see [Reproducibility and Evidence](#reproducibility-and-evidence)) and is not a standalone Colab demo.
121
+
122
+ ## v1.1.0 Surface
81
123
 
82
124
  - Core: `VectorArray`, `VectorIndex`, `Metric`, `SearchResult`
83
125
  - ML: `knn_classify`, `knn_regress`, `kmeans`, `KMeansResult`
@@ -174,8 +216,8 @@ python scripts/credibility_audit.py --matrix-summary artifacts/benchmark_matrix/
174
216
 
175
217
  ## Project Links
176
218
 
177
- - `docs/releases/v1.0.0.md`
178
- - `docs/releases/v1.0.0-checklist.md`
219
+ - `docs/releases/v1.1.0.md`
220
+ - `docs/releases/v1.1.0-checklist.md`
179
221
  - `docs/reproducibility.md`
180
222
  - `docs/use_cases.md`
181
223
  - `docs/api_stability.md`
@@ -12,6 +12,7 @@ tests/test_faiss_optional.py
12
12
  tests/test_hardening.py
13
13
  tests/test_ingest_pipeline.py
14
14
  tests/test_install_smoke.py
15
+ tests/test_matrix_profile_advisor.py
15
16
  tests/test_ml_eval.py
16
17
  tests/test_perf_smoke.py
17
18
  tests/test_persistence_compat.py
@@ -19,6 +20,7 @@ tests/test_profile_local.py
19
20
  tests/test_rag_reliability.py
20
21
  tests/test_real_corpus_eval.py
21
22
  tests/test_release_bundle.py
23
+ tests/test_release_performance_workflow.py
22
24
  tests/test_v02_features.py
23
25
  vector_engine/__init__.py
24
26
  vector_engine/array.py
@@ -1,32 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=68", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "vector-engine"
7
- version = "1.0.2"
8
- description = "ML-first vector computation and retrieval engine."
9
- readme = "README.md"
10
- requires-python = ">=3.10"
11
- license = "MIT"
12
- authors = [
13
- { name = "Neel Panchal" }
14
- ]
15
- dependencies = [
16
- "numpy>=1.26.4,<2.0",
17
- ]
18
-
19
- [project.optional-dependencies]
20
- faiss = [
21
- "faiss-cpu>=1.7.4; platform_system != 'Darwin' or platform_machine != 'arm64'",
22
- ]
23
- ml = [
24
- "scikit-learn>=1.4,<1.7",
25
- ]
26
- dev = [
27
- "pytest>=8.2,<9",
28
- ]
29
-
30
- [tool.setuptools.packages.find]
31
- where = ["."]
32
- include = ["vector_engine*"]
File without changes
File without changes