vicinus 0.0.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.
- vicinus-0.0.1/.gitignore +9 -0
- vicinus-0.0.1/PKG-INFO +272 -0
- vicinus-0.0.1/changelog.md +8 -0
- vicinus-0.0.1/docs.md +166 -0
- vicinus-0.0.1/license +17 -0
- vicinus-0.0.1/old/0.vectordb.md +255 -0
- vicinus-0.0.1/pyproject.toml +45 -0
- vicinus-0.0.1/readme.md +254 -0
- vicinus-0.0.1/vicinus/SKILL.md +182 -0
- vicinus-0.0.1/vicinus/__init__.py +12 -0
- vicinus-0.0.1/vicinus/cli.py +181 -0
- vicinus-0.0.1/vicinus/errors.py +8 -0
- vicinus-0.0.1/vicinus/hamming.py +19 -0
- vicinus-0.0.1/vicinus/helpers.py +37 -0
- vicinus-0.0.1/vicinus/levenshtein.py +37 -0
- vicinus-0.0.1/vicinus/ngf_idf.py +167 -0
- vicinus-0.0.1/vicinus/ngrams.py +23 -0
- vicinus-0.0.1/vicinus/samples/__init__.py +23 -0
- vicinus-0.0.1/vicinus/samples/agentic-ai-emerging-cyber-threat.txt +22 -0
- vicinus-0.0.1/vicinus/samples/agentic-ai-technical.txt +36 -0
- vicinus-0.0.1/vicinus/samples/bespoke-data-erasure.txt +28 -0
- vicinus-0.0.1/vicinus/samples/breakfast.txt +33 -0
- vicinus-0.0.1/vicinus/samples/carl-jung-anima-animus.txt +18 -0
- vicinus-0.0.1/vicinus/samples/common-cold-vs-flu.txt +14 -0
- vicinus-0.0.1/vicinus/samples/finance-capitalism.txt +56 -0
- vicinus-0.0.1/vicinus/samples/hamming-levenshtein.txt +50 -0
- vicinus-0.0.1/vicinus/samples/horse-tinder-pitch.txt +14 -0
- vicinus-0.0.1/vicinus/samples/hymn-to-tourac.txt +49 -0
- vicinus-0.0.1/vicinus/samples/n-grams-jaccards-index.txt +46 -0
- vicinus-0.0.1/vicinus/samples/ngf-idf.txt +26 -0
- vicinus-0.0.1/vicinus/samples/sanctions-guide.md +57 -0
- vicinus-0.0.1/vicinus/samples/sanctions-lamentation.txt +26 -0
- vicinus-0.0.1/vicinus/samples/software-design-patterns.md +115 -0
- vicinus-0.0.1/vicinus/samples/spirits-cause-disease.txt +10 -0
- vicinus-0.0.1/vicinus/samples/tf-idf-cosine-similarity.txt +63 -0
- vicinus-0.0.1/vicinus/samples/wallace-in-underland.txt +22 -0
- vicinus-0.0.1/vicinus/samples/wolf-who-cried-boy.txt +18 -0
- vicinus-0.0.1/vicinus/sparse_vector.py +85 -0
- vicinus-0.0.1/vicinus/tokenize.py +9 -0
- vicinus-0.0.1/vicinus/version.py +5 -0
vicinus-0.0.1/.gitignore
ADDED
vicinus-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vicinus
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Fuzzy search library from scratch implementing novel NGF/NGF-IDF system.
|
|
5
|
+
Project-URL: Homepage, https://pycelium.com
|
|
6
|
+
Project-URL: Repository, https://github.com/k98kurz/vicinus
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/k98kurz/vicinus/issues
|
|
8
|
+
Author-email: k98kurz <k98kurz@gmail.com>
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: License :: OSI Approved :: ISC License (ISCL)
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Provides-Extra: docs
|
|
16
|
+
Requires-Dist: autodox>=0.1.16; extra == 'docs'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# Vicinus
|
|
20
|
+
|
|
21
|
+
Vicinus is a library for building fuzzy search tools. It includes multiple
|
|
22
|
+
similarity/distance algorithms, an in-memory vector DB, and an optional
|
|
23
|
+
persistent vector DB using my sqloquent ORM package (sqlite3). Made from
|
|
24
|
+
all-organic, artisanal, 100% hand-crafted code with no gen AI (except to write
|
|
25
|
+
some text samples for testing) and no external dependencies.
|
|
26
|
+
|
|
27
|
+
This library includes several standard algorithms as well as a few novel (to my
|
|
28
|
+
knowledge) constructions: NGF and NGF-IDF, adapted from TF and TF-IDF but using
|
|
29
|
+
N-Grams to construct a comprehensive lexicon (26 letters + 10 numerals). The goal
|
|
30
|
+
of these novel constructions is to provide a lightweight alternative to text
|
|
31
|
+
embedding models and full TF-IDF while preserving utility for fuzzy searching.
|
|
32
|
+
|
|
33
|
+
("Vicinus" means "neighboring/nearby" in Latin.)
|
|
34
|
+
|
|
35
|
+
## Status
|
|
36
|
+
|
|
37
|
+
- [x] Hamming Distance/Similarity
|
|
38
|
+
- [x] Levenshtein Distance/Similarity
|
|
39
|
+
- [x] N-Gram Extraction
|
|
40
|
+
- [x] Jaccard Index
|
|
41
|
+
- [x] Sparse Vector Cosine Similarity
|
|
42
|
+
- [x] NGF (N-Gram Frequency)
|
|
43
|
+
- [x] NGF-IDF (N-Gram Frequency * Inverse Document Frequecy)
|
|
44
|
+
- [ ] Planned Optimizations: Levenshtein, NGF-IDF
|
|
45
|
+
- [ ] In-Memory VectorDB using NGF or NGF-IDF
|
|
46
|
+
- [ ] Persistent VectorDB using NGF or NGF-IDF
|
|
47
|
+
|
|
48
|
+
Open issues can be tracked [here](https://github.com/k98kurz/vicinus/issues).
|
|
49
|
+
Historical changes can be found in the
|
|
50
|
+
[changelog](https://github.com/k98kurz/vicinus/blob/master/changelog.md).
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install vicinus
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### CLI
|
|
61
|
+
|
|
62
|
+
This package includes a CLI tool for exporting an agent skill to help clankers
|
|
63
|
+
use this package correctly. (It also serves as decent documentation in general,
|
|
64
|
+
so it might also be worth scanning if you aren't coding with a clanker.)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
vicinus skill # prints to stdout
|
|
68
|
+
vicinus skill -o path # exports to path/vicinus/
|
|
69
|
+
vicinus skill --agent # exports to .agent/skills/vicinus/
|
|
70
|
+
vicinus skill --claude # exports to .claude/skills/vicinus/
|
|
71
|
+
vicinus skill --codex # exports to .agent/skills/vicinus/
|
|
72
|
+
vicinus skill --cursor # exports to .cursor/skills/vicinus/
|
|
73
|
+
vicinus skill --opencode # exports to .opencode/skills/vicinus/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The CLI can also be used to export the bundled text samples for experimentation.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
vicinus samples # prints all to stdout with filenames
|
|
80
|
+
vicinus samples -l # prints list of all filenames
|
|
81
|
+
vicinus samples -n name # prints a specific sample to stdout
|
|
82
|
+
vicinus samples -o path # exports all files to path/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Distance/Similarity
|
|
86
|
+
|
|
87
|
+
There are two distance metrics with corresponding similarity scores Hamming and
|
|
88
|
+
Levenshtein.
|
|
89
|
+
|
|
90
|
+
There are additional similarity scores:
|
|
91
|
+
- N-Grams w/ Jaccard Index:
|
|
92
|
+
- NGF w/ Cosine Similarity
|
|
93
|
+
- NGF-IDF w/ Cosine Similarity
|
|
94
|
+
|
|
95
|
+
There are also two helper functions:
|
|
96
|
+
- `rank(score_fn: Callable, candidates: list) -> list[tuple[float, int]]`
|
|
97
|
+
- `select(rankings: list[tuple[float, int]], k: int = 4) -> list[tuple[float, int]]`
|
|
98
|
+
|
|
99
|
+
#### Hamming
|
|
100
|
+
|
|
101
|
+
Relatively simple and cheap, but not very robust. Not suitable for large texts.
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from vicinus import hamming_distance, hamming_similarity, rank, select
|
|
105
|
+
|
|
106
|
+
# distance between two texts
|
|
107
|
+
distance = hamming_distance(text1, text2)
|
|
108
|
+
|
|
109
|
+
# rank by similarity
|
|
110
|
+
corpus = [text1, text2, ...]
|
|
111
|
+
query = "something"
|
|
112
|
+
# rank all by query similarity
|
|
113
|
+
rankings = rank(lambda t: hamming_similarity(query, t), corpus)
|
|
114
|
+
# get top k=2 rankings
|
|
115
|
+
candidates = select(rankings, 2)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Levenshtein
|
|
119
|
+
|
|
120
|
+
More complex and robust than Hamming, but entails recursive computation. Optimized
|
|
121
|
+
by a limited `lru_cache(maxsize=1024)`. Not suitable for large texts.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from vicinus import levenshtein_distance, levenshtein_similarity, rank, select
|
|
125
|
+
|
|
126
|
+
# distance between two texts
|
|
127
|
+
distance = levenshtein_distance(text1, text2)
|
|
128
|
+
|
|
129
|
+
# rank by similarity
|
|
130
|
+
corpus = [text1, text2, ...]
|
|
131
|
+
query = "something"
|
|
132
|
+
# rank all by query similarity
|
|
133
|
+
rankings = rank(lambda t: levenshtein_similarity(query, t), corpus)
|
|
134
|
+
# get top k=2 rankings
|
|
135
|
+
candidates = select(rankings, 2)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### N-Grams w/ Jaccard Index
|
|
139
|
+
|
|
140
|
+
Normalize and break text into N-Grams, then use Jaccard Index on the N-Gram sets.
|
|
141
|
+
Scales well but loses cardinality of N-Gram frequencies -- a "bag of words"
|
|
142
|
+
technique. N-Grams should be at least 3 long (trigrams) but can be made longer for
|
|
143
|
+
larger texts. Jaccard Index is a measure of similarity based upon set inclusion of
|
|
144
|
+
N-Grams: shared/total (|intersection| / |union|). Only aphanumeric chars (standard
|
|
145
|
+
Latin lowercase + Arabic numerals) are supported.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from vicinus import n_grams, jaccard_index
|
|
149
|
+
|
|
150
|
+
# calculate similarity
|
|
151
|
+
ng1 = n_grams(text1, N=3) # default N
|
|
152
|
+
ng2 = n_grams(text2, N=3)
|
|
153
|
+
similarity = jaccard_index(ng1, ng2) # between 0 and 1.0
|
|
154
|
+
|
|
155
|
+
# rank by similarity
|
|
156
|
+
corpus = [text1, text2, ...]
|
|
157
|
+
query = "something"
|
|
158
|
+
corpus_ngrams = [n_grams(t) for t in corpus]
|
|
159
|
+
query_ngrams = n_grams(query)
|
|
160
|
+
# rank all by query similarity
|
|
161
|
+
rankings = rank(lambda t: jaccard_index(query_ngrams, t), corpus_ngrams)
|
|
162
|
+
# get top k=2 rankings
|
|
163
|
+
candidates = select(rankings, k=2)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### NGF w/ Cosine Similarity
|
|
167
|
+
|
|
168
|
+
Like TF but with N-Grams instead of terms. Includes cardinality of N-Gram
|
|
169
|
+
frequencies within texts but not between texts. Does not require recalculating
|
|
170
|
+
all vectors when a text in the corpus changes. Uses `SparseVector`s for efficiency.
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from vicinus import ngf, ngf_rank, ngf_select
|
|
174
|
+
|
|
175
|
+
corpus = ["Text 1 is some text...", "Text 2 is another thing...", ...]
|
|
176
|
+
vecs = [ngf(t) for t in corpus]
|
|
177
|
+
query = "text about something"
|
|
178
|
+
# to sort all texts
|
|
179
|
+
rankings = ngf_rank(query, vecs)
|
|
180
|
+
# or select top k=2
|
|
181
|
+
candidates = ngf_select(query, vecs, k=2) # or candidates = select(rankings, 2)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### NGF-IDF w/ Cosine Similarity
|
|
185
|
+
|
|
186
|
+
Like TF-IDF but with N-Grams instead of terms. Considers N-Gram frequencies within
|
|
187
|
+
texts and between texts. Requires setup phase that recalculates the IDF for a
|
|
188
|
+
corpus whenever a text changes.
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from vicinus import ngf_idf_setup, ngf_idf_rank, ngf_idf_select
|
|
192
|
+
|
|
193
|
+
corpus = ["Text 1 is some text...", "Text 2 is another thing...", ...]
|
|
194
|
+
corpus_idf, vecs = ngf_idf_setup(corpus)
|
|
195
|
+
query = "text about something"
|
|
196
|
+
# to sort all texts by cosine similarity
|
|
197
|
+
all_ranked = ngf_idf_rank(query, corpus_idf, vecs)
|
|
198
|
+
# or select the top k=4 (default)
|
|
199
|
+
candidates = ngf_idf_select(query, corpus_idf, vecs)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Note: N=5 resulted in far more accurate rankings for the test vectors than the
|
|
203
|
+
default N=3 for Jaccard Index, NGF, and NGF-IDF. This may require some tuning.
|
|
204
|
+
Higher `N` values lead to sparser vectors and lower cosine similarity/Jaccard
|
|
205
|
+
Index scores, but this appears to be primarily a culling of noise.
|
|
206
|
+
|
|
207
|
+
### Docs
|
|
208
|
+
|
|
209
|
+
Documentation generated by [autodox](https://pypi.org/project/autodox) (with one
|
|
210
|
+
fix due to a bug/missing feature in autodox) can be found
|
|
211
|
+
[here](https://github.com/k98kurz/vicinus/blob/master/docs.md).
|
|
212
|
+
|
|
213
|
+
## Note on Generative AI Use
|
|
214
|
+
|
|
215
|
+
All code and documentation was written by hand, including the test suite. I used
|
|
216
|
+
mistral and gemma4:e4b (running on my own machine via ollama with some fun bashfu)
|
|
217
|
+
to write the text samples for testing. I also used gemma4:31b via Ollama cloud in
|
|
218
|
+
OpenCode for code review (it caught a few loose ends and documentation issues).
|
|
219
|
+
|
|
220
|
+
The inspiration for this library came during development of a yet unreleased new
|
|
221
|
+
agentic harness system that I intend to optimize for small, local models: as I
|
|
222
|
+
drafted a spec for a `tool_search` tool as an option to avoid context bloat, I
|
|
223
|
+
initially thought to copy a Hamming distance implementation I wrote a few months
|
|
224
|
+
ago in a different project for fuzzy search. I reviewed the draft spec with
|
|
225
|
+
gemma4:e4b, and it suggested I look at Levenshtein distance and Jaccard Index.
|
|
226
|
+
I then read some formulas on Wikipedia, implemented Levenshtein distance, N-grams,
|
|
227
|
+
and Jaccard index, and then derived the concept of NGF/NGF-IDF independently while
|
|
228
|
+
reflecting upon the code I had just written and the inherent difficulties with
|
|
229
|
+
TF/TF-IDF (i.e. the need to construct an indexed lexicon or use a text embedding
|
|
230
|
+
model).
|
|
231
|
+
|
|
232
|
+
Code projects like this are too fun to give to clankers. Gotta maintain some joy
|
|
233
|
+
in life.
|
|
234
|
+
|
|
235
|
+
## Testing
|
|
236
|
+
|
|
237
|
+
First, clone the repo, set up a virtual env, and install requirements from
|
|
238
|
+
requirements.txt. Then run the following command to run the test suite.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
pip install -e . # or use uv
|
|
242
|
+
python -m unittest -s discover tests
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
There are currently 38 tests covering all functionality except the CLI, which is
|
|
246
|
+
tested manually.
|
|
247
|
+
|
|
248
|
+
## Contributing
|
|
249
|
+
|
|
250
|
+
Check out the [Pycelium discord server](https://discord.gg/b2QFEJDX69). If you
|
|
251
|
+
experience a problem, please discuss it on the Discord server. All suggestions
|
|
252
|
+
for improvement are also welcome, and the best place for that is also Discord.
|
|
253
|
+
If you experience a bug and do not use Discord, open an issue or discussion on
|
|
254
|
+
Github.
|
|
255
|
+
|
|
256
|
+
## ISC License
|
|
257
|
+
|
|
258
|
+
Copyright (c) 2026 Jonathan Voss (k98kurz)
|
|
259
|
+
|
|
260
|
+
Permission to use, copy, modify, and/or distribute this software
|
|
261
|
+
for any purpose with or without fee is hereby granted, provided
|
|
262
|
+
that the above copyright notice and this permission notice appear in
|
|
263
|
+
all copies.
|
|
264
|
+
|
|
265
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
266
|
+
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
267
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
268
|
+
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
|
269
|
+
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
270
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
271
|
+
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
272
|
+
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
vicinus-0.0.1/docs.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# vicinus
|
|
2
|
+
|
|
3
|
+
## Classes
|
|
4
|
+
|
|
5
|
+
### `SparseVector`
|
|
6
|
+
|
|
7
|
+
Class representing a sparse vector, i.e. omitting every element that equals 0.
|
|
8
|
+
Useful for high dimensionality vectors with mostly 0s.
|
|
9
|
+
|
|
10
|
+
#### Methods
|
|
11
|
+
|
|
12
|
+
##### `__init__(data: dict[int, int | float] = None):`
|
|
13
|
+
|
|
14
|
+
Initialize. Raises `TypeError` for invalid data.
|
|
15
|
+
|
|
16
|
+
##### `get(index: int = 0) -> int | float | None:`
|
|
17
|
+
|
|
18
|
+
Get the element at the specified index.
|
|
19
|
+
|
|
20
|
+
##### `keys() -> set[int]:`
|
|
21
|
+
|
|
22
|
+
Return the set of indices for which elements exist.
|
|
23
|
+
|
|
24
|
+
##### `values() -> ValuesView[int | float]:`
|
|
25
|
+
|
|
26
|
+
Return a view of all elements.
|
|
27
|
+
|
|
28
|
+
##### `items() -> ItemsView[tuple[int, int | float]]:`
|
|
29
|
+
|
|
30
|
+
Return an ItemsView for `for i, e in vec.items()` syntax.
|
|
31
|
+
|
|
32
|
+
##### `norm() -> float:`
|
|
33
|
+
|
|
34
|
+
Calculate the Euclidean norm of a SparseVector, defined as the square root of
|
|
35
|
+
the dot product of itself (i.e. the sqrt of the sum of the squares of the
|
|
36
|
+
elements). Raises `TypeError` for invalid input.
|
|
37
|
+
|
|
38
|
+
##### `dot_product(other: SparseVector) -> float:`
|
|
39
|
+
|
|
40
|
+
Calculate the dot product between two `SparseVector`s. Raises `TypeError` for
|
|
41
|
+
invalid other. Treats unset indices as 0 values mathematically.
|
|
42
|
+
|
|
43
|
+
##### `cosine_similarity(other: SparseVector) -> float:`
|
|
44
|
+
|
|
45
|
+
Calculate the cosine similarity with another SparseVector. Raises `TypeError`.
|
|
46
|
+
|
|
47
|
+
## Functions
|
|
48
|
+
|
|
49
|
+
### `hamming_distance(str1: str, str2: str, normalize: bool = False) -> int | float:`
|
|
50
|
+
|
|
51
|
+
Calculate Hamming distance between two strs. If `normalize` is `False`
|
|
52
|
+
(default), distance is returned directly as an int. If `normalize` is set to
|
|
53
|
+
`True`, the distance is normalized to a float proportional to the length of the
|
|
54
|
+
longest string.
|
|
55
|
+
|
|
56
|
+
### `hamming_similarity(str1: str, str2: str) -> float:`
|
|
57
|
+
|
|
58
|
+
Hamming similarity: 1 - normalized Hamming distance.
|
|
59
|
+
|
|
60
|
+
### `rank(score_fn: Callable, candidates: list) -> list[tuple[float, int]]:`
|
|
61
|
+
|
|
62
|
+
Ranks `candidates` using the `score_fn` callable. Returns a list of tuples in
|
|
63
|
+
form `(score: float, index: int)`, sorted by score descending.
|
|
64
|
+
|
|
65
|
+
### `select(rankings: list, k: int = 4) -> list[tuple[float, int]]:`
|
|
66
|
+
|
|
67
|
+
Select the top `k` from the rankings. Sorts beforehand. Assumes similarity
|
|
68
|
+
scores and not distance scores. Raises `TypeError` or `ValueError` for invalid
|
|
69
|
+
inputs.
|
|
70
|
+
|
|
71
|
+
### `levenshtein_distance(a: str, b: str, normalize: bool = False) -> int|float:`
|
|
72
|
+
|
|
73
|
+
Calculate Levenshtein distance between two strs. If `normalize` is `False`
|
|
74
|
+
(default), distance is returned directly as an int. If `normalize` is set to
|
|
75
|
+
`True`, the distance is normalized to a float proportional to the average
|
|
76
|
+
length of the strings, clamped to a max of 1.0. Optimized by `@lru_cache`
|
|
77
|
+
decorator -- be sure to use `.lower()` or `' '.join(tokenize())` on strings
|
|
78
|
+
before passing them in to avoid cache fragmentation.
|
|
79
|
+
|
|
80
|
+
### `levenshtein_similarity(a: str, b: str) -> float:`
|
|
81
|
+
|
|
82
|
+
Turns the normalized Levenshtein difference metric into a similarity metric by
|
|
83
|
+
substracting it from 1.0.
|
|
84
|
+
|
|
85
|
+
### `tokenize(text: str) -> list[str]:`
|
|
86
|
+
|
|
87
|
+
Preprocess some text by casting to lower, removing punctuation, and splitting on
|
|
88
|
+
word boundaries. Returns only alphanumeric tokens.
|
|
89
|
+
|
|
90
|
+
### `ngf_index(ng: str) -> int:`
|
|
91
|
+
|
|
92
|
+
Calculate the NGF vector index for a given alphanumeric N-Gram.
|
|
93
|
+
|
|
94
|
+
### `ng_count(text: str, N: int = 3, ngs: set = None) -> SparseVector:`
|
|
95
|
+
|
|
96
|
+
Calculate the N-Gram Count of some text. First step in NGF or NGF-IDF analysis,
|
|
97
|
+
where NGF is like TF but with N-Grams instead of whole words. The `N` parameter
|
|
98
|
+
controls N-Gram size. Produces a SparseVector with max length `36^N`, where
|
|
99
|
+
element index is ordered by N-Gram alphanumeric order, e.g. 000, 001, ..., 0a0,
|
|
100
|
+
0a1, ..., zzz.
|
|
101
|
+
|
|
102
|
+
### `ngf(text: str, N: int = 3, vec: SparseVector = None) -> SparseVector:`
|
|
103
|
+
|
|
104
|
+
Calculate the N-Gram Frequency of some text. Analogous to TF, but with N-Grams
|
|
105
|
+
instead of whole words. The `N` parameter controls N-Gram size. Produces a
|
|
106
|
+
SparseVector max length `36^N`, where element index is ordered by N-Gram
|
|
107
|
+
alphanumeric order, e.g. 000, 001, ..., 0a0, 0a1, ..., zzz. Pass `vec` result of
|
|
108
|
+
`ng_count` to bypass retokenization of the text and recalculation of N-Grams.
|
|
109
|
+
|
|
110
|
+
### `ngf_rank(query: str, text_vecs: list, N: int = 3) -> list[tuple[float, int]]:`
|
|
111
|
+
|
|
112
|
+
Runs NGF cosine similarity between the query and the text vectors. Returns a
|
|
113
|
+
sorted list of form `[(similarity, index)]`.
|
|
114
|
+
|
|
115
|
+
### `ngf_select(query: str, text_vecs: list, k: int = 4, N: int = 3) -> list[tuple[float, int]]:`
|
|
116
|
+
|
|
117
|
+
Runs NGF cosine similarity between the query and the text vectors. Returns the
|
|
118
|
+
top `k` candidates in a sorted list of form `[(similarity, index)]`.
|
|
119
|
+
|
|
120
|
+
### `ngf_idf_setup(corpus: list, N: int = 3) -> tuple[vicinus.sparse_vector.SparseVector, list[vicinus.sparse_vector.SparseVector]]:`
|
|
121
|
+
|
|
122
|
+
Processes a corpus, creating the vectors for each text in a pipeline: 1) extract
|
|
123
|
+
N-Grams and create NG count vectors; 2) aggregate corpus NG count vector; 3)
|
|
124
|
+
create NGF vectors; 4) calculate the IDF vector; 5) modify NGF vectors by
|
|
125
|
+
multiplying by the IDF vector. Returns the corpus IDF vector as well as the
|
|
126
|
+
NGF-IDF vectors to enable fuzzy search on queries.
|
|
127
|
+
|
|
128
|
+
### `ngf_idf_query(query: str, corpus_idf: SparseVector, N: int = 3) -> SparseVector:`
|
|
129
|
+
|
|
130
|
+
Processes a query, calculating the NGF-IDF vector for it using the corpus IDF
|
|
131
|
+
vector.
|
|
132
|
+
|
|
133
|
+
### `ngf_idf_rank(query: str, corpus_idf: SparseVector, text_vecs: list, N: int = 3) -> list[tuple[float, int]]:`
|
|
134
|
+
|
|
135
|
+
Runs NGF-IDF cosine similarity between the query and the text vectors. Returns a
|
|
136
|
+
sorted list of form `[(similarity, index)]`.
|
|
137
|
+
|
|
138
|
+
### `ngf_idf_select(query: str, corpus_idf: SparseVector, text_vecs: list, k: int = 4, N: int = 3) -> list[tuple[float, int]]:`
|
|
139
|
+
|
|
140
|
+
Runs NGF-IDF cosine similarity between the query and the text vectors. Returns
|
|
141
|
+
the top `k` candidates in a sorted list of form `[(similarity, index)]`.
|
|
142
|
+
|
|
143
|
+
### `n_grams(text: str, N: int = 3) -> set[str]:`
|
|
144
|
+
|
|
145
|
+
Extract the N-Grams of a text, defined as the set of unique substrings of the
|
|
146
|
+
given N.
|
|
147
|
+
|
|
148
|
+
### `jaccard_index(a: set, b: set) -> float:`
|
|
149
|
+
|
|
150
|
+
Calculate the Jaccard similarity index between two sets, e.g. of N-Grams.
|
|
151
|
+
Defined as the cardinality of the intersection divided by the cardinality of the
|
|
152
|
+
union.
|
|
153
|
+
|
|
154
|
+
### `list_samples() -> list[str]:`
|
|
155
|
+
|
|
156
|
+
Returns the list of bundled sample file names.
|
|
157
|
+
|
|
158
|
+
### `get_sample(name: str) -> str:`
|
|
159
|
+
|
|
160
|
+
Reads and returns the content of the named sample. Raises FileNotFoundError for
|
|
161
|
+
an invalid name.
|
|
162
|
+
|
|
163
|
+
### `version() -> str:`
|
|
164
|
+
|
|
165
|
+
Return the current library version.
|
|
166
|
+
|
vicinus-0.0.1/license
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan Voss (k98kurz)
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software
|
|
6
|
+
for any purpose with or without fee is hereby granted, provided
|
|
7
|
+
that the above copyright notice and this permission notice appear in
|
|
8
|
+
all copies.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
11
|
+
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
12
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
13
|
+
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
|
14
|
+
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
15
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
16
|
+
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
17
|
+
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|