fuzzgpu 0.4.0__tar.gz → 0.4.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.
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/Cargo.lock +44 -44
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/PKG-INFO +30 -13
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/README.md +29 -12
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/Cargo.toml +1 -1
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/gpu.rs +28 -13
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/lib.rs +8 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/needleman_wavefront.wgsl +9 -9
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/simd.rs +9 -3
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/tests/differential.rs +3 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/tests/kernel_registration.rs +2 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-python/Cargo.toml +2 -2
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-python/src/lib.rs +30 -5
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-wasm/Cargo.toml +1 -1
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/pyproject.toml +1 -1
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/__init__.pyi +35 -8
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Levenshtein.py +20 -8
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/fuzz.pyi +14 -0
- fuzzgpu-0.4.1/python/fuzzgpu/py.typed +1 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_out_buffers.py +8 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_rapidfuzz_differential.py +13 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/Cargo.toml +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/LICENSE +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/assets/logo.png +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/benches/bench.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/damerau.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/fuzz.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/jaro.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/levenshtein.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/needleman.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/damerau.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/damerau_matrix.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/jaro.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/jaro_matrix.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein_cdist_myers.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein_matrix.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein_myers.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein_short.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/needleman_affine.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/tests/differential.proptest-regressions +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/tests/fixtures/broken.wgsl +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-wasm/src/lib.rs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-wasm/tests/differential_harness.js +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-wasm/tests/js_api.test.cjs +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/__init__.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/DamerauLevenshtein.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Hamming.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Indel.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Jaro.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/JaroWinkler.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/LCSseq.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/OSA.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Postfix.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/Prefix.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/__init__.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/__init__.pyi +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/distance/_common.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/fuzz.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/process.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/python/fuzzgpu/process.pyi +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_api_signatures.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_basic.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_concurrency.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_edge_cases.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_gpu_health.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_gpu_threshold_env.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_invariants.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_rapidfuzz_compat.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/test_stress.py +0 -0
- {fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/tests/wasm_python_differential.py +0 -0
|
@@ -91,9 +91,9 @@ checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
|
|
|
91
91
|
|
|
92
92
|
[[package]]
|
|
93
93
|
name = "bitflags"
|
|
94
|
-
version = "2.13.
|
|
94
|
+
version = "2.13.2"
|
|
95
95
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
96
|
-
checksum = "
|
|
96
|
+
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
|
97
97
|
|
|
98
98
|
[[package]]
|
|
99
99
|
name = "block2"
|
|
@@ -121,13 +121,13 @@ dependencies = [
|
|
|
121
121
|
|
|
122
122
|
[[package]]
|
|
123
123
|
name = "bytemuck_derive"
|
|
124
|
-
version = "1.12.
|
|
124
|
+
version = "1.12.1"
|
|
125
125
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
126
|
-
checksum = "
|
|
126
|
+
checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c"
|
|
127
127
|
dependencies = [
|
|
128
128
|
"proc-macro2",
|
|
129
129
|
"quote",
|
|
130
|
-
"syn 3.0.
|
|
130
|
+
"syn 3.0.5",
|
|
131
131
|
]
|
|
132
132
|
|
|
133
133
|
[[package]]
|
|
@@ -249,9 +249,9 @@ dependencies = [
|
|
|
249
249
|
|
|
250
250
|
[[package]]
|
|
251
251
|
name = "crossbeam-deque"
|
|
252
|
-
version = "0.8.
|
|
252
|
+
version = "0.8.8"
|
|
253
253
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
254
|
-
checksum = "
|
|
254
|
+
checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
|
|
255
255
|
dependencies = [
|
|
256
256
|
"crossbeam-epoch",
|
|
257
257
|
"crossbeam-utils",
|
|
@@ -259,18 +259,18 @@ dependencies = [
|
|
|
259
259
|
|
|
260
260
|
[[package]]
|
|
261
261
|
name = "crossbeam-epoch"
|
|
262
|
-
version = "0.9.
|
|
262
|
+
version = "0.9.21"
|
|
263
263
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
264
|
-
checksum = "
|
|
264
|
+
checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
|
|
265
265
|
dependencies = [
|
|
266
266
|
"crossbeam-utils",
|
|
267
267
|
]
|
|
268
268
|
|
|
269
269
|
[[package]]
|
|
270
270
|
name = "crossbeam-utils"
|
|
271
|
-
version = "0.8.
|
|
271
|
+
version = "0.8.23"
|
|
272
272
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
273
|
-
checksum = "
|
|
273
|
+
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
|
|
274
274
|
|
|
275
275
|
[[package]]
|
|
276
276
|
name = "crunchy"
|
|
@@ -372,7 +372,7 @@ dependencies = [
|
|
|
372
372
|
|
|
373
373
|
[[package]]
|
|
374
374
|
name = "fuzzgpu-core"
|
|
375
|
-
version = "0.4.
|
|
375
|
+
version = "0.4.1"
|
|
376
376
|
dependencies = [
|
|
377
377
|
"bytemuck",
|
|
378
378
|
"criterion",
|
|
@@ -386,7 +386,7 @@ dependencies = [
|
|
|
386
386
|
|
|
387
387
|
[[package]]
|
|
388
388
|
name = "fuzzgpu-python"
|
|
389
|
-
version = "0.4.
|
|
389
|
+
version = "0.4.1"
|
|
390
390
|
dependencies = [
|
|
391
391
|
"fuzzgpu-core",
|
|
392
392
|
"log",
|
|
@@ -504,15 +504,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
|
504
504
|
|
|
505
505
|
[[package]]
|
|
506
506
|
name = "hermit-abi"
|
|
507
|
-
version = "0.5.
|
|
507
|
+
version = "0.5.3"
|
|
508
508
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
509
|
-
checksum = "
|
|
509
|
+
checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
|
|
510
510
|
|
|
511
511
|
[[package]]
|
|
512
512
|
name = "indexmap"
|
|
513
|
-
version = "2.14.
|
|
513
|
+
version = "2.14.2"
|
|
514
514
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
515
|
-
checksum = "
|
|
515
|
+
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
|
|
516
516
|
dependencies = [
|
|
517
517
|
"equivalent",
|
|
518
518
|
"hashbrown 0.17.1",
|
|
@@ -574,9 +574,9 @@ dependencies = [
|
|
|
574
574
|
|
|
575
575
|
[[package]]
|
|
576
576
|
name = "js-sys"
|
|
577
|
-
version = "0.3.
|
|
577
|
+
version = "0.3.105"
|
|
578
578
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
579
|
-
checksum = "
|
|
579
|
+
checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e"
|
|
580
580
|
dependencies = [
|
|
581
581
|
"cfg-if",
|
|
582
582
|
"futures-util",
|
|
@@ -955,9 +955,9 @@ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
|
955
955
|
|
|
956
956
|
[[package]]
|
|
957
957
|
name = "portable-atomic-util"
|
|
958
|
-
version = "0.2.
|
|
958
|
+
version = "0.2.8"
|
|
959
959
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
960
|
-
checksum = "
|
|
960
|
+
checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
|
|
961
961
|
dependencies = [
|
|
962
962
|
"portable-atomic",
|
|
963
963
|
]
|
|
@@ -1312,7 +1312,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
|
1312
1312
|
dependencies = [
|
|
1313
1313
|
"proc-macro2",
|
|
1314
1314
|
"quote",
|
|
1315
|
-
"syn 3.0.
|
|
1315
|
+
"syn 3.0.5",
|
|
1316
1316
|
]
|
|
1317
1317
|
|
|
1318
1318
|
[[package]]
|
|
@@ -1345,9 +1345,9 @@ dependencies = [
|
|
|
1345
1345
|
|
|
1346
1346
|
[[package]]
|
|
1347
1347
|
name = "smallvec"
|
|
1348
|
-
version = "1.
|
|
1348
|
+
version = "1.16.1"
|
|
1349
1349
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1350
|
-
checksum = "
|
|
1350
|
+
checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891"
|
|
1351
1351
|
|
|
1352
1352
|
[[package]]
|
|
1353
1353
|
name = "spirv"
|
|
@@ -1377,9 +1377,9 @@ dependencies = [
|
|
|
1377
1377
|
|
|
1378
1378
|
[[package]]
|
|
1379
1379
|
name = "syn"
|
|
1380
|
-
version = "3.0.
|
|
1380
|
+
version = "3.0.5"
|
|
1381
1381
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1382
|
-
checksum = "
|
|
1382
|
+
checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
|
|
1383
1383
|
dependencies = [
|
|
1384
1384
|
"proc-macro2",
|
|
1385
1385
|
"quote",
|
|
@@ -1431,7 +1431,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
|
|
|
1431
1431
|
dependencies = [
|
|
1432
1432
|
"proc-macro2",
|
|
1433
1433
|
"quote",
|
|
1434
|
-
"syn 3.0.
|
|
1434
|
+
"syn 3.0.5",
|
|
1435
1435
|
]
|
|
1436
1436
|
|
|
1437
1437
|
[[package]]
|
|
@@ -1498,9 +1498,9 @@ dependencies = [
|
|
|
1498
1498
|
|
|
1499
1499
|
[[package]]
|
|
1500
1500
|
name = "wasm-bindgen"
|
|
1501
|
-
version = "0.2.
|
|
1501
|
+
version = "0.2.128"
|
|
1502
1502
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1503
|
-
checksum = "
|
|
1503
|
+
checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
|
|
1504
1504
|
dependencies = [
|
|
1505
1505
|
"cfg-if",
|
|
1506
1506
|
"once_cell",
|
|
@@ -1511,9 +1511,9 @@ dependencies = [
|
|
|
1511
1511
|
|
|
1512
1512
|
[[package]]
|
|
1513
1513
|
name = "wasm-bindgen-futures"
|
|
1514
|
-
version = "0.4.
|
|
1514
|
+
version = "0.4.78"
|
|
1515
1515
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1516
|
-
checksum = "
|
|
1516
|
+
checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928"
|
|
1517
1517
|
dependencies = [
|
|
1518
1518
|
"js-sys",
|
|
1519
1519
|
"wasm-bindgen",
|
|
@@ -1521,9 +1521,9 @@ dependencies = [
|
|
|
1521
1521
|
|
|
1522
1522
|
[[package]]
|
|
1523
1523
|
name = "wasm-bindgen-macro"
|
|
1524
|
-
version = "0.2.
|
|
1524
|
+
version = "0.2.128"
|
|
1525
1525
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1526
|
-
checksum = "
|
|
1526
|
+
checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
|
|
1527
1527
|
dependencies = [
|
|
1528
1528
|
"quote",
|
|
1529
1529
|
"wasm-bindgen-macro-support",
|
|
@@ -1531,22 +1531,22 @@ dependencies = [
|
|
|
1531
1531
|
|
|
1532
1532
|
[[package]]
|
|
1533
1533
|
name = "wasm-bindgen-macro-support"
|
|
1534
|
-
version = "0.2.
|
|
1534
|
+
version = "0.2.128"
|
|
1535
1535
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1536
|
-
checksum = "
|
|
1536
|
+
checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
|
|
1537
1537
|
dependencies = [
|
|
1538
1538
|
"bumpalo",
|
|
1539
1539
|
"proc-macro2",
|
|
1540
1540
|
"quote",
|
|
1541
|
-
"syn
|
|
1541
|
+
"syn 3.0.5",
|
|
1542
1542
|
"wasm-bindgen-shared",
|
|
1543
1543
|
]
|
|
1544
1544
|
|
|
1545
1545
|
[[package]]
|
|
1546
1546
|
name = "wasm-bindgen-shared"
|
|
1547
|
-
version = "0.2.
|
|
1547
|
+
version = "0.2.128"
|
|
1548
1548
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1549
|
-
checksum = "
|
|
1549
|
+
checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
|
|
1550
1550
|
dependencies = [
|
|
1551
1551
|
"unicode-ident",
|
|
1552
1552
|
]
|
|
@@ -1565,9 +1565,9 @@ dependencies = [
|
|
|
1565
1565
|
|
|
1566
1566
|
[[package]]
|
|
1567
1567
|
name = "web-sys"
|
|
1568
|
-
version = "0.3.
|
|
1568
|
+
version = "0.3.105"
|
|
1569
1569
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1570
|
-
checksum = "
|
|
1570
|
+
checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8"
|
|
1571
1571
|
dependencies = [
|
|
1572
1572
|
"js-sys",
|
|
1573
1573
|
"wasm-bindgen",
|
|
@@ -1888,18 +1888,18 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
|
|
1888
1888
|
|
|
1889
1889
|
[[package]]
|
|
1890
1890
|
name = "zerocopy"
|
|
1891
|
-
version = "0.8.
|
|
1891
|
+
version = "0.8.57"
|
|
1892
1892
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1893
|
-
checksum = "
|
|
1893
|
+
checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873"
|
|
1894
1894
|
dependencies = [
|
|
1895
1895
|
"zerocopy-derive",
|
|
1896
1896
|
]
|
|
1897
1897
|
|
|
1898
1898
|
[[package]]
|
|
1899
1899
|
name = "zerocopy-derive"
|
|
1900
|
-
version = "0.8.
|
|
1900
|
+
version = "0.8.57"
|
|
1901
1901
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1902
|
-
checksum = "
|
|
1902
|
+
checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc"
|
|
1903
1903
|
dependencies = [
|
|
1904
1904
|
"proc-macro2",
|
|
1905
1905
|
"quote",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fuzzgpu
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -38,7 +38,7 @@ Project-URL: Repository, https://github.com/kuntal-devrat/fuzzgpu
|
|
|
38
38
|
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
39
39
|
|
|
40
40
|
[](https://pypi.org/project/fuzzgpu/)
|
|
42
42
|
[](https://opensource.org/licenses/MIT)
|
|
43
43
|
[](https://www.rust-lang.org)
|
|
44
44
|
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
@@ -61,7 +61,21 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
61
61
|
|
|
62
62
|
---
|
|
63
63
|
|
|
64
|
-
## What's New in v0.4.
|
|
64
|
+
## What's New in v0.4.1
|
|
65
|
+
|
|
66
|
+
### Production hardening & Performance
|
|
67
|
+
- **Fail-fast contiguous buffer validation** — `*_into` zero-allocation APIs now validate numpy C-contiguity before any GPU/CPU dispatch, preventing wasted compute on strided arrays.
|
|
68
|
+
- **RapidFuzz weighted Levenshtein parity** — `similarity`, `normalized_distance`, and `normalized_similarity` now support `weights=(1, 1, 1)` with exact weighted maximum distance calculation.
|
|
69
|
+
- **Wavefront WGSL register optimization** — replaced ~1.5 KB private array stack copies with direct workgroup indexing in Gotoh affine gap DP.
|
|
70
|
+
- **Zero-heap Myers SIMD fallback** — eliminated heap allocations on non-ASCII input paths with `std::str::from_utf8` / `Cow`.
|
|
71
|
+
- **PEP 561 type safety** — shipped `py.typed` and comprehensive `.pyi` type stubs for all 54 public APIs and submodules.
|
|
72
|
+
- **Community governance & Health files** — added CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, and GitHub issue/PR templates.
|
|
73
|
+
- **Cross-platform release CI** — made CPU wheel publishing portable across Linux, Windows, and macOS runners.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
<details>
|
|
78
|
+
<summary><b>Previous (v0.4.0)</b></summary>
|
|
65
79
|
|
|
66
80
|
### Production hardening
|
|
67
81
|
- **WRatio score_cutoff parity** — WRatio now threads a rescaled running cutoff through its token/partial-token steps exactly as rapidfuzz does; high cutoffs no longer leak scaled token ratios (verified against rapidfuzz 3.14.5).
|
|
@@ -72,10 +86,7 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
72
86
|
- **Flaky stress asserts gated** — wall-clock budgets in `test_stress.py` are disabled via `FUZZGPU_SKIP_PERF_ASSERTS=1` (correctness checks always run).
|
|
73
87
|
- **Accurate GPU timeout message** — readback timeouts now report the actual configured timeout.
|
|
74
88
|
|
|
75
|
-
|
|
76
|
-
All fixes from v0.3.0 are included.
|
|
77
|
-
|
|
78
|
-
---
|
|
89
|
+
</details>
|
|
79
90
|
|
|
80
91
|
<details>
|
|
81
92
|
<summary><b>Previous (v0.3.0)</b></summary>
|
|
@@ -245,10 +256,16 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
|
|
|
245
256
|
pip install fuzzgpu
|
|
246
257
|
```
|
|
247
258
|
|
|
259
|
+
For a smaller, dependency-light install with no GPU/WebGPU support (CPU + Rayon only):
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
pip install fuzzgpu-cpu
|
|
263
|
+
```
|
|
264
|
+
|
|
248
265
|
```toml
|
|
249
266
|
# Rust
|
|
250
267
|
[dependencies]
|
|
251
|
-
fuzzgpu-core = "0.4.
|
|
268
|
+
fuzzgpu-core = "0.4.1"
|
|
252
269
|
```
|
|
253
270
|
|
|
254
271
|
---
|
|
@@ -268,7 +285,7 @@ candidates = ["hallo", "hullo", "jello", "yellow", "hello world"] * 10_000
|
|
|
268
285
|
distances = fuzzgpu.levenshtein_batch("hello", candidates)
|
|
269
286
|
jw_scores = fuzzgpu.jaro_winkler_batch("hello", candidates, p=0.1)
|
|
270
287
|
nw_scores = fuzzgpu.needleman_wunsch_affine_batch(
|
|
271
|
-
"AGTACGCA", candidates,
|
|
288
|
+
"AGTACGCA", candidates, match_score=2, mismatch_score=-1, gap_open=-3, gap_extend=-1
|
|
272
289
|
)
|
|
273
290
|
|
|
274
291
|
# ── Cross-product distance matrix ─────────────────────────────────────────────
|
|
@@ -344,12 +361,12 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
|
|
|
344
361
|
|
|
345
362
|
```toml
|
|
346
363
|
[dependencies]
|
|
347
|
-
fuzzgpu-core = "0.4.
|
|
348
|
-
# fuzzgpu-core = { version = "0.4.
|
|
364
|
+
fuzzgpu-core = "0.4.1" # GPU + CPU fallback
|
|
365
|
+
# fuzzgpu-core = { version = "0.4.1", default-features = false } # CPU-only
|
|
349
366
|
```
|
|
350
367
|
|
|
351
368
|
```rust
|
|
352
|
-
use fuzzgpu_core::
|
|
369
|
+
use fuzzgpu_core::GpuLevenshteinKernel;
|
|
353
370
|
|
|
354
371
|
fn main() -> fuzzgpu_core::Result<()> {
|
|
355
372
|
let kernel = GpuLevenshteinKernel::get()?;
|
|
@@ -490,7 +507,7 @@ cargo test --workspace
|
|
|
490
507
|
| `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
|
|
491
508
|
| `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
|
|
492
509
|
| `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
|
|
493
|
-
| `
|
|
510
|
+
| `FUZZGPU_SERIALIZE_DISPATCH` | Opt-in GPU dispatch serialization (safety valve for rare driver heap corruption on Intel D3D12; dispatch is fully concurrent by default). Legacy alias: `FUZZGPU_SKIP_DISPATCH_LOCK` |
|
|
494
511
|
| `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
|
|
495
512
|
| `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
|
|
496
513
|
| `PROPTEST_CASES` | Override proptest case count |
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
10
10
|
|
|
11
11
|
[](https://pypi.org/project/fuzzgpu/)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
14
|
[](https://www.rust-lang.org)
|
|
15
15
|
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
@@ -32,7 +32,21 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
-
## What's New in v0.4.
|
|
35
|
+
## What's New in v0.4.1
|
|
36
|
+
|
|
37
|
+
### Production hardening & Performance
|
|
38
|
+
- **Fail-fast contiguous buffer validation** — `*_into` zero-allocation APIs now validate numpy C-contiguity before any GPU/CPU dispatch, preventing wasted compute on strided arrays.
|
|
39
|
+
- **RapidFuzz weighted Levenshtein parity** — `similarity`, `normalized_distance`, and `normalized_similarity` now support `weights=(1, 1, 1)` with exact weighted maximum distance calculation.
|
|
40
|
+
- **Wavefront WGSL register optimization** — replaced ~1.5 KB private array stack copies with direct workgroup indexing in Gotoh affine gap DP.
|
|
41
|
+
- **Zero-heap Myers SIMD fallback** — eliminated heap allocations on non-ASCII input paths with `std::str::from_utf8` / `Cow`.
|
|
42
|
+
- **PEP 561 type safety** — shipped `py.typed` and comprehensive `.pyi` type stubs for all 54 public APIs and submodules.
|
|
43
|
+
- **Community governance & Health files** — added CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, and GitHub issue/PR templates.
|
|
44
|
+
- **Cross-platform release CI** — made CPU wheel publishing portable across Linux, Windows, and macOS runners.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
<details>
|
|
49
|
+
<summary><b>Previous (v0.4.0)</b></summary>
|
|
36
50
|
|
|
37
51
|
### Production hardening
|
|
38
52
|
- **WRatio score_cutoff parity** — WRatio now threads a rescaled running cutoff through its token/partial-token steps exactly as rapidfuzz does; high cutoffs no longer leak scaled token ratios (verified against rapidfuzz 3.14.5).
|
|
@@ -43,10 +57,7 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
43
57
|
- **Flaky stress asserts gated** — wall-clock budgets in `test_stress.py` are disabled via `FUZZGPU_SKIP_PERF_ASSERTS=1` (correctness checks always run).
|
|
44
58
|
- **Accurate GPU timeout message** — readback timeouts now report the actual configured timeout.
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
All fixes from v0.3.0 are included.
|
|
48
|
-
|
|
49
|
-
---
|
|
60
|
+
</details>
|
|
50
61
|
|
|
51
62
|
<details>
|
|
52
63
|
<summary><b>Previous (v0.3.0)</b></summary>
|
|
@@ -216,10 +227,16 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
|
|
|
216
227
|
pip install fuzzgpu
|
|
217
228
|
```
|
|
218
229
|
|
|
230
|
+
For a smaller, dependency-light install with no GPU/WebGPU support (CPU + Rayon only):
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
pip install fuzzgpu-cpu
|
|
234
|
+
```
|
|
235
|
+
|
|
219
236
|
```toml
|
|
220
237
|
# Rust
|
|
221
238
|
[dependencies]
|
|
222
|
-
fuzzgpu-core = "0.4.
|
|
239
|
+
fuzzgpu-core = "0.4.1"
|
|
223
240
|
```
|
|
224
241
|
|
|
225
242
|
---
|
|
@@ -239,7 +256,7 @@ candidates = ["hallo", "hullo", "jello", "yellow", "hello world"] * 10_000
|
|
|
239
256
|
distances = fuzzgpu.levenshtein_batch("hello", candidates)
|
|
240
257
|
jw_scores = fuzzgpu.jaro_winkler_batch("hello", candidates, p=0.1)
|
|
241
258
|
nw_scores = fuzzgpu.needleman_wunsch_affine_batch(
|
|
242
|
-
"AGTACGCA", candidates,
|
|
259
|
+
"AGTACGCA", candidates, match_score=2, mismatch_score=-1, gap_open=-3, gap_extend=-1
|
|
243
260
|
)
|
|
244
261
|
|
|
245
262
|
# ── Cross-product distance matrix ─────────────────────────────────────────────
|
|
@@ -315,12 +332,12 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
|
|
|
315
332
|
|
|
316
333
|
```toml
|
|
317
334
|
[dependencies]
|
|
318
|
-
fuzzgpu-core = "0.4.
|
|
319
|
-
# fuzzgpu-core = { version = "0.4.
|
|
335
|
+
fuzzgpu-core = "0.4.1" # GPU + CPU fallback
|
|
336
|
+
# fuzzgpu-core = { version = "0.4.1", default-features = false } # CPU-only
|
|
320
337
|
```
|
|
321
338
|
|
|
322
339
|
```rust
|
|
323
|
-
use fuzzgpu_core::
|
|
340
|
+
use fuzzgpu_core::GpuLevenshteinKernel;
|
|
324
341
|
|
|
325
342
|
fn main() -> fuzzgpu_core::Result<()> {
|
|
326
343
|
let kernel = GpuLevenshteinKernel::get()?;
|
|
@@ -461,7 +478,7 @@ cargo test --workspace
|
|
|
461
478
|
| `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
|
|
462
479
|
| `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
|
|
463
480
|
| `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
|
|
464
|
-
| `
|
|
481
|
+
| `FUZZGPU_SERIALIZE_DISPATCH` | Opt-in GPU dispatch serialization (safety valve for rare driver heap corruption on Intel D3D12; dispatch is fully concurrent by default). Legacy alias: `FUZZGPU_SKIP_DISPATCH_LOCK` |
|
|
465
482
|
| `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
|
|
466
483
|
| `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
|
|
467
484
|
| `PROPTEST_CASES` | Override proptest case count |
|
|
@@ -25,21 +25,24 @@ pub fn require_gpu() -> bool {
|
|
|
25
25
|
.unwrap_or(false)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
/// Opt-in dispatch serialization (safety valve). `
|
|
29
|
-
/// re-enables the GPU-dispatch
|
|
30
|
-
/// workaround for the rare gfx-rs/wgpu#10085
|
|
31
|
-
/// Intel D3D12 under >=3 concurrent dispatchers on a
|
|
32
|
-
/// is fully concurrent by default; set this env var on affected
|
|
33
|
-
/// to serialize both the production dispatch path and the test suite.
|
|
28
|
+
/// Opt-in dispatch serialization (safety valve). `FUZZGPU_SERIALIZE_DISPATCH=1`
|
|
29
|
+
/// (or legacy alias `FUZZGPU_SKIP_DISPATCH_LOCK=1`) re-enables the GPU-dispatch
|
|
30
|
+
/// serialization that used to be the default workaround for the rare gfx-rs/wgpu#10085
|
|
31
|
+
/// crash class (heap corruption on Intel D3D12 under >=3 concurrent dispatchers on a
|
|
32
|
+
/// shared device). Dispatch is fully concurrent by default; set this env var on affected
|
|
33
|
+
/// Intel hardware to serialize both the production dispatch path and the test suite.
|
|
34
34
|
pub(crate) fn dispatch_serialize() -> bool {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
let check = |var: &str| {
|
|
36
|
+
std::env::var(var)
|
|
37
|
+
.map(|v| v == "1" || v.eq_ignore_ascii_case("true") || v.eq_ignore_ascii_case("yes"))
|
|
38
|
+
.unwrap_or(false)
|
|
39
|
+
};
|
|
40
|
+
check("FUZZGPU_SERIALIZE_DISPATCH") || check("FUZZGPU_SKIP_DISPATCH_LOCK")
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
/// Serialize GPU access across tests. Only active when
|
|
41
|
-
/// `FUZZGPU_SKIP_DISPATCH_LOCK=1` (opt-in safety valve);
|
|
42
|
-
/// `None` so the test suite runs with fully concurrent GPU dispatch.
|
|
44
|
+
/// `FUZZGPU_SERIALIZE_DISPATCH=1` or `FUZZGPU_SKIP_DISPATCH_LOCK=1` (opt-in safety valve);
|
|
45
|
+
/// by default returns `None` so the test suite runs with fully concurrent GPU dispatch.
|
|
43
46
|
pub fn gpu_test_lock() -> Option<std::sync::MutexGuard<'static, ()>> {
|
|
44
47
|
if !dispatch_serialize() {
|
|
45
48
|
return None;
|
|
@@ -802,13 +805,25 @@ mod tests {
|
|
|
802
805
|
disarm_shader_error_fault();
|
|
803
806
|
}
|
|
804
807
|
|
|
805
|
-
/// dispatch_serialize must read
|
|
806
|
-
/// true only when
|
|
808
|
+
/// dispatch_serialize must read FUZZGPU_SERIALIZE_DISPATCH or FUZZGPU_SKIP_DISPATCH_LOCK
|
|
809
|
+
/// and return true only when set to '1' or 'true' (case-insensitive). The
|
|
807
810
|
/// serialization is opt-in: unset (default) means fully concurrent.
|
|
808
811
|
#[test]
|
|
809
812
|
fn test_dispatch_serialize_opt_in() {
|
|
813
|
+
std::env::remove_var("FUZZGPU_SERIALIZE_DISPATCH");
|
|
810
814
|
std::env::remove_var("FUZZGPU_SKIP_DISPATCH_LOCK");
|
|
811
815
|
assert!(!dispatch_serialize());
|
|
816
|
+
|
|
817
|
+
// Primary self-documenting variable
|
|
818
|
+
std::env::set_var("FUZZGPU_SERIALIZE_DISPATCH", "1");
|
|
819
|
+
assert!(dispatch_serialize());
|
|
820
|
+
std::env::set_var("FUZZGPU_SERIALIZE_DISPATCH", "true");
|
|
821
|
+
assert!(dispatch_serialize());
|
|
822
|
+
std::env::set_var("FUZZGPU_SERIALIZE_DISPATCH", "0");
|
|
823
|
+
assert!(!dispatch_serialize());
|
|
824
|
+
std::env::remove_var("FUZZGPU_SERIALIZE_DISPATCH");
|
|
825
|
+
|
|
826
|
+
// Backward-compatible alias
|
|
812
827
|
std::env::set_var("FUZZGPU_SKIP_DISPATCH_LOCK", "1");
|
|
813
828
|
assert!(dispatch_serialize());
|
|
814
829
|
std::env::set_var("FUZZGPU_SKIP_DISPATCH_LOCK", "true");
|
|
@@ -7,8 +7,16 @@ pub mod levenshtein;
|
|
|
7
7
|
pub mod needleman;
|
|
8
8
|
pub mod simd;
|
|
9
9
|
|
|
10
|
+
#[cfg(feature = "gpu")]
|
|
11
|
+
pub use damerau::gpu_ext::GpuDamerauKernel;
|
|
10
12
|
#[cfg(feature = "gpu")]
|
|
11
13
|
pub use gpu::{GpuEngine, GpuInfo, Result};
|
|
14
|
+
#[cfg(feature = "gpu")]
|
|
15
|
+
pub use jaro::gpu_ext::GpuJaroKernel;
|
|
16
|
+
#[cfg(feature = "gpu")]
|
|
17
|
+
pub use levenshtein::gpu_ext::GpuLevenshteinKernel;
|
|
18
|
+
#[cfg(feature = "gpu")]
|
|
19
|
+
pub use needleman::gpu_ext::GpuNeedlemanAffineKernel;
|
|
12
20
|
|
|
13
21
|
#[cfg(not(feature = "gpu"))]
|
|
14
22
|
pub type Result<T> = std::result::Result<T, String>;
|
|
@@ -104,8 +104,8 @@ fn main(
|
|
|
104
104
|
let j = j_start + t;
|
|
105
105
|
let i = k - j;
|
|
106
106
|
|
|
107
|
-
let
|
|
108
|
-
let
|
|
107
|
+
let prev_idx = (k - 1u) % 3u;
|
|
108
|
+
let prev2_idx = (k - 2u) % 3u;
|
|
109
109
|
|
|
110
110
|
var cell: State;
|
|
111
111
|
if (i == 0u) {
|
|
@@ -122,18 +122,18 @@ fn main(
|
|
|
122
122
|
let sub = select(params.mismatch_score, params.match_score, a_char == b_char);
|
|
123
123
|
|
|
124
124
|
// M(i,j) = max(M,Ix,Iy)(i-1,j-1) + sub -- diagonal k-2.
|
|
125
|
-
let best_diag = max(
|
|
125
|
+
let best_diag = max(diags[prev2_idx][j - 1u].m, max(diags[prev2_idx][j - 1u].ix, diags[prev2_idx][j - 1u].iy));
|
|
126
126
|
let cell_m = best_diag + sub;
|
|
127
127
|
|
|
128
128
|
// Ix(i,j) from (i,j-1) -- diagonal k-1, column j-1.
|
|
129
|
-
let cell_ix = max(
|
|
130
|
-
max(
|
|
131
|
-
|
|
129
|
+
let cell_ix = max(diags[prev_idx][j - 1u].ix + params.gap_extend,
|
|
130
|
+
max(diags[prev_idx][j - 1u].m + params.gap_open + params.gap_extend,
|
|
131
|
+
diags[prev_idx][j - 1u].iy + params.gap_open + params.gap_extend));
|
|
132
132
|
|
|
133
133
|
// Iy(i,j) from (i-1,j) -- diagonal k-1, column j.
|
|
134
|
-
let cell_iy = max(
|
|
135
|
-
max(
|
|
136
|
-
|
|
134
|
+
let cell_iy = max(diags[prev_idx][j].iy + params.gap_extend,
|
|
135
|
+
max(diags[prev_idx][j].m + params.gap_open + params.gap_extend,
|
|
136
|
+
diags[prev_idx][j].ix + params.gap_open + params.gap_extend));
|
|
137
137
|
|
|
138
138
|
cell = State(cell_m, cell_ix, cell_iy);
|
|
139
139
|
}
|
|
@@ -19,9 +19,15 @@ pub fn levenshtein_myers(a: &[u8], b: &[u8]) -> u32 {
|
|
|
19
19
|
// back to the Unicode path. Assert it here so direct Rust callers can't
|
|
20
20
|
// silently get byte-semantics results.
|
|
21
21
|
if !a.is_ascii() || !b.is_ascii() {
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let a_str = match std::str::from_utf8(a) {
|
|
23
|
+
Ok(s) => std::borrow::Cow::Borrowed(s),
|
|
24
|
+
Err(_) => String::from_utf8_lossy(a),
|
|
25
|
+
};
|
|
26
|
+
let b_str = match std::str::from_utf8(b) {
|
|
27
|
+
Ok(s) => std::borrow::Cow::Borrowed(s),
|
|
28
|
+
Err(_) => String::from_utf8_lossy(b),
|
|
29
|
+
};
|
|
30
|
+
return crate::levenshtein::levenshtein_distance_raw(&a_str, &b_str);
|
|
25
31
|
}
|
|
26
32
|
let (m, n) = (a.len(), b.len());
|
|
27
33
|
if m == 0 {
|
|
@@ -43,6 +43,7 @@ fn any_string(max_len: usize) -> impl Strategy<Value = String> {
|
|
|
43
43
|
|
|
44
44
|
/// ASCII string, length `1..=max_len` (non-empty: the row-wise Myers cdist
|
|
45
45
|
/// kernel requires a non-empty pattern per row).
|
|
46
|
+
#[allow(dead_code)]
|
|
46
47
|
fn ascii_string_nz(max_len: usize) -> impl Strategy<Value = String> {
|
|
47
48
|
(1usize..=max_len).prop_flat_map(move |len| {
|
|
48
49
|
prop::collection::vec(prop::char::range('a', 'z'), len..=len)
|
|
@@ -50,12 +51,14 @@ fn ascii_string_nz(max_len: usize) -> impl Strategy<Value = String> {
|
|
|
50
51
|
})
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
#[allow(dead_code)]
|
|
53
55
|
fn any_pair(max_len: usize) -> impl Strategy<Value = (String, String)> {
|
|
54
56
|
(any_string(max_len), any_string(max_len))
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/// A pair of ASCII strings (the GPU Damerau kernel's gate is ASCII ≤ 32
|
|
58
60
|
/// chars, so ASCII pairs are what actually runs on the shader).
|
|
61
|
+
#[allow(dead_code)]
|
|
59
62
|
fn ascii_pair(max_len: usize) -> impl Strategy<Value = (String, String)> {
|
|
60
63
|
(ascii_string(max_len), ascii_string(max_len))
|
|
61
64
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "fuzzgpu-python"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Python bindings for FuzzGPU: GPU-accelerated fuzzy string matching engine"
|
|
6
6
|
license = "MIT"
|
|
@@ -17,7 +17,7 @@ default = ["gpu"]
|
|
|
17
17
|
gpu = ["fuzzgpu-core/gpu"]
|
|
18
18
|
|
|
19
19
|
[dependencies]
|
|
20
|
-
fuzzgpu-core = { path = "../fuzzgpu-core", version = "0.4.
|
|
20
|
+
fuzzgpu-core = { path = "../fuzzgpu-core", version = "0.4.1", default-features = false }
|
|
21
21
|
pyo3 = { workspace = true, features = ["abi3-py310"] }
|
|
22
22
|
numpy = "0.29"
|
|
23
23
|
pollster = { workspace = true }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
use pyo3::prelude::*;
|
|
2
2
|
use pyo3::types::{PyString, PyStringMethods};
|
|
3
|
+
#[cfg(feature = "gpu")]
|
|
3
4
|
use std::sync::OnceLock;
|
|
4
5
|
|
|
5
6
|
#[cfg(feature = "gpu")]
|
|
@@ -7,9 +8,12 @@ use fuzzgpu_core::gpu::GpuEngine;
|
|
|
7
8
|
|
|
8
9
|
// ── Cached Environment Configuration ─────────────────────────
|
|
9
10
|
|
|
11
|
+
#[cfg(feature = "gpu")]
|
|
10
12
|
static FORCE_GPU_CACHE: OnceLock<bool> = OnceLock::new();
|
|
13
|
+
#[cfg(feature = "gpu")]
|
|
11
14
|
static DEBUG_CACHE: OnceLock<bool> = OnceLock::new();
|
|
12
15
|
|
|
16
|
+
#[cfg(feature = "gpu")]
|
|
13
17
|
#[inline]
|
|
14
18
|
fn is_force_gpu() -> bool {
|
|
15
19
|
*FORCE_GPU_CACHE.get_or_init(|| {
|
|
@@ -21,6 +25,7 @@ fn is_force_gpu() -> bool {
|
|
|
21
25
|
})
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
#[cfg(feature = "gpu")]
|
|
24
29
|
#[inline]
|
|
25
30
|
fn is_debug_mode() -> bool {
|
|
26
31
|
*DEBUG_CACHE.get_or_init(|| {
|
|
@@ -95,7 +100,7 @@ fn checked_u32_array1<'py>(
|
|
|
95
100
|
) -> PyResult<numpy::PyReadwriteArray1<'py, u32>> {
|
|
96
101
|
use numpy::{PyArray1, PyUntypedArrayMethods};
|
|
97
102
|
let arr = out.cast::<PyArray1<u32>>()?;
|
|
98
|
-
let rw = readwrite_or_err(arr)?;
|
|
103
|
+
let mut rw = readwrite_or_err(arr)?;
|
|
99
104
|
if rw.len() != expected {
|
|
100
105
|
return Err(pyo3::exceptions::PyValueError::new_err(format!(
|
|
101
106
|
"out must hold exactly {} uint32 elements, got {}",
|
|
@@ -103,6 +108,11 @@ fn checked_u32_array1<'py>(
|
|
|
103
108
|
rw.len()
|
|
104
109
|
)));
|
|
105
110
|
}
|
|
111
|
+
if rw.as_slice_mut().is_err() {
|
|
112
|
+
return Err(pyo3::exceptions::PyBufferError::new_err(
|
|
113
|
+
"out must be C-contiguous",
|
|
114
|
+
));
|
|
115
|
+
}
|
|
106
116
|
Ok(rw)
|
|
107
117
|
}
|
|
108
118
|
|
|
@@ -114,7 +124,7 @@ fn checked_f64_array1<'py>(
|
|
|
114
124
|
) -> PyResult<numpy::PyReadwriteArray1<'py, f64>> {
|
|
115
125
|
use numpy::{PyArray1, PyUntypedArrayMethods};
|
|
116
126
|
let arr = out.cast::<PyArray1<f64>>()?;
|
|
117
|
-
let rw = readwrite_or_err(arr)?;
|
|
127
|
+
let mut rw = readwrite_or_err(arr)?;
|
|
118
128
|
if rw.len() != expected {
|
|
119
129
|
return Err(pyo3::exceptions::PyValueError::new_err(format!(
|
|
120
130
|
"out must hold exactly {} float64 elements, got {}",
|
|
@@ -122,6 +132,11 @@ fn checked_f64_array1<'py>(
|
|
|
122
132
|
rw.len()
|
|
123
133
|
)));
|
|
124
134
|
}
|
|
135
|
+
if rw.as_slice_mut().is_err() {
|
|
136
|
+
return Err(pyo3::exceptions::PyBufferError::new_err(
|
|
137
|
+
"out must be C-contiguous",
|
|
138
|
+
));
|
|
139
|
+
}
|
|
125
140
|
Ok(rw)
|
|
126
141
|
}
|
|
127
142
|
|
|
@@ -134,13 +149,18 @@ fn checked_u32_array2<'py>(
|
|
|
134
149
|
) -> PyResult<numpy::PyReadwriteArray2<'py, u32>> {
|
|
135
150
|
use numpy::{PyArray2, PyUntypedArrayMethods};
|
|
136
151
|
let arr = out.cast::<PyArray2<u32>>()?;
|
|
137
|
-
let rw = readwrite_or_err(arr)?;
|
|
152
|
+
let mut rw = readwrite_or_err(arr)?;
|
|
138
153
|
if rw.shape() != [rows, cols] {
|
|
139
154
|
return Err(pyo3::exceptions::PyValueError::new_err(format!(
|
|
140
155
|
"out must have shape ({rows}, {cols}), got {:?}",
|
|
141
156
|
rw.shape()
|
|
142
157
|
)));
|
|
143
158
|
}
|
|
159
|
+
if rw.as_slice_mut().is_err() {
|
|
160
|
+
return Err(pyo3::exceptions::PyBufferError::new_err(
|
|
161
|
+
"out must be C-contiguous",
|
|
162
|
+
));
|
|
163
|
+
}
|
|
144
164
|
Ok(rw)
|
|
145
165
|
}
|
|
146
166
|
|
|
@@ -153,13 +173,18 @@ fn checked_f64_array2<'py>(
|
|
|
153
173
|
) -> PyResult<numpy::PyReadwriteArray2<'py, f64>> {
|
|
154
174
|
use numpy::{PyArray2, PyUntypedArrayMethods};
|
|
155
175
|
let arr = out.cast::<PyArray2<f64>>()?;
|
|
156
|
-
let rw = readwrite_or_err(arr)?;
|
|
176
|
+
let mut rw = readwrite_or_err(arr)?;
|
|
157
177
|
if rw.shape() != [rows, cols] {
|
|
158
178
|
return Err(pyo3::exceptions::PyValueError::new_err(format!(
|
|
159
179
|
"out must have shape ({rows}, {cols}), got {:?}",
|
|
160
180
|
rw.shape()
|
|
161
181
|
)));
|
|
162
182
|
}
|
|
183
|
+
if rw.as_slice_mut().is_err() {
|
|
184
|
+
return Err(pyo3::exceptions::PyBufferError::new_err(
|
|
185
|
+
"out must be C-contiguous",
|
|
186
|
+
));
|
|
187
|
+
}
|
|
163
188
|
Ok(rw)
|
|
164
189
|
}
|
|
165
190
|
|
|
@@ -370,11 +395,11 @@ fn damerau_levenshtein_distance(py: Python, a: &str, b: &str) -> PyResult<u32> {
|
|
|
370
395
|
/// Shared compute for `damerau_levenshtein_batch` / `..._into`: GPU
|
|
371
396
|
/// Lowrance-Wagner kernel (auto-routed, CPU fallback).
|
|
372
397
|
fn damerau_batch_core(py: Python<'_>, query: &str, cands: &[&str]) -> PyResult<Vec<u32>> {
|
|
373
|
-
let pairs: Vec<(&str, &str)> = cands.iter().map(|c| (query, *c)).collect();
|
|
374
398
|
#[cfg(feature = "gpu")]
|
|
375
399
|
{
|
|
376
400
|
if !GpuEngine::is_cpu_only() {
|
|
377
401
|
if let Ok(kernel) = fuzzgpu_core::damerau::gpu_ext::GpuDamerauKernel::get() {
|
|
402
|
+
let pairs: Vec<(&str, &str)> = cands.iter().map(|c| (query, *c)).collect();
|
|
378
403
|
match py.detach(|| kernel.compute_batch(&pairs)) {
|
|
379
404
|
Ok(res) => return Ok(res),
|
|
380
405
|
Err(e) => {
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fuzzgpu"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.1"
|
|
8
8
|
description = "Hardware-accelerated fuzzy string matching & sequence alignment — cross-platform, no CUDA required"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -5,6 +5,10 @@ from typing import Callable, Iterable, Optional, Sequence, Tuple
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from numpy.typing import NDArray
|
|
7
7
|
|
|
8
|
+
from . import fuzz as fuzz
|
|
9
|
+
from . import process as process
|
|
10
|
+
from . import distance as distance
|
|
11
|
+
|
|
8
12
|
Processor = Optional[Callable[[str], str]]
|
|
9
13
|
Scorer = Callable[..., float]
|
|
10
14
|
|
|
@@ -34,6 +38,7 @@ def damerau_ratio(a: str, b: str) -> float: ...
|
|
|
34
38
|
def needleman_wunsch_score(a: str, b: str, match_score: int, mismatch_score: int, gap_penalty: int) -> int: ...
|
|
35
39
|
def needleman_wunsch(a: str, b: str, match_score: int, mismatch_score: int, gap_penalty: int) -> int: ...
|
|
36
40
|
def needleman_wunsch_batch(query: str, candidates: Sequence[str], match_score: int, mismatch_score: int, gap_penalty: int) -> list[int]: ...
|
|
41
|
+
def needleman_wunsch_batch_fn(query: str, candidates: Sequence[str], match_score: int, mismatch_score: int, gap_penalty: int) -> list[int]: ...
|
|
37
42
|
def needleman_wunsch_affine(a: str, b: str, match_score: int, mismatch_score: int, gap_open: int, gap_extend: int) -> int: ...
|
|
38
43
|
def needleman_wunsch_affine_batch(query: str, candidates: Sequence[str], match_score: int, mismatch_score: int, gap_open: int, gap_extend: int) -> list[int]: ...
|
|
39
44
|
def needleman_wunsch_striped(a: str, b: str, match_score: int, mismatch_score: int, gap_penalty: int) -> int: ...
|
|
@@ -45,6 +50,7 @@ def jaro_winkler_similarity(a: str, b: str, p: float = 0.1) -> float: ...
|
|
|
45
50
|
def jaro_winkler(a: str, b: str, p: float = 0.1) -> float: ...
|
|
46
51
|
def jaro_optimized(a: str, b: str) -> float: ...
|
|
47
52
|
def jaro_winkler_batch(query: str, candidates: Sequence[str], p: float = 0.1) -> list[float]: ...
|
|
53
|
+
def jaro_winkler_batch_fn(query: str, candidates: Sequence[str], p: float = 0.1) -> list[float]: ...
|
|
48
54
|
def jaro_winkler_batch_into(query: str, candidates: Sequence[str], out: NDArray[np.float64], p: float = 0.1) -> None: ...
|
|
49
55
|
def jaro_winkler_cdist(list_a: Sequence[str], list_b: Sequence[str], p: float = 0.1) -> list[list[float]]: ...
|
|
50
56
|
def jaro_winkler_cdist_into(list_a: Sequence[str], list_b: Sequence[str], out: NDArray[np.float64], p: float = 0.1) -> None: ...
|
|
@@ -66,6 +72,22 @@ def WRatio(s1: str, s2: str, *, processor: Processor = None, score_cutoff: float
|
|
|
66
72
|
def wratio(s1: str, s2: str, *, processor: Processor = None, score_cutoff: float = 0.0) -> float: ...
|
|
67
73
|
def ratio_batch(query: str, candidates: Sequence[str], *, processor: Processor = None, score_cutoff: float = 0.0, workers: Optional[int] = None) -> list[float]: ...
|
|
68
74
|
|
|
75
|
+
# ── Native extension exports ──────────────────────────────────
|
|
76
|
+
def fuzz_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
77
|
+
def fuzz_partial_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
78
|
+
def fuzz_partial_ratio_alignment(a: str, b: str, score_cutoff: float = 0.0) -> Tuple[float, int, int, int, int]: ...
|
|
79
|
+
def fuzz_token_sort_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
80
|
+
def fuzz_token_set_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
81
|
+
def fuzz_token_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
82
|
+
def fuzz_wratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
83
|
+
def fuzz_ratio_batch(query: str, candidates: Sequence[str]) -> list[float]: ...
|
|
84
|
+
def fuzz_extract(query: str, choices: Sequence[str], score_cutoff: float = 0.0, limit: int = 5) -> list[Tuple[str, float, int]]: ...
|
|
85
|
+
def fuzz_extract_one(query: str, choices: Sequence[str], score_cutoff: float = 0.0) -> Optional[Tuple[str, float, int]]: ...
|
|
86
|
+
def fuzz_partial_token_sort_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
87
|
+
def fuzz_partial_token_set_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
88
|
+
def fuzz_partial_token_ratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
89
|
+
def fuzz_qratio(a: str, b: str, score_cutoff: float = 0.0) -> float: ...
|
|
90
|
+
|
|
69
91
|
# ── Search ───────────────────────────────────────────────────
|
|
70
92
|
def extract(
|
|
71
93
|
query: str,
|
|
@@ -101,15 +123,10 @@ def extract_one(
|
|
|
101
123
|
scorer_kwargs: Optional[dict] = None,
|
|
102
124
|
) -> Optional[Tuple[str, float, int]]: ...
|
|
103
125
|
|
|
104
|
-
# ── Utilities ────────────────────────────────────────────────
|
|
105
|
-
def set_cpu_only(cpu_only: bool) -> None: ...
|
|
106
|
-
def set_gpu_threshold(threshold: Optional[int]) -> None: ...
|
|
107
|
-
def is_gpu_available() -> bool: ...
|
|
108
|
-
def warmup() -> tuple[bool, str]: ...
|
|
109
|
-
def gpu_info() -> str: ...
|
|
110
|
-
def hardware_info() -> str: ...
|
|
111
|
-
|
|
112
126
|
# ── Alignment helpers (rapidfuzz.distance API) ───────────────
|
|
127
|
+
def editops(s1: str, s2: str) -> Editops: ...
|
|
128
|
+
def opcodes(s1: str, s2: str) -> Opcodes: ...
|
|
129
|
+
|
|
113
130
|
class Editop(Tuple[str, int, int]):
|
|
114
131
|
tag: str
|
|
115
132
|
src_pos: int
|
|
@@ -166,3 +183,13 @@ class ScoreAlignment(Tuple[float, int, int, int, int]):
|
|
|
166
183
|
src_end: int
|
|
167
184
|
dest_start: int
|
|
168
185
|
dest_end: int
|
|
186
|
+
|
|
187
|
+
# ── Utilities ────────────────────────────────────────────────
|
|
188
|
+
def set_cpu_only(cpu_only: bool) -> None: ...
|
|
189
|
+
def set_gpu_threshold(threshold: Optional[int]) -> None: ...
|
|
190
|
+
def is_gpu_available() -> bool: ...
|
|
191
|
+
def warmup() -> tuple[bool, str]: ...
|
|
192
|
+
def gpu_info() -> str: ...
|
|
193
|
+
def hardware_info() -> str: ...
|
|
194
|
+
|
|
195
|
+
__all__: list[str]
|
|
@@ -27,30 +27,42 @@ def distance(s1, s2, *, weights=(1, 1, 1), processor=None, score_cutoff=None, sc
|
|
|
27
27
|
return cutoff_distance(value, score_cutoff)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def _max_distance(len1, len2, weights):
|
|
31
|
+
if weights == (1, 1, 1):
|
|
32
|
+
return max(len1, len2)
|
|
33
|
+
ins, dele, sub = weights
|
|
34
|
+
s = min(sub, ins + dele)
|
|
35
|
+
if len1 >= len2:
|
|
36
|
+
return len2 * s + (len1 - len2) * dele
|
|
37
|
+
else:
|
|
38
|
+
return len1 * s + (len2 - len1) * ins
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def similarity(s1, s2, *, weights=(1, 1, 1), processor=None, score_cutoff=None, score_hint=None):
|
|
31
42
|
del score_hint
|
|
32
43
|
if processor:
|
|
33
44
|
s1, s2 = processor(s1), processor(s2)
|
|
34
45
|
# Compute maximum AFTER processing so len() reflects the processed strings.
|
|
35
|
-
maximum =
|
|
36
|
-
value = maximum - distance(s1, s2)
|
|
46
|
+
maximum = _max_distance(len(s1), len(s2), weights)
|
|
47
|
+
value = maximum - distance(s1, s2, weights=weights)
|
|
37
48
|
return value if score_cutoff is None or value >= score_cutoff else 0
|
|
38
49
|
|
|
39
50
|
|
|
40
|
-
def normalized_distance(s1, s2, *, processor=None, score_cutoff=None, score_hint=None):
|
|
51
|
+
def normalized_distance(s1, s2, *, weights=(1, 1, 1), processor=None, score_cutoff=None, score_hint=None):
|
|
41
52
|
del score_hint
|
|
42
53
|
if processor:
|
|
43
54
|
s1, s2 = processor(s1), processor(s2)
|
|
44
|
-
maximum =
|
|
45
|
-
value = _normalized(distance(s1, s2), maximum)
|
|
55
|
+
maximum = _max_distance(len(s1), len(s2), weights)
|
|
56
|
+
value = _normalized(distance(s1, s2, weights=weights), maximum)
|
|
46
57
|
return value if score_cutoff is None or value <= score_cutoff else 1.0
|
|
47
58
|
|
|
48
59
|
|
|
49
|
-
def normalized_similarity(s1, s2, *, processor=None, score_cutoff=None, score_hint=None):
|
|
60
|
+
def normalized_similarity(s1, s2, *, weights=(1, 1, 1), processor=None, score_cutoff=None, score_hint=None):
|
|
50
61
|
del score_hint
|
|
51
62
|
if processor:
|
|
52
63
|
s1, s2 = processor(s1), processor(s2)
|
|
53
|
-
|
|
64
|
+
maximum = _max_distance(len(s1), len(s2), weights)
|
|
65
|
+
value = 1.0 - _normalized(distance(s1, s2, weights=weights), maximum)
|
|
54
66
|
return value if score_cutoff is None or value >= score_cutoff else 0.0
|
|
55
67
|
|
|
56
68
|
|
|
@@ -40,6 +40,20 @@ def extractOne(
|
|
|
40
40
|
extract_one = extractOne
|
|
41
41
|
damerau_ratio: Callable[[str, str], float]
|
|
42
42
|
|
|
43
|
+
def cdist(
|
|
44
|
+
queries: Iterable[str],
|
|
45
|
+
choices: Iterable[str],
|
|
46
|
+
*,
|
|
47
|
+
scorer: Optional[Callable] = ...,
|
|
48
|
+
processor: Optional[Processor] = ...,
|
|
49
|
+
score_cutoff: Optional[float] = ...,
|
|
50
|
+
score_hint: Optional[float] = ...,
|
|
51
|
+
score_multiplier: float = ...,
|
|
52
|
+
dtype: Optional[object] = ...,
|
|
53
|
+
workers: Optional[int] = ...,
|
|
54
|
+
scorer_kwargs: Optional[dict] = ...,
|
|
55
|
+
) -> object: ...
|
|
56
|
+
|
|
43
57
|
class ScoreAlignment(Tuple[float, int, int, int, int]):
|
|
44
58
|
score: float
|
|
45
59
|
src_start: int
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561.
|
|
@@ -144,6 +144,14 @@ def test_cdist_into_non_contiguous_raises():
|
|
|
144
144
|
fuzzgpu.levenshtein_cdist_into(a, b, out)
|
|
145
145
|
|
|
146
146
|
|
|
147
|
+
def test_batch_into_non_contiguous_raises():
|
|
148
|
+
query = "hello"
|
|
149
|
+
cands = ["world", "help"]
|
|
150
|
+
out = np.zeros(4, dtype=np.uint32)[::2] # strided 1D view
|
|
151
|
+
with pytest.raises(BufferError, match=r"C-contiguous"):
|
|
152
|
+
fuzzgpu.levenshtein_batch_into(query, cands, out)
|
|
153
|
+
|
|
154
|
+
|
|
147
155
|
def test_jaro_batch_into_invalid_p_raises():
|
|
148
156
|
out = np.zeros(1, dtype=np.float64)
|
|
149
157
|
with pytest.raises(ValueError):
|
|
@@ -98,6 +98,19 @@ def test_distance_modules_match_rapidfuzz(mod, fn):
|
|
|
98
98
|
assert r == g, f"{mod}.{fn}({a!r}, {b!r}): rapidfuzz={r} fuzzgpu={g}"
|
|
99
99
|
|
|
100
100
|
|
|
101
|
+
@pytest.mark.parametrize("fn", ["distance", "similarity", "normalized_distance", "normalized_similarity"])
|
|
102
|
+
@pytest.mark.parametrize("weights", [(1, 1, 1), (1, 1, 2), (2, 1, 1), (1, 2, 1), (2, 3, 4)])
|
|
103
|
+
def test_levenshtein_weighted_matches_rapidfuzz(fn, weights):
|
|
104
|
+
rmod, gmod = rd.Levenshtein, fd.Levenshtein
|
|
105
|
+
for a, b in _PAIRS[:20]:
|
|
106
|
+
r = getattr(rmod, fn)(a, b, weights=weights)
|
|
107
|
+
g = getattr(gmod, fn)(a, b, weights=weights)
|
|
108
|
+
if isinstance(r, float):
|
|
109
|
+
_assert_close(r, g, f"Levenshtein.{fn}({a!r}, {b!r}, weights={weights})")
|
|
110
|
+
else:
|
|
111
|
+
assert r == g, f"Levenshtein.{fn}({a!r}, {b!r}, weights={weights}): rapidfuzz={r} fuzzgpu={g}"
|
|
112
|
+
|
|
113
|
+
|
|
101
114
|
@pytest.mark.parametrize("mod", ["Levenshtein", "Indel"])
|
|
102
115
|
def test_editops_length_matches_rapidfuzz(mod):
|
|
103
116
|
rmod, gmod = getattr(rd, mod), getattr(fd, mod)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fuzzgpu-0.4.0 → fuzzgpu-0.4.1}/crates/fuzzgpu-core/src/shaders/levenshtein_cdist_myers.wgsl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|