fuzzgpu 0.1.0__cp39-abi3-win_amd64.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.
- LICENSE +21 -0
- README.md +225 -0
- assets/logo.png +0 -0
- assets/logo.svg +46 -0
- fuzzgpu/__init__.py +96 -0
- fuzzgpu/fuzz.py +18 -0
- fuzzgpu/fuzzgpu.pyd +0 -0
- fuzzgpu-0.1.0.dist-info/METADATA +253 -0
- fuzzgpu-0.1.0.dist-info/RECORD +12 -0
- fuzzgpu-0.1.0.dist-info/WHEEL +4 -0
- fuzzgpu-0.1.0.dist-info/licenses/LICENSE +21 -0
- fuzzgpu-0.1.0.dist-info/sboms/fuzzgpu-python.cyclonedx.json +3763 -0
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Flaxmbot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://raw.githubusercontent.com/kuntal-devrat/fuzzgpu/main/assets/logo.png" alt="fuzzgpu logo" width="140" height="140" />
|
|
4
|
+
|
|
5
|
+
# fuzzgpu
|
|
6
|
+
|
|
7
|
+
**Hardware-Accelerated Fuzzy String Matching & Sequence Alignment**
|
|
8
|
+
|
|
9
|
+
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
10
|
+
|
|
11
|
+
[](https://pypi.org/project/fuzzgpu/)
|
|
12
|
+
[](https://opensource.org/licenses/MIT)
|
|
13
|
+
[](https://www.rust-lang.org)
|
|
14
|
+
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
`fuzzgpu` is a high-throughput string distance and sequence alignment engine written in **Rust** with native **Python** and **WebAssembly** bindings. It leverages GPU compute shaders (`wgpu` / WGSL) and Rayon multi-threading to accelerate large-scale batch queries and distance matrix computations across:
|
|
23
|
+
|
|
24
|
+
- **Apple Silicon (Metal)**
|
|
25
|
+
- **Linux (Vulkan)**
|
|
26
|
+
- **Windows (DirectX 12 / Vulkan)**
|
|
27
|
+
- **Integrated GPUs (Intel Iris Xe, AMD Radeon)**
|
|
28
|
+
- **WebAssembly (In-browser execution)**
|
|
29
|
+
|
|
30
|
+
No NVIDIA CUDA drivers or complex toolkits required.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Benchmark Results
|
|
35
|
+
|
|
36
|
+
*Hardware: Intel(R) Iris(R) Xe Graphics (Vulkan) / Intel Core i7 CPU*
|
|
37
|
+
|
|
38
|
+
### 1. Damerau-Levenshtein Batch (1 Query × N Candidates)
|
|
39
|
+
| Batch Size | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RapidFuzz |
|
|
40
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
41
|
+
| **100** | **0.21 ms** | 0.36 ms | N/A | **1.74×** |
|
|
42
|
+
| **1,000** | **0.96 ms** | 3.72 ms | N/A | **3.88×** |
|
|
43
|
+
| **5,000** | **3.67 ms** | 18.44 ms | N/A | **5.02×** |
|
|
44
|
+
| **10,000** | **5.95 ms** | 37.46 ms | N/A | **6.30×** |
|
|
45
|
+
| **50,000** | **31.74 ms** | 85.87 ms | N/A | **2.71×** |
|
|
46
|
+
|
|
47
|
+
### 2. Levenshtein Cross-Product Matrix (`cdist` $N \times M$)
|
|
48
|
+
*Utilizing dedicated 2D Grid Workgroup Shaders with $O(N + M)$ memory bandwidth:*
|
|
49
|
+
| Matrix Size | Total Pairs | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RF | Speedup vs py-Lev |
|
|
50
|
+
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
51
|
+
| **10 × 10** | 100 | **0.04 ms** | 0.04 ms | 0.05 ms | 1.00× | **1.31×** |
|
|
52
|
+
| **50 × 50** | 2,500 | **2.22 ms** | 0.71 ms | 0.99 ms | 0.32× | 0.45× |
|
|
53
|
+
| **100 × 100** | 10,000 | **5.29 ms** | 3.51 ms | 4.03 ms | 0.66× | 0.76× |
|
|
54
|
+
| **200 × 200** | 40,000 | **15.05 ms** | 33.58 ms | 46.82 ms | **2.23×** | **3.11×** |
|
|
55
|
+
|
|
56
|
+
### 3. Jaro-Winkler Similarity Batch
|
|
57
|
+
| Batch Size | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RapidFuzz |
|
|
58
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
59
|
+
| **1,000** | **3.10 ms** | 0.81 ms | 1.13 ms | 0.26× |
|
|
60
|
+
| **5,000** | **6.56 ms** | 5.12 ms | 5.78 ms | 0.78× |
|
|
61
|
+
| **10,000** | **8.56 ms** | 7.80 ms | 9.17 ms | 0.91× |
|
|
62
|
+
| **50,000** | **33.24 ms** | 47.11 ms | 24.86 ms | **1.42×** |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
### Python
|
|
69
|
+
```bash
|
|
70
|
+
pip install fuzzgpu
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Rust (Cargo.toml)
|
|
74
|
+
```toml
|
|
75
|
+
[dependencies]
|
|
76
|
+
fuzzgpu-core = "0.1.0"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Quickstart
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import fuzzgpu
|
|
85
|
+
from fuzzgpu.fuzz import ratio, partial_ratio, token_sort_ratio, token_set_ratio, extract, extractOne
|
|
86
|
+
|
|
87
|
+
# 1. Classical Distance Metrics
|
|
88
|
+
lev = fuzzgpu.levenshtein_distance("kitten", "sitting") # 3
|
|
89
|
+
dam = fuzzgpu.damerau_levenshtein_distance("ab", "ba") # 1 (transposition-aware)
|
|
90
|
+
jw = fuzzgpu.jaro_winkler_similarity("MARTHA", "MARHTA", 0.1) # 0.9611
|
|
91
|
+
|
|
92
|
+
# 2. High-Throughput Batch Processing (Auto-dispatched to GPU/CPU)
|
|
93
|
+
candidates = ["hallo", "hullo", "jello", "yellow", "hello world"] * 10_000
|
|
94
|
+
distances = fuzzgpu.levenshtein_batch("hello", candidates)
|
|
95
|
+
jw_scores = fuzzgpu.jaro_winkler_batch("hello", candidates, prefix_weight=0.1)
|
|
96
|
+
|
|
97
|
+
# 3. 2D Cross-Product Distance Matrix (Dedicated 2D Grid Shader)
|
|
98
|
+
matrix = fuzzgpu.levenshtein_cdist(["abc", "def", "xyz"], ["abd", "axy", "def"])
|
|
99
|
+
|
|
100
|
+
# 4. Global Sequence Alignment (Gotoh 1982 Linear & Affine Gap Penalties)
|
|
101
|
+
score_linear = fuzzgpu.needleman_wunsch_score("AGTACGCA", "TATGC", match=2, mismatch=-1, gap=-2)
|
|
102
|
+
score_affine = fuzzgpu.needleman_wunsch_affine("AGTACGCA", "TATGC", match=2, mismatch=-1, gap_open=-3, gap_extend=-1)
|
|
103
|
+
|
|
104
|
+
# 5. RapidFuzz-Compatible Scorer & Search API
|
|
105
|
+
score = ratio("fuzzy was a bear", "fuzzy was a bear") # 100.0
|
|
106
|
+
part = partial_ratio("hello", "oh hello there") # 100.0
|
|
107
|
+
tsr = token_sort_ratio("new york mets", "mets new york") # 100.0
|
|
108
|
+
tset = token_set_ratio("fuzzy was a bear", "fuzzy bear") # 100.0
|
|
109
|
+
|
|
110
|
+
# 6. Top-K Best Match Search
|
|
111
|
+
best = extractOne("hellp", ["hello", "world", "help"], score_cutoff=50.0)
|
|
112
|
+
# Output: ("hello", 80.0, 0)
|
|
113
|
+
|
|
114
|
+
top_3 = extract("apple", ["apply", "ape", "banana", "applesauce"], score_cutoff=50.0, limit=3)
|
|
115
|
+
|
|
116
|
+
# 7. Hardware Diagnostics
|
|
117
|
+
print(fuzzgpu.gpu_info())
|
|
118
|
+
# Output: Intel(R) Iris(R) Xe Graphics (Vulkan) / Apple M2 (Metal)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Technical Architecture
|
|
124
|
+
|
|
125
|
+
`fuzzgpu` combines a tiered execution pipeline to balance low-latency single queries and high-throughput batch workloads:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
┌──────────────────────────┐
|
|
129
|
+
│ User Query / API │
|
|
130
|
+
└─────────────┬────────────┘
|
|
131
|
+
│
|
|
132
|
+
Batch Size / Dataset Assessment
|
|
133
|
+
│
|
|
134
|
+
┌───────────────────────┴───────────────────────┐
|
|
135
|
+
▼ ▼
|
|
136
|
+
Small Workloads (< 500) Large Batches (≥ 500)
|
|
137
|
+
│ │
|
|
138
|
+
┌───────────────────────────┐ ┌───────────────────────────┐
|
|
139
|
+
│ Rayon Multi-Threaded │ │ wgpu WebGPU Compute │
|
|
140
|
+
│ CPU Parallelism │ │ Shaders (Metal/Vulkan) │
|
|
141
|
+
│ - Myers 1999 Bit-Vector │ │ - 2D Workgroup Grids │
|
|
142
|
+
│ - Zero PCIe Latency │ │ - Streaming Chunking │
|
|
143
|
+
└───────────────────────────┘ └───────────────────────────┘
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Key Architectural Optimizations
|
|
147
|
+
|
|
148
|
+
1. **2D Grid Matrix Shaders (`levenshtein_matrix.wgsl` & `jaro_matrix.wgsl`)**:
|
|
149
|
+
Instead of duplicating string pairs across PCIe ($O(N \cdot M)$ transfers), List A and List B are uploaded once ($O(N + M)$ memory bandwidth). Workgroups execute on a 2D grid (`@workgroup_size(16, 16)`).
|
|
150
|
+
2. **Myers (1999) Bit-Parallel CPU Engine**:
|
|
151
|
+
For strings $\le 64$ characters, computes Levenshtein edit distance using bit-vector operations with zero inner dynamic programming loops ($O(N)$ execution).
|
|
152
|
+
3. **Lowrance & Wagner (1975) Unrestricted Damerau-Levenshtein**:
|
|
153
|
+
Full support for character insertions, deletions, substitutions, and arbitrary transpositions.
|
|
154
|
+
4. **Gotoh (1982) Affine Gap Sequence Alignment**:
|
|
155
|
+
Memory-efficient 3-state recurrence ($O(N)$ auxiliary space) for bioinformatics and long-sequence alignment.
|
|
156
|
+
5. **Streaming Chunk Partitioner**:
|
|
157
|
+
Datasets exceeding GPU buffer limits (>128MB or >500,000 pairs) are automatically streamed in chunks to prevent VRAM overflow.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Project Structure
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
fuzzgpu/
|
|
165
|
+
├── assets/
|
|
166
|
+
│ └── logo.svg # Vector brand asset
|
|
167
|
+
├── crates/
|
|
168
|
+
│ ├── fuzzgpu-core/ # Core Rust engine & compute shaders
|
|
169
|
+
│ │ ├── src/
|
|
170
|
+
│ │ │ ├── gpu.rs # wgpu instance and device singleton
|
|
171
|
+
│ │ │ ├── levenshtein.rs # Levenshtein kernel & 2D matrix dispatch
|
|
172
|
+
│ │ │ ├── damerau.rs # Lowrance-Wagner Damerau-Levenshtein
|
|
173
|
+
│ │ │ ├── needleman.rs # Needleman-Wunsch (Linear & Affine)
|
|
174
|
+
│ │ │ ├── jaro.rs # Jaro / Jaro-Winkler GPU & CPU kernels
|
|
175
|
+
│ │ │ ├── fuzz.rs # Fuzzy ratio, token sort/set, extract
|
|
176
|
+
│ │ │ ├── simd.rs # Myers bit-vector algorithms
|
|
177
|
+
│ │ │ └── shaders/ # WGSL compute shaders (1D & 2D)
|
|
178
|
+
│ ├── fuzzgpu-python/ # PyO3 CPython C-extension module
|
|
179
|
+
│ └── fuzzgpu-wasm/ # wasm-bindgen WebAssembly module
|
|
180
|
+
├── python/
|
|
181
|
+
│ └── fuzzgpu/ # Python package wrapper & typing
|
|
182
|
+
├── tests/
|
|
183
|
+
│ └── test_basic.py # Comprehensive test suite (50 tests)
|
|
184
|
+
└── benchmarks/
|
|
185
|
+
└── bench_compare.py # Comparative benchmarking harness
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Building from Source
|
|
191
|
+
|
|
192
|
+
### Prerequisites
|
|
193
|
+
- [Rust Toolchain (1.75+)](https://rustup.rs/)
|
|
194
|
+
- Python 3.8+ & `pip install maturin`
|
|
195
|
+
|
|
196
|
+
### Build Python Extension
|
|
197
|
+
```bash
|
|
198
|
+
# Clone the repository
|
|
199
|
+
git clone https://github.com/Flaxmbot/fuzzgpu.git
|
|
200
|
+
cd fuzzgpu
|
|
201
|
+
|
|
202
|
+
# Build and install into current virtual environment
|
|
203
|
+
maturin develop --release
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Run Tests & Benchmarks
|
|
207
|
+
```bash
|
|
208
|
+
# Run pytest verification suite
|
|
209
|
+
pytest tests/ -v
|
|
210
|
+
|
|
211
|
+
# Run comparative benchmark harness
|
|
212
|
+
python benchmarks/bench_compare.py
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Build WebAssembly (Browser Target)
|
|
216
|
+
```bash
|
|
217
|
+
cd crates/fuzzgpu-wasm
|
|
218
|
+
wasm-pack build --target web --release
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
This project is licensed under the [MIT License](LICENSE).
|
assets/logo.png
ADDED
|
Binary file
|
assets/logo.svg
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="100%" height="100%" fill="none">
|
|
2
|
+
<!-- Background Rounded Canvas -->
|
|
3
|
+
<rect width="256" height="256" rx="56" fill="#F8F9FA"/>
|
|
4
|
+
<rect x="8" y="8" width="240" height="240" rx="48" stroke="#E8EAED" stroke-width="4"/>
|
|
5
|
+
|
|
6
|
+
<!-- GPU Compute Core / String Matrix Geometry -->
|
|
7
|
+
<g transform="translate(48, 48)">
|
|
8
|
+
<!-- Base Silicon Chip Shadow / Accent -->
|
|
9
|
+
<rect x="0" y="0" width="160" height="160" rx="32" fill="#FFFFFF" stroke="#DADCE0" stroke-width="6"/>
|
|
10
|
+
|
|
11
|
+
<!-- Geometric Grid Rays & Hardware Pins -->
|
|
12
|
+
<rect x="36" y="-12" width="12" height="12" rx="4" fill="#1A73E8"/>
|
|
13
|
+
<rect x="74" y="-12" width="12" height="12" rx="4" fill="#1A73E8"/>
|
|
14
|
+
<rect x="112" y="-12" width="12" height="12" rx="4" fill="#1A73E8"/>
|
|
15
|
+
|
|
16
|
+
<rect x="36" y="160" width="12" height="12" rx="4" fill="#34A853"/>
|
|
17
|
+
<rect x="74" y="160" width="12" height="12" rx="4" fill="#34A853"/>
|
|
18
|
+
<rect x="112" y="160" width="12" height="12" rx="4" fill="#34A853"/>
|
|
19
|
+
|
|
20
|
+
<rect x="-12" y="36" width="12" height="12" rx="4" fill="#EA4335"/>
|
|
21
|
+
<rect x="-12" y="74" width="12" height="12" rx="4" fill="#EA4335"/>
|
|
22
|
+
<rect x="-12" y="112" width="12" height="12" rx="4" fill="#EA4335"/>
|
|
23
|
+
|
|
24
|
+
<rect x="160" y="36" width="12" height="12" rx="4" fill="#FBBC04"/>
|
|
25
|
+
<rect x="160" y="74" width="12" height="12" rx="4" fill="#FBBC04"/>
|
|
26
|
+
<rect x="160" y="112" width="12" height="12" rx="4" fill="#FBBC04"/>
|
|
27
|
+
|
|
28
|
+
<!-- Central Parallel Compute Lattice / "F" and Lightning Node -->
|
|
29
|
+
<!-- Top Bar: Google Blue -->
|
|
30
|
+
<rect x="32" y="32" width="96" height="24" rx="8" fill="#1A73E8"/>
|
|
31
|
+
|
|
32
|
+
<!-- Middle Stem: Google Coral Red -->
|
|
33
|
+
<rect x="32" y="32" width="24" height="96" rx="8" fill="#EA4335"/>
|
|
34
|
+
|
|
35
|
+
<!-- Middle Horizontal Branch: Google Amber -->
|
|
36
|
+
<rect x="32" y="68" width="68" height="22" rx="8" fill="#FBBC04"/>
|
|
37
|
+
|
|
38
|
+
<!-- High-Performance Acceleration Arrow / String Match Wave: Google Emerald Green -->
|
|
39
|
+
<path d="M72 108 L114 108 L128 122 L114 136 L72 136 Z" fill="#34A853"/>
|
|
40
|
+
|
|
41
|
+
<!-- Inner Core Processor Node -->
|
|
42
|
+
<circle cx="114" cy="44" r="7" fill="#FFFFFF"/>
|
|
43
|
+
<circle cx="86" cy="79" r="6" fill="#FFFFFF"/>
|
|
44
|
+
<circle cx="106" cy="122" r="5" fill="#FFFFFF"/>
|
|
45
|
+
</g>
|
|
46
|
+
</svg>
|
fuzzgpu/__init__.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fuzzgpu - GPU-accelerated fuzzy string matching.
|
|
3
|
+
|
|
4
|
+
Cross-platform GPU acceleration via wgpu (Metal, Vulkan, DX12).
|
|
5
|
+
No CUDA required. Works on Mac, Linux, Windows.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
import fuzzgpu
|
|
9
|
+
|
|
10
|
+
# Levenshtein & Damerau-Levenshtein
|
|
11
|
+
dist = fuzzgpu.levenshtein_distance("kitten", "sitting") # 3
|
|
12
|
+
dam = fuzzgpu.damerau_levenshtein_distance("ab", "ba") # 1
|
|
13
|
+
|
|
14
|
+
# Batch & Cross-product Matrix
|
|
15
|
+
distances = fuzzgpu.levenshtein_batch("hello", ["hallo", "hullo"])
|
|
16
|
+
matrix = fuzzgpu.levenshtein_cdist(["abc", "def"], ["abc", "xyz"])
|
|
17
|
+
|
|
18
|
+
# Needleman-Wunsch with linear or affine gap penalty
|
|
19
|
+
score = fuzzgpu.needleman_wunsch_score("AGTACGCA", "TATGC", 2, -1, -2)
|
|
20
|
+
score_affine = fuzzgpu.needleman_wunsch_affine("AGTACGCA", "TATGC", 2, -1, -3, -1)
|
|
21
|
+
|
|
22
|
+
# Jaro-Winkler similarity (GPU-accelerated for batches)
|
|
23
|
+
sim = fuzzgpu.jaro_winkler_similarity("MARTHA", "MARHTA", 0.1) # 0.96
|
|
24
|
+
jw_batch = fuzzgpu.jaro_winkler_batch("MARTHA", ["MARHTA", "MATRH"], 0.1)
|
|
25
|
+
|
|
26
|
+
# Fuzzy matching (rapidfuzz-compatible)
|
|
27
|
+
from fuzzgpu.fuzz import ratio, partial_ratio, token_sort_ratio, token_set_ratio, extract, extractOne
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from fuzzgpu.fuzzgpu import (
|
|
31
|
+
# Levenshtein
|
|
32
|
+
levenshtein_distance,
|
|
33
|
+
levenshtein_batch,
|
|
34
|
+
levenshtein_cdist,
|
|
35
|
+
# Damerau-Levenshtein
|
|
36
|
+
damerau_levenshtein_distance,
|
|
37
|
+
damerau_levenshtein_batch,
|
|
38
|
+
damerau_levenshtein_cdist,
|
|
39
|
+
damerau_ratio,
|
|
40
|
+
# Needleman-Wunsch
|
|
41
|
+
needleman_wunsch_score,
|
|
42
|
+
needleman_wunsch_batch_fn,
|
|
43
|
+
needleman_wunsch_affine,
|
|
44
|
+
needleman_wunsch_affine_batch,
|
|
45
|
+
# Jaro-Winkler
|
|
46
|
+
jaro_similarity,
|
|
47
|
+
jaro_winkler_similarity,
|
|
48
|
+
jaro_winkler_batch_fn,
|
|
49
|
+
jaro_winkler_cdist,
|
|
50
|
+
# Fuzzy matching
|
|
51
|
+
fuzz_ratio,
|
|
52
|
+
fuzz_partial_ratio,
|
|
53
|
+
fuzz_token_sort_ratio,
|
|
54
|
+
fuzz_token_set_ratio,
|
|
55
|
+
fuzz_wratio,
|
|
56
|
+
fuzz_ratio_batch,
|
|
57
|
+
fuzz_extract,
|
|
58
|
+
fuzz_extract_one,
|
|
59
|
+
# Optimized algorithm variants
|
|
60
|
+
levenshtein_myers,
|
|
61
|
+
needleman_wunsch_striped,
|
|
62
|
+
jaro_optimized,
|
|
63
|
+
# GPU
|
|
64
|
+
gpu_info,
|
|
65
|
+
__version__,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Re-export with clean names
|
|
69
|
+
levenshtein = levenshtein_distance
|
|
70
|
+
damerau_levenshtein = damerau_levenshtein_distance
|
|
71
|
+
needleman_wunsch = needleman_wunsch_score
|
|
72
|
+
needleman_wunsch_batch = needleman_wunsch_batch_fn
|
|
73
|
+
jaro_winkler_batch = jaro_winkler_batch_fn
|
|
74
|
+
ratio = fuzz_ratio
|
|
75
|
+
partial_ratio = fuzz_partial_ratio
|
|
76
|
+
token_sort_ratio = fuzz_token_sort_ratio
|
|
77
|
+
token_set_ratio = fuzz_token_set_ratio
|
|
78
|
+
wratio = fuzz_wratio
|
|
79
|
+
ratio_batch = fuzz_ratio_batch
|
|
80
|
+
extract = fuzz_extract
|
|
81
|
+
extractOne = fuzz_extract_one
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
"levenshtein_distance", "levenshtein_batch", "levenshtein_cdist",
|
|
85
|
+
"damerau_levenshtein_distance", "damerau_levenshtein_batch", "damerau_levenshtein_cdist", "damerau_ratio",
|
|
86
|
+
"needleman_wunsch_score", "needleman_wunsch_batch_fn", "needleman_wunsch_affine", "needleman_wunsch_affine_batch",
|
|
87
|
+
"jaro_similarity", "jaro_winkler_similarity", "jaro_winkler_batch_fn", "jaro_winkler_cdist",
|
|
88
|
+
"fuzz_ratio", "fuzz_partial_ratio", "fuzz_token_sort_ratio", "fuzz_token_set_ratio",
|
|
89
|
+
"fuzz_wratio", "fuzz_ratio_batch", "fuzz_extract", "fuzz_extract_one",
|
|
90
|
+
"levenshtein_myers", "needleman_wunsch_striped", "jaro_optimized",
|
|
91
|
+
"gpu_info", "__version__",
|
|
92
|
+
# Aliases
|
|
93
|
+
"levenshtein", "damerau_levenshtein", "needleman_wunsch", "needleman_wunsch_batch",
|
|
94
|
+
"jaro_winkler_batch", "ratio", "partial_ratio", "token_sort_ratio", "token_set_ratio",
|
|
95
|
+
"wratio", "ratio_batch", "extract", "extractOne",
|
|
96
|
+
]
|
fuzzgpu/fuzz.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""rapidfuzz-compatible API for fuzzgpu — delegates to Rust implementations."""
|
|
2
|
+
|
|
3
|
+
from fuzzgpu.fuzzgpu import (
|
|
4
|
+
fuzz_ratio as ratio,
|
|
5
|
+
fuzz_partial_ratio as partial_ratio,
|
|
6
|
+
fuzz_token_sort_ratio as token_sort_ratio,
|
|
7
|
+
fuzz_token_set_ratio as token_set_ratio,
|
|
8
|
+
fuzz_wratio as WRatio,
|
|
9
|
+
fuzz_ratio_batch as ratio_batch,
|
|
10
|
+
fuzz_extract as extract,
|
|
11
|
+
fuzz_extract_one as extractOne,
|
|
12
|
+
damerau_ratio as damerau_ratio,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"ratio", "partial_ratio", "token_sort_ratio", "token_set_ratio",
|
|
17
|
+
"WRatio", "ratio_batch", "extract", "extractOne", "damerau_ratio",
|
|
18
|
+
]
|
fuzzgpu/fuzzgpu.pyd
ADDED
|
Binary file
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fuzzgpu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering
|
|
15
|
+
Classifier: Topic :: Text Processing :: General
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Summary: Hardware-accelerated fuzzy string matching & sequence alignment — cross-platform, no CUDA required
|
|
18
|
+
Keywords: gpu,fuzzy,string-matching,levenshtein,damerau,jaro-winkler,needleman-wunsch,webgpu
|
|
19
|
+
Home-Page: https://github.com/kuntal-devrat/fuzzgpu
|
|
20
|
+
Author: Devrat Kuntal
|
|
21
|
+
License: MIT
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
24
|
+
Project-URL: Homepage, https://github.com/kuntal-devrat/fuzzgpu
|
|
25
|
+
Project-URL: Issues, https://github.com/kuntal-devrat/fuzzgpu/issues
|
|
26
|
+
Project-URL: Repository, https://github.com/kuntal-devrat/fuzzgpu
|
|
27
|
+
|
|
28
|
+
<div align="center">
|
|
29
|
+
|
|
30
|
+
<img src="https://raw.githubusercontent.com/kuntal-devrat/fuzzgpu/main/assets/logo.png" alt="fuzzgpu logo" width="140" height="140" />
|
|
31
|
+
|
|
32
|
+
# fuzzgpu
|
|
33
|
+
|
|
34
|
+
**Hardware-Accelerated Fuzzy String Matching & Sequence Alignment**
|
|
35
|
+
|
|
36
|
+
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
37
|
+
|
|
38
|
+
[](https://pypi.org/project/fuzzgpu/)
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
[](https://www.rust-lang.org)
|
|
41
|
+
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
42
|
+
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
|
|
49
|
+
`fuzzgpu` is a high-throughput string distance and sequence alignment engine written in **Rust** with native **Python** and **WebAssembly** bindings. It leverages GPU compute shaders (`wgpu` / WGSL) and Rayon multi-threading to accelerate large-scale batch queries and distance matrix computations across:
|
|
50
|
+
|
|
51
|
+
- **Apple Silicon (Metal)**
|
|
52
|
+
- **Linux (Vulkan)**
|
|
53
|
+
- **Windows (DirectX 12 / Vulkan)**
|
|
54
|
+
- **Integrated GPUs (Intel Iris Xe, AMD Radeon)**
|
|
55
|
+
- **WebAssembly (In-browser execution)**
|
|
56
|
+
|
|
57
|
+
No NVIDIA CUDA drivers or complex toolkits required.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Benchmark Results
|
|
62
|
+
|
|
63
|
+
*Hardware: Intel(R) Iris(R) Xe Graphics (Vulkan) / Intel Core i7 CPU*
|
|
64
|
+
|
|
65
|
+
### 1. Damerau-Levenshtein Batch (1 Query × N Candidates)
|
|
66
|
+
| Batch Size | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RapidFuzz |
|
|
67
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
68
|
+
| **100** | **0.21 ms** | 0.36 ms | N/A | **1.74×** |
|
|
69
|
+
| **1,000** | **0.96 ms** | 3.72 ms | N/A | **3.88×** |
|
|
70
|
+
| **5,000** | **3.67 ms** | 18.44 ms | N/A | **5.02×** |
|
|
71
|
+
| **10,000** | **5.95 ms** | 37.46 ms | N/A | **6.30×** |
|
|
72
|
+
| **50,000** | **31.74 ms** | 85.87 ms | N/A | **2.71×** |
|
|
73
|
+
|
|
74
|
+
### 2. Levenshtein Cross-Product Matrix (`cdist` $N \times M$)
|
|
75
|
+
*Utilizing dedicated 2D Grid Workgroup Shaders with $O(N + M)$ memory bandwidth:*
|
|
76
|
+
| Matrix Size | Total Pairs | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RF | Speedup vs py-Lev |
|
|
77
|
+
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
78
|
+
| **10 × 10** | 100 | **0.04 ms** | 0.04 ms | 0.05 ms | 1.00× | **1.31×** |
|
|
79
|
+
| **50 × 50** | 2,500 | **2.22 ms** | 0.71 ms | 0.99 ms | 0.32× | 0.45× |
|
|
80
|
+
| **100 × 100** | 10,000 | **5.29 ms** | 3.51 ms | 4.03 ms | 0.66× | 0.76× |
|
|
81
|
+
| **200 × 200** | 40,000 | **15.05 ms** | 33.58 ms | 46.82 ms | **2.23×** | **3.11×** |
|
|
82
|
+
|
|
83
|
+
### 3. Jaro-Winkler Similarity Batch
|
|
84
|
+
| Batch Size | `fuzzgpu` | `rapidfuzz` | `python-Levenshtein` | Speedup vs RapidFuzz |
|
|
85
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
86
|
+
| **1,000** | **3.10 ms** | 0.81 ms | 1.13 ms | 0.26× |
|
|
87
|
+
| **5,000** | **6.56 ms** | 5.12 ms | 5.78 ms | 0.78× |
|
|
88
|
+
| **10,000** | **8.56 ms** | 7.80 ms | 9.17 ms | 0.91× |
|
|
89
|
+
| **50,000** | **33.24 ms** | 47.11 ms | 24.86 ms | **1.42×** |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Installation
|
|
94
|
+
|
|
95
|
+
### Python
|
|
96
|
+
```bash
|
|
97
|
+
pip install fuzzgpu
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Rust (Cargo.toml)
|
|
101
|
+
```toml
|
|
102
|
+
[dependencies]
|
|
103
|
+
fuzzgpu-core = "0.1.0"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Quickstart
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import fuzzgpu
|
|
112
|
+
from fuzzgpu.fuzz import ratio, partial_ratio, token_sort_ratio, token_set_ratio, extract, extractOne
|
|
113
|
+
|
|
114
|
+
# 1. Classical Distance Metrics
|
|
115
|
+
lev = fuzzgpu.levenshtein_distance("kitten", "sitting") # 3
|
|
116
|
+
dam = fuzzgpu.damerau_levenshtein_distance("ab", "ba") # 1 (transposition-aware)
|
|
117
|
+
jw = fuzzgpu.jaro_winkler_similarity("MARTHA", "MARHTA", 0.1) # 0.9611
|
|
118
|
+
|
|
119
|
+
# 2. High-Throughput Batch Processing (Auto-dispatched to GPU/CPU)
|
|
120
|
+
candidates = ["hallo", "hullo", "jello", "yellow", "hello world"] * 10_000
|
|
121
|
+
distances = fuzzgpu.levenshtein_batch("hello", candidates)
|
|
122
|
+
jw_scores = fuzzgpu.jaro_winkler_batch("hello", candidates, prefix_weight=0.1)
|
|
123
|
+
|
|
124
|
+
# 3. 2D Cross-Product Distance Matrix (Dedicated 2D Grid Shader)
|
|
125
|
+
matrix = fuzzgpu.levenshtein_cdist(["abc", "def", "xyz"], ["abd", "axy", "def"])
|
|
126
|
+
|
|
127
|
+
# 4. Global Sequence Alignment (Gotoh 1982 Linear & Affine Gap Penalties)
|
|
128
|
+
score_linear = fuzzgpu.needleman_wunsch_score("AGTACGCA", "TATGC", match=2, mismatch=-1, gap=-2)
|
|
129
|
+
score_affine = fuzzgpu.needleman_wunsch_affine("AGTACGCA", "TATGC", match=2, mismatch=-1, gap_open=-3, gap_extend=-1)
|
|
130
|
+
|
|
131
|
+
# 5. RapidFuzz-Compatible Scorer & Search API
|
|
132
|
+
score = ratio("fuzzy was a bear", "fuzzy was a bear") # 100.0
|
|
133
|
+
part = partial_ratio("hello", "oh hello there") # 100.0
|
|
134
|
+
tsr = token_sort_ratio("new york mets", "mets new york") # 100.0
|
|
135
|
+
tset = token_set_ratio("fuzzy was a bear", "fuzzy bear") # 100.0
|
|
136
|
+
|
|
137
|
+
# 6. Top-K Best Match Search
|
|
138
|
+
best = extractOne("hellp", ["hello", "world", "help"], score_cutoff=50.0)
|
|
139
|
+
# Output: ("hello", 80.0, 0)
|
|
140
|
+
|
|
141
|
+
top_3 = extract("apple", ["apply", "ape", "banana", "applesauce"], score_cutoff=50.0, limit=3)
|
|
142
|
+
|
|
143
|
+
# 7. Hardware Diagnostics
|
|
144
|
+
print(fuzzgpu.gpu_info())
|
|
145
|
+
# Output: Intel(R) Iris(R) Xe Graphics (Vulkan) / Apple M2 (Metal)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Technical Architecture
|
|
151
|
+
|
|
152
|
+
`fuzzgpu` combines a tiered execution pipeline to balance low-latency single queries and high-throughput batch workloads:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
┌──────────────────────────┐
|
|
156
|
+
│ User Query / API │
|
|
157
|
+
└─────────────┬────────────┘
|
|
158
|
+
│
|
|
159
|
+
Batch Size / Dataset Assessment
|
|
160
|
+
│
|
|
161
|
+
┌───────────────────────┴───────────────────────┐
|
|
162
|
+
▼ ▼
|
|
163
|
+
Small Workloads (< 500) Large Batches (≥ 500)
|
|
164
|
+
│ │
|
|
165
|
+
┌───────────────────────────┐ ┌───────────────────────────┐
|
|
166
|
+
│ Rayon Multi-Threaded │ │ wgpu WebGPU Compute │
|
|
167
|
+
│ CPU Parallelism │ │ Shaders (Metal/Vulkan) │
|
|
168
|
+
│ - Myers 1999 Bit-Vector │ │ - 2D Workgroup Grids │
|
|
169
|
+
│ - Zero PCIe Latency │ │ - Streaming Chunking │
|
|
170
|
+
└───────────────────────────┘ └───────────────────────────┘
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Key Architectural Optimizations
|
|
174
|
+
|
|
175
|
+
1. **2D Grid Matrix Shaders (`levenshtein_matrix.wgsl` & `jaro_matrix.wgsl`)**:
|
|
176
|
+
Instead of duplicating string pairs across PCIe ($O(N \cdot M)$ transfers), List A and List B are uploaded once ($O(N + M)$ memory bandwidth). Workgroups execute on a 2D grid (`@workgroup_size(16, 16)`).
|
|
177
|
+
2. **Myers (1999) Bit-Parallel CPU Engine**:
|
|
178
|
+
For strings $\le 64$ characters, computes Levenshtein edit distance using bit-vector operations with zero inner dynamic programming loops ($O(N)$ execution).
|
|
179
|
+
3. **Lowrance & Wagner (1975) Unrestricted Damerau-Levenshtein**:
|
|
180
|
+
Full support for character insertions, deletions, substitutions, and arbitrary transpositions.
|
|
181
|
+
4. **Gotoh (1982) Affine Gap Sequence Alignment**:
|
|
182
|
+
Memory-efficient 3-state recurrence ($O(N)$ auxiliary space) for bioinformatics and long-sequence alignment.
|
|
183
|
+
5. **Streaming Chunk Partitioner**:
|
|
184
|
+
Datasets exceeding GPU buffer limits (>128MB or >500,000 pairs) are automatically streamed in chunks to prevent VRAM overflow.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Project Structure
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
fuzzgpu/
|
|
192
|
+
├── assets/
|
|
193
|
+
│ └── logo.svg # Vector brand asset
|
|
194
|
+
├── crates/
|
|
195
|
+
│ ├── fuzzgpu-core/ # Core Rust engine & compute shaders
|
|
196
|
+
│ │ ├── src/
|
|
197
|
+
│ │ │ ├── gpu.rs # wgpu instance and device singleton
|
|
198
|
+
│ │ │ ├── levenshtein.rs # Levenshtein kernel & 2D matrix dispatch
|
|
199
|
+
│ │ │ ├── damerau.rs # Lowrance-Wagner Damerau-Levenshtein
|
|
200
|
+
│ │ │ ├── needleman.rs # Needleman-Wunsch (Linear & Affine)
|
|
201
|
+
│ │ │ ├── jaro.rs # Jaro / Jaro-Winkler GPU & CPU kernels
|
|
202
|
+
│ │ │ ├── fuzz.rs # Fuzzy ratio, token sort/set, extract
|
|
203
|
+
│ │ │ ├── simd.rs # Myers bit-vector algorithms
|
|
204
|
+
│ │ │ └── shaders/ # WGSL compute shaders (1D & 2D)
|
|
205
|
+
│ ├── fuzzgpu-python/ # PyO3 CPython C-extension module
|
|
206
|
+
│ └── fuzzgpu-wasm/ # wasm-bindgen WebAssembly module
|
|
207
|
+
├── python/
|
|
208
|
+
│ └── fuzzgpu/ # Python package wrapper & typing
|
|
209
|
+
├── tests/
|
|
210
|
+
│ └── test_basic.py # Comprehensive test suite (50 tests)
|
|
211
|
+
└── benchmarks/
|
|
212
|
+
└── bench_compare.py # Comparative benchmarking harness
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Building from Source
|
|
218
|
+
|
|
219
|
+
### Prerequisites
|
|
220
|
+
- [Rust Toolchain (1.75+)](https://rustup.rs/)
|
|
221
|
+
- Python 3.8+ & `pip install maturin`
|
|
222
|
+
|
|
223
|
+
### Build Python Extension
|
|
224
|
+
```bash
|
|
225
|
+
# Clone the repository
|
|
226
|
+
git clone https://github.com/Flaxmbot/fuzzgpu.git
|
|
227
|
+
cd fuzzgpu
|
|
228
|
+
|
|
229
|
+
# Build and install into current virtual environment
|
|
230
|
+
maturin develop --release
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Run Tests & Benchmarks
|
|
234
|
+
```bash
|
|
235
|
+
# Run pytest verification suite
|
|
236
|
+
pytest tests/ -v
|
|
237
|
+
|
|
238
|
+
# Run comparative benchmark harness
|
|
239
|
+
python benchmarks/bench_compare.py
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Build WebAssembly (Browser Target)
|
|
243
|
+
```bash
|
|
244
|
+
cd crates/fuzzgpu-wasm
|
|
245
|
+
wasm-pack build --target web --release
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
253
|
+
|