metta-faiss 0.9.0__py3-none-any.whl
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.
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: metta-faiss
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: faiss as a nearest-neighbour backend for a MeTTa embedding store
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Intended Audience :: Science/Research
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: pymetta==0.8.0
|
|
12
|
+
Requires-Dist: faiss-cpu
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
|
|
15
|
+
# metta-faiss
|
|
16
|
+
|
|
17
|
+
faiss as a nearest-neighbour backend for a MeTTa embedding store.
|
|
18
|
+
|
|
19
|
+
`pymetta` names no third-party library. This package is one row against the `index` point, and the seat
|
|
20
|
+
finds it exactly as it finds a package written by somebody else: through the
|
|
21
|
+
`metta.extensions` entry point, loaded at the first dispatch that has no answer
|
|
22
|
+
without it, or through `import metta_faiss`, whose module body registers the same
|
|
23
|
+
rows.
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pip install metta-faiss # or: pip install 'pymetta[arrays]'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Its tests are in `tests/`, and they run in the workspace suite:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
sh extensions/python/test.sh ext/metta-faiss
|
|
33
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
metta_faiss.py,sha256=FeiZpH0fmb9SRYwEEBsf6x1LCLp75E9wR8GO62zbFfU,3083
|
|
2
|
+
metta_faiss-0.9.0.dist-info/METADATA,sha256=s0oNkR9k-VqcUu4feX6oa6XKgc4hiud16KrwQ8fAmXk,1068
|
|
3
|
+
metta_faiss-0.9.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
4
|
+
metta_faiss-0.9.0.dist-info/entry_points.txt,sha256=ahP6XClBTPiBWg6Mbx8bsxg6CXRcAB9sCXBtgGKh3OA,45
|
|
5
|
+
metta_faiss-0.9.0.dist-info/top_level.txt,sha256=tM7Yb1N2mt3vDHsqEMiUG4kM4gxcl-Cw6W7pTX7Bi3M,12
|
|
6
|
+
metta_faiss-0.9.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
metta_faiss
|
metta_faiss.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Purpose: faiss as a nearest-neighbour backend of the MeTTa Python seat.
|
|
2
|
+
|
|
3
|
+
One row against the seat's `index` point, so an embedding store searches
|
|
4
|
+
through faiss when this package is installed. The row is NOT a fallback, which
|
|
5
|
+
is what makes `backend="auto"` prefer it over the generic Array API path
|
|
6
|
+
whatever order the two distributions loaded in; entry-point order is not
|
|
7
|
+
something a package can arrange.
|
|
8
|
+
|
|
9
|
+
NumPy is a dependency here and is not an integration: faiss' own interface
|
|
10
|
+
takes contiguous float32 NumPy arrays for `add` and `search`, so staging one is
|
|
11
|
+
part of calling faiss at all, and faiss-cpu depends on NumPy itself.
|
|
12
|
+
|
|
13
|
+
Assumes:
|
|
14
|
+
- a normalized matrix, which is the `index` point's contract: the backend
|
|
15
|
+
searches inner products and the store normalizes before it gets here
|
|
16
|
+
Guarantees:
|
|
17
|
+
- `available()` answers False rather than raising when faiss is absent, so
|
|
18
|
+
an embedding store falls through to the next backend instead of failing
|
|
19
|
+
[tested: tests/test_faiss.py::test_an_absent_faiss_declines_rather_than_raising;
|
|
20
|
+
commit=94057a0f073c0fab0a35c42beff2c324d8a0addd]
|
|
21
|
+
- faiss wins `backend="auto"` over the Array API fallback in either load
|
|
22
|
+
order [tested: tests/test_faiss.py::test_faiss_wins_auto_over_the_array_api_fallback;
|
|
23
|
+
commit=94057a0f073c0fab0a35c42beff2c324d8a0addd]
|
|
24
|
+
Open Obligations:
|
|
25
|
+
To Do: None
|
|
26
|
+
Hacks: None
|
|
27
|
+
Future Enhancements: None
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
from typing import Any, Final
|
|
33
|
+
|
|
34
|
+
from metta import seam
|
|
35
|
+
|
|
36
|
+
_MISSING: Final = (
|
|
37
|
+
"the faiss embedding backend needs faiss-cpu; install pymetta[arrays]"
|
|
38
|
+
)
|
|
39
|
+
_NUMPY_MISSING: Final = (
|
|
40
|
+
"the faiss embedding backend stages its matrix as a contiguous float32 "
|
|
41
|
+
"NumPy array, which is faiss' own interface, and NumPy is not installed; "
|
|
42
|
+
"install pymetta[arrays]"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
require_module = seam.at("module").call()
|
|
46
|
+
optional_module = seam.at("optional-module").call()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _available() -> bool:
|
|
50
|
+
"""Whether faiss can run here."""
|
|
51
|
+
return optional_module("faiss") is not None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _build(matrix: Any) -> Any:
|
|
55
|
+
"""An exact inner-product index over the normalized matrix."""
|
|
56
|
+
faiss = require_module("faiss", _MISSING)
|
|
57
|
+
numpy = require_module("numpy", _NUMPY_MISSING)
|
|
58
|
+
staged = numpy.ascontiguousarray(numpy.asarray(matrix, dtype=numpy.float32))
|
|
59
|
+
index = faiss.IndexFlatIP(staged.shape[1])
|
|
60
|
+
index.add(staged)
|
|
61
|
+
return index
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _search(index: Any, query: Any, count: int) -> list[tuple[int, float]]:
|
|
65
|
+
"""(row, score) pairs best first, from the built index."""
|
|
66
|
+
numpy = require_module("numpy", _NUMPY_MISSING)
|
|
67
|
+
probe = numpy.ascontiguousarray(numpy.asarray(query, dtype=numpy.float32).reshape(1, -1))
|
|
68
|
+
scores, indexes = index.search(probe, count)
|
|
69
|
+
return [
|
|
70
|
+
(int(index), float(score))
|
|
71
|
+
for score, index in zip(scores[0], indexes[0], strict=True)
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def register() -> None:
|
|
76
|
+
"""This package's one row, against the seat's `index` point."""
|
|
77
|
+
seam.index.register(
|
|
78
|
+
"faiss",
|
|
79
|
+
available=_available,
|
|
80
|
+
build=_build,
|
|
81
|
+
search=_search,
|
|
82
|
+
missing=_MISSING,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
register()
|