fuzzgpu 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/Cargo.lock +45 -74
  2. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/Cargo.toml +1 -1
  3. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/PKG-INFO +33 -14
  4. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/README.md +32 -13
  5. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/Cargo.toml +1 -1
  6. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/fuzz.rs +29 -13
  7. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/gpu.rs +51 -49
  8. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/jaro.rs +2 -1
  9. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/levenshtein.rs +5 -7
  10. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/needleman.rs +8 -4
  11. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/simd.rs +1 -1
  12. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/tests/differential.rs +19 -9
  13. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-python/Cargo.toml +3 -3
  14. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-python/src/lib.rs +43 -43
  15. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-wasm/Cargo.toml +1 -1
  16. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/pyproject.toml +5 -1
  17. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/DamerauLevenshtein.py +5 -6
  18. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/process.py +27 -6
  19. fuzzgpu-0.4.0/tests/test_rapidfuzz_differential.py +170 -0
  20. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_stress.py +15 -5
  21. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/LICENSE +0 -0
  22. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/assets/logo.png +0 -0
  23. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/benches/bench.rs +0 -0
  24. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/damerau.rs +0 -0
  25. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/lib.rs +0 -0
  26. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/damerau.wgsl +0 -0
  27. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/damerau_matrix.wgsl +0 -0
  28. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/jaro.wgsl +0 -0
  29. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/jaro_matrix.wgsl +0 -0
  30. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/levenshtein.wgsl +0 -0
  31. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/levenshtein_cdist_myers.wgsl +0 -0
  32. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/levenshtein_matrix.wgsl +0 -0
  33. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/levenshtein_myers.wgsl +0 -0
  34. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/levenshtein_short.wgsl +0 -0
  35. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/needleman_affine.wgsl +0 -0
  36. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/src/shaders/needleman_wavefront.wgsl +0 -0
  37. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/tests/differential.proptest-regressions +0 -0
  38. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/tests/fixtures/broken.wgsl +0 -0
  39. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-core/tests/kernel_registration.rs +0 -0
  40. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-wasm/src/lib.rs +0 -0
  41. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-wasm/tests/differential_harness.js +0 -0
  42. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/crates/fuzzgpu-wasm/tests/js_api.test.cjs +0 -0
  43. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/__init__.py +0 -0
  44. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/__init__.pyi +0 -0
  45. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Hamming.py +0 -0
  46. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Indel.py +0 -0
  47. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Jaro.py +0 -0
  48. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/JaroWinkler.py +0 -0
  49. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/LCSseq.py +0 -0
  50. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Levenshtein.py +0 -0
  51. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/OSA.py +0 -0
  52. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Postfix.py +0 -0
  53. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/Prefix.py +0 -0
  54. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/__init__.py +0 -0
  55. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/__init__.pyi +0 -0
  56. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/distance/_common.py +0 -0
  57. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/fuzz.py +0 -0
  58. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/fuzz.pyi +0 -0
  59. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/python/fuzzgpu/process.pyi +0 -0
  60. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_api_signatures.py +0 -0
  61. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_basic.py +0 -0
  62. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_concurrency.py +0 -0
  63. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_edge_cases.py +0 -0
  64. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_gpu_health.py +0 -0
  65. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_gpu_threshold_env.py +0 -0
  66. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_invariants.py +0 -0
  67. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_out_buffers.py +0 -0
  68. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/test_rapidfuzz_compat.py +0 -0
  69. {fuzzgpu-0.2.0 → fuzzgpu-0.4.0}/tests/wasm_python_differential.py +0 -0
@@ -308,9 +308,9 @@ dependencies = [
308
308
 
309
309
  [[package]]
310
310
  name = "either"
311
- version = "1.17.0"
311
+ version = "1.18.0"
312
312
  source = "registry+https://github.com/rust-lang/crates.io-index"
313
- checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
313
+ checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
314
314
 
315
315
  [[package]]
316
316
  name = "equivalent"
@@ -372,7 +372,7 @@ dependencies = [
372
372
 
373
373
  [[package]]
374
374
  name = "fuzzgpu-core"
375
- version = "0.2.0"
375
+ version = "0.4.0"
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.2.0"
389
+ version = "0.4.0"
390
390
  dependencies = [
391
391
  "fuzzgpu-core",
392
392
  "log",
@@ -518,15 +518,6 @@ dependencies = [
518
518
  "hashbrown 0.17.1",
519
519
  ]
520
520
 
521
- [[package]]
522
- name = "indoc"
523
- version = "2.0.7"
524
- source = "registry+https://github.com/rust-lang/crates.io-index"
525
- checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
526
- dependencies = [
527
- "rustversion",
528
- ]
529
-
530
521
  [[package]]
531
522
  name = "is-terminal"
532
523
  version = "0.4.17"
@@ -654,9 +645,9 @@ dependencies = [
654
645
 
655
646
  [[package]]
656
647
  name = "log"
657
- version = "0.4.33"
648
+ version = "0.4.34"
658
649
  source = "registry+https://github.com/rust-lang/crates.io-index"
659
- checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
650
+ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
660
651
 
661
652
  [[package]]
662
653
  name = "matrixmultiply"
@@ -674,20 +665,11 @@ version = "2.8.3"
674
665
  source = "registry+https://github.com/rust-lang/crates.io-index"
675
666
  checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
676
667
 
677
- [[package]]
678
- name = "memoffset"
679
- version = "0.9.1"
680
- source = "registry+https://github.com/rust-lang/crates.io-index"
681
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
682
- dependencies = [
683
- "autocfg",
684
- ]
685
-
686
668
  [[package]]
687
669
  name = "naga"
688
- version = "30.0.0"
670
+ version = "30.0.1"
689
671
  source = "registry+https://github.com/rust-lang/crates.io-index"
690
- checksum = "23bf0a141a9ab6f07dbb492db53245e464bc9db42f407772d9ae03d83a2c1033"
672
+ checksum = "a616d2fb8c89516ac2723a581f69d6c18576046bed761bd6b305e5618e6ae130"
691
673
  dependencies = [
692
674
  "arrayvec",
693
675
  "bit-set 0.10.0",
@@ -711,9 +693,9 @@ dependencies = [
711
693
 
712
694
  [[package]]
713
695
  name = "naga-types"
714
- version = "30.0.0"
696
+ version = "30.0.1"
715
697
  source = "registry+https://github.com/rust-lang/crates.io-index"
716
- checksum = "658200ddc25c6c7b860747516d132d1b284c0fafb7a380233acee9a72fb30e11"
698
+ checksum = "590afbf58a6f4f62873cd5cff4468061844bafa1cdf399cc954537c22d768d49"
717
699
  dependencies = [
718
700
  "hashbrown 0.17.1",
719
701
  "indexmap",
@@ -723,9 +705,9 @@ dependencies = [
723
705
 
724
706
  [[package]]
725
707
  name = "ndarray"
726
- version = "0.16.1"
708
+ version = "0.17.2"
727
709
  source = "registry+https://github.com/rust-lang/crates.io-index"
728
- checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
710
+ checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d"
729
711
  dependencies = [
730
712
  "matrixmultiply",
731
713
  "num-complex",
@@ -775,9 +757,9 @@ dependencies = [
775
757
 
776
758
  [[package]]
777
759
  name = "numpy"
778
- version = "0.23.0"
760
+ version = "0.29.0"
779
761
  source = "registry+https://github.com/rust-lang/crates.io-index"
780
- checksum = "b94caae805f998a07d33af06e6a3891e38556051b8045c615470a71590e13e78"
762
+ checksum = "6a5b15d63a5ff39e378daed0e1340d3a5964703ea9712eb09a0dc66fade996f4"
781
763
  dependencies = [
782
764
  "libc",
783
765
  "ndarray",
@@ -785,6 +767,7 @@ dependencies = [
785
767
  "num-integer",
786
768
  "num-traits",
787
769
  "pyo3",
770
+ "pyo3-build-config",
788
771
  "rustc-hash 2.1.3",
789
772
  ]
790
773
 
@@ -888,9 +871,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
888
871
 
889
872
  [[package]]
890
873
  name = "ordered-float"
891
- version = "5.3.0"
874
+ version = "5.5.0"
892
875
  source = "registry+https://github.com/rust-lang/crates.io-index"
893
- checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e"
876
+ checksum = "8c7c9e0d9b23589f26070720bac724174bfec1083e82f7854cdd0267518343c0"
894
877
  dependencies = [
895
878
  "num-traits",
896
879
  ]
@@ -1030,37 +1013,32 @@ dependencies = [
1030
1013
 
1031
1014
  [[package]]
1032
1015
  name = "pyo3"
1033
- version = "0.23.5"
1016
+ version = "0.29.2"
1034
1017
  source = "registry+https://github.com/rust-lang/crates.io-index"
1035
- checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872"
1018
+ checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
1036
1019
  dependencies = [
1037
- "cfg-if",
1038
- "indoc",
1039
1020
  "libc",
1040
- "memoffset",
1041
1021
  "once_cell",
1042
1022
  "portable-atomic",
1043
1023
  "pyo3-build-config",
1044
1024
  "pyo3-ffi",
1045
1025
  "pyo3-macros",
1046
- "unindent",
1047
1026
  ]
1048
1027
 
1049
1028
  [[package]]
1050
1029
  name = "pyo3-build-config"
1051
- version = "0.23.5"
1030
+ version = "0.29.2"
1052
1031
  source = "registry+https://github.com/rust-lang/crates.io-index"
1053
- checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb"
1032
+ checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
1054
1033
  dependencies = [
1055
- "once_cell",
1056
1034
  "target-lexicon",
1057
1035
  ]
1058
1036
 
1059
1037
  [[package]]
1060
1038
  name = "pyo3-ffi"
1061
- version = "0.23.5"
1039
+ version = "0.29.2"
1062
1040
  source = "registry+https://github.com/rust-lang/crates.io-index"
1063
- checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d"
1041
+ checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
1064
1042
  dependencies = [
1065
1043
  "libc",
1066
1044
  "pyo3-build-config",
@@ -1068,9 +1046,9 @@ dependencies = [
1068
1046
 
1069
1047
  [[package]]
1070
1048
  name = "pyo3-macros"
1071
- version = "0.23.5"
1049
+ version = "0.29.2"
1072
1050
  source = "registry+https://github.com/rust-lang/crates.io-index"
1073
- checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da"
1051
+ checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
1074
1052
  dependencies = [
1075
1053
  "proc-macro2",
1076
1054
  "pyo3-macros-backend",
@@ -1080,13 +1058,12 @@ dependencies = [
1080
1058
 
1081
1059
  [[package]]
1082
1060
  name = "pyo3-macros-backend"
1083
- version = "0.23.5"
1061
+ version = "0.29.2"
1084
1062
  source = "registry+https://github.com/rust-lang/crates.io-index"
1085
- checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028"
1063
+ checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
1086
1064
  dependencies = [
1087
1065
  "heck",
1088
1066
  "proc-macro2",
1089
- "pyo3-build-config",
1090
1067
  "quote",
1091
1068
  "syn 2.0.119",
1092
1069
  ]
@@ -1411,9 +1388,9 @@ dependencies = [
1411
1388
 
1412
1389
  [[package]]
1413
1390
  name = "target-lexicon"
1414
- version = "0.12.16"
1391
+ version = "0.13.5"
1415
1392
  source = "registry+https://github.com/rust-lang/crates.io-index"
1416
- checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
1393
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
1417
1394
 
1418
1395
  [[package]]
1419
1396
  name = "tempfile"
@@ -1485,12 +1462,6 @@ version = "0.2.2"
1485
1462
  source = "registry+https://github.com/rust-lang/crates.io-index"
1486
1463
  checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
1487
1464
 
1488
- [[package]]
1489
- name = "unindent"
1490
- version = "0.2.4"
1491
- source = "registry+https://github.com/rust-lang/crates.io-index"
1492
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
1493
-
1494
1465
  [[package]]
1495
1466
  name = "version_check"
1496
1467
  version = "0.9.5"
@@ -1604,9 +1575,9 @@ dependencies = [
1604
1575
 
1605
1576
  [[package]]
1606
1577
  name = "wgpu"
1607
- version = "30.0.0"
1578
+ version = "30.0.1"
1608
1579
  source = "registry+https://github.com/rust-lang/crates.io-index"
1609
- checksum = "6d8f4bd44d92da5270f03409dba9f952dab24f128e05d6a554926101d1bf9114"
1580
+ checksum = "527ccdf43dd5b2e8676eed9984ce00e2bbb0a1b85b70c1969dcb6cd2eb55ab9e"
1610
1581
  dependencies = [
1611
1582
  "arrayvec",
1612
1583
  "bitflags",
@@ -1634,9 +1605,9 @@ dependencies = [
1634
1605
 
1635
1606
  [[package]]
1636
1607
  name = "wgpu-core"
1637
- version = "30.0.0"
1608
+ version = "30.0.1"
1638
1609
  source = "registry+https://github.com/rust-lang/crates.io-index"
1639
- checksum = "08763620e76fc980bca7bf84de82568614487a53172dd968d89187282eb87fa2"
1610
+ checksum = "14c018fce9b6270aa203c2fdd56f3cce996713534bd757e4ea58c8560b121f14"
1640
1611
  dependencies = [
1641
1612
  "arrayvec",
1642
1613
  "bit-set 0.10.0",
@@ -1668,36 +1639,36 @@ dependencies = [
1668
1639
 
1669
1640
  [[package]]
1670
1641
  name = "wgpu-core-deps-apple"
1671
- version = "30.0.0"
1642
+ version = "30.0.1"
1672
1643
  source = "registry+https://github.com/rust-lang/crates.io-index"
1673
- checksum = "3283b6da70d7fc892de95840215aa36381b5d0cbc479e88ee2b173c7b992b225"
1644
+ checksum = "061f3d319a40d39d00b1ecc2c33b89fe21d4e6fe01859df3500a3a8ecccd6b68"
1674
1645
  dependencies = [
1675
1646
  "wgpu-hal",
1676
1647
  ]
1677
1648
 
1678
1649
  [[package]]
1679
1650
  name = "wgpu-core-deps-emscripten"
1680
- version = "30.0.0"
1651
+ version = "30.0.1"
1681
1652
  source = "registry+https://github.com/rust-lang/crates.io-index"
1682
- checksum = "85dcf2b2e5c2afb9eda64c570a87a4e570304bf39e52eddbaaf222d655b656ad"
1653
+ checksum = "d98b86cf4abf524a902dd35f18ca6a3f08fc2ae9847c8f10b48e30491b1f0b86"
1683
1654
  dependencies = [
1684
1655
  "wgpu-hal",
1685
1656
  ]
1686
1657
 
1687
1658
  [[package]]
1688
1659
  name = "wgpu-core-deps-windows-linux-android"
1689
- version = "30.0.0"
1660
+ version = "30.0.1"
1690
1661
  source = "registry+https://github.com/rust-lang/crates.io-index"
1691
- checksum = "f76bc9c1c186ff3d9054e0d224c93c8c1c79d6653907c5249a5c1ea1a2cb1e43"
1662
+ checksum = "7586165fd5f6d881cb9ce4bb71f40d6caab2c0f1837e3fc1d9788a197fb6004f"
1692
1663
  dependencies = [
1693
1664
  "wgpu-hal",
1694
1665
  ]
1695
1666
 
1696
1667
  [[package]]
1697
1668
  name = "wgpu-hal"
1698
- version = "30.0.0"
1669
+ version = "30.0.1"
1699
1670
  source = "registry+https://github.com/rust-lang/crates.io-index"
1700
- checksum = "cf765132d8d5f50e192e7880464890c13f4e7457aafe8e5466e8174586e9f101"
1671
+ checksum = "b6b7fb58561a792bc237628ba0792e332de418fefe145f13b5ed8201e6d52f58"
1701
1672
  dependencies = [
1702
1673
  "android_system_properties",
1703
1674
  "arrayvec",
@@ -1751,9 +1722,9 @@ dependencies = [
1751
1722
 
1752
1723
  [[package]]
1753
1724
  name = "wgpu-naga-bridge"
1754
- version = "30.0.0"
1725
+ version = "30.0.1"
1755
1726
  source = "registry+https://github.com/rust-lang/crates.io-index"
1756
- checksum = "c9eaac644e5008925c78567d272b9d66ef83da55a53cc17fc7daade7bb6e66e5"
1727
+ checksum = "d2f62e73117bb7a62bfd9c5a5841438a823f6566c6442a808ee269d2d055c081"
1757
1728
  dependencies = [
1758
1729
  "naga",
1759
1730
  "wgpu-types",
@@ -1761,9 +1732,9 @@ dependencies = [
1761
1732
 
1762
1733
  [[package]]
1763
1734
  name = "wgpu-types"
1764
- version = "30.0.0"
1735
+ version = "30.0.1"
1765
1736
  source = "registry+https://github.com/rust-lang/crates.io-index"
1766
- checksum = "1a9c93c2b35edde326df60ffdee4c0f5864eac3011d6768b70d43f028ad93565"
1737
+ checksum = "99dad6f1fbdbbdb4c278a6508b059d44688f5cebddf78d005a46a31340269286"
1767
1738
  dependencies = [
1768
1739
  "bitflags",
1769
1740
  "bytemuck",
@@ -6,4 +6,4 @@ resolver = "2"
6
6
  wgpu = "30.0"
7
7
  pollster = "0.4"
8
8
  bytemuck = { version = "1.14", features = ["derive"] }
9
- pyo3 = { version = "0.23", features = ["extension-module"] }
9
+ pyo3 = { version = "0.29", features = ["extension-module"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fuzzgpu
3
- Version: 0.2.0
3
+ Version: 0.4.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -37,7 +37,8 @@ Project-URL: Repository, https://github.com/kuntal-devrat/fuzzgpu
37
37
 
38
38
  *Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
39
39
 
40
- [![PyPI Version](https://img.shields.io/badge/pypi-v0.2.0-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
40
+ [![PyPI
41
+ Version](https://img.shields.io/badge/pypi-v0.4.0-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
41
42
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](https://opensource.org/licenses/MIT)
42
43
  [![Rust](https://img.shields.io/badge/rust-1.87+-orange.svg?style=flat-square)](https://www.rust-lang.org)
43
44
  [![Cross Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux%20%7C%20WASM-lightgrey.svg?style=flat-square)](https://github.com/kuntal-devrat/fuzzgpu)
@@ -60,7 +61,24 @@ No NVIDIA CUDA drivers or complex toolkits required.
60
61
 
61
62
  ---
62
63
 
63
- ## What's New in v0.2.0
64
+ ## What's New in v0.4.0
65
+
66
+ ### Production hardening
67
+ - **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).
68
+ - **`process.cdist` correctness** — the generic path now zeroes below-cutoff scores for scorers without `score_cutoff` support, and the fast path honors `score_multiplier` (cutoff is applied to the raw score, then scaled) — matching rapidfuzz.
69
+ - **Randomized rapidfuzz differential suite** — new `tests/test_rapidfuzz_differential.py` pins every scorer, cutoff, alignment, distance module, editops, and `process` helper to rapidfuzz 3.14.5 across a seeded 200-pair corpus (runs on every push).
70
+ - **Gotoh sentinel** — `NEG_INF` hardened to `i64::MIN/4` so pathological gap penalties can no longer beat it.
71
+ - **CPU-only wheel** — `maturin build --no-default-features` now ships a GPU-free variant, built and smoke-tested in CI.
72
+ - **Flaky stress asserts gated** — wall-clock budgets in `test_stress.py` are disabled via `FUZZGPU_SKIP_PERF_ASSERTS=1` (correctness checks always run).
73
+ - **Accurate GPU timeout message** — readback timeouts now report the actual configured timeout.
74
+
75
+ ### Includes all v0.3.0 fixes
76
+ All fixes from v0.3.0 are included.
77
+
78
+ ---
79
+
80
+ <details>
81
+ <summary><b>Previous (v0.3.0)</b></summary>
64
82
 
65
83
  ### Production hardening
66
84
  - **Kernel `get()` panics eliminated** — all four GPU kernels (`GpuLevenshteinKernel`,
@@ -164,15 +182,14 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
164
182
  ## Benchmark Results
165
183
 
166
184
  *Hardware: Intel(R) Iris(R) Xe Graphics — integrated GPU (Vulkan) + Intel Core i7 (Rayon, all cores)*
167
- *Versions: fuzzgpu 0.2.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
185
+ *Versions: fuzzgpu 0.4.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
168
186
  *Median of 7 runs after warmup. Reproduce: `python benchmarks/bench_compare.py`*
169
187
 
170
188
  > **GPU class note:** These numbers are from an **integrated GPU** (iGPU), which shares memory
171
189
  > bandwidth with the CPU and has a ~1 ms dispatch round-trip. On a **discrete GPU** (dGPU) the
172
190
  > GPU columns improve significantly — expect 3–10× better GPU throughput and GPU routing kicking
173
191
  > in at much smaller batch sizes (threshold drops from ~500 pairs to ~64 pairs automatically).
174
- > Concurrency gains (multiple Python threads, after the wgpu fix ships) add a further 2–4×
175
- > on top for server workloads regardless of GPU class.
192
+ > Concurrent Python-thread dispatch is supported on all backends.
176
193
 
177
194
  ### Levenshtein Batch (1 query × N candidates, 10-char strings)
178
195
  | Batch Size | `fuzzgpu` (GPU) | `fuzzgpu` (CPU) | `rapidfuzz` | vs RF (GPU) | vs RF (CPU) |
@@ -190,7 +207,9 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
190
207
  | **10,000** | 1.39 ms | 1.49 ms | 9.93 ms | 7.14× | 6.67× |
191
208
  | **50,000** | 10.19 ms | 9.91 ms | 66.57 ms | 6.54× | 6.72× |
192
209
 
193
- > **Note:** rapidfuzz's `DamerauLevenshtein` uses Optimal String Alignment (OSA). fuzzgpu implements the **unrestricted** Lowrance-Wagner (1975) algorithm which allows non-adjacent transpositions. For example: `damerau("ca", "abc") == 2` (fuzzgpu) vs `3` (rapidfuzz OSA). Use `fuzzgpu.distance.OSA` for OSA-compatible semantics.
210
+ > **Note:** Both fuzzgpu and rapidfuzz's `DamerauLevenshtein` implement the **unrestricted**
211
+ > Lowrance-Wagner (1975) algorithm (non-adjacent transpositions allowed): `damerau("ca", "abc") == 2`
212
+ > in both. For the restricted variant use `fuzzgpu.distance.OSA` (`== 3`, also matching rapidfuzz).
194
213
 
195
214
  ### Jaro-Winkler Batch (p = 0.1)
196
215
  | Batch Size | `fuzzgpu` (GPU) | `fuzzgpu` (CPU) | `rapidfuzz` | vs RF (GPU) | vs RF (CPU) |
@@ -229,7 +248,7 @@ pip install fuzzgpu
229
248
  ```toml
230
249
  # Rust
231
250
  [dependencies]
232
- fuzzgpu-core = "0.2.0"
251
+ fuzzgpu-core = "0.4.0"
233
252
  ```
234
253
 
235
254
  ---
@@ -277,8 +296,8 @@ from fuzzgpu.fuzz import (
277
296
 
278
297
  ratio("fuzzy was a bear", "fuzzy was a bear") # 100.0
279
298
  partial_ratio("hello", "oh hello there") # 100.0
280
- score, src, dst, length = partial_ratio_alignment("hello", "oh hello there")
281
- # (100.0, 0, 3, 5) ← window starts at char 3 of the longer string
299
+ score, src, dst = partial_ratio_alignment("hello", "oh hello there")
300
+ # ScoreAlignment(score=100.0, src_start=0, src_end=5, dest_start=3, dest_end=8)
282
301
 
283
302
  token_sort_ratio("new york mets", "mets new york") # 100.0
284
303
  token_set_ratio("fuzzy was a bear", "fuzzy bear") # 100.0
@@ -325,8 +344,8 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
325
344
 
326
345
  ```toml
327
346
  [dependencies]
328
- fuzzgpu-core = "0.2.0" # GPU + CPU fallback
329
- # fuzzgpu-core = { version = "0.1.7", default-features = false } # CPU-only
347
+ fuzzgpu-core = "0.4.0" # GPU + CPU fallback
348
+ # fuzzgpu-core = { version = "0.4.0", default-features = false } # CPU-only
330
349
  ```
331
350
 
332
351
  ```rust
@@ -443,7 +462,7 @@ fuzzgpu/
443
462
  │ └── process.py # rapidfuzz.process-compatible helpers
444
463
  ├── fuzz/ # libFuzzer targets + stable self-harness
445
464
  ├── benchmarks/ # Comparative benchmark scripts
446
- ├── tests/ # Python pytest suite (174 tests)
465
+ ├── tests/ # Python pytest suite (278 tests incl. rapidfuzz differential)
447
466
  └── docs/GPU_TESTING.md # Fault injection & GPU test conventions
448
467
  ```
449
468
 
@@ -471,7 +490,7 @@ cargo test --workspace
471
490
  | `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
472
491
  | `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
473
492
  | `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
474
- | `FUZZGPU_SKIP_DISPATCH_LOCK` | Bypass serialization lock (repro only) |
493
+ | `FUZZGPU_SKIP_DISPATCH_LOCK` | Opt-in GPU dispatch serialization (safety valve for the rare gfx-rs/wgpu#10085 crash class on Intel D3D12; dispatch is fully concurrent by default) |
475
494
  | `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
476
495
  | `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
477
496
  | `PROPTEST_CASES` | Override proptest case count |
@@ -8,7 +8,8 @@
8
8
 
9
9
  *Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
10
10
 
11
- [![PyPI Version](https://img.shields.io/badge/pypi-v0.2.0-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
11
+ [![PyPI
12
+ Version](https://img.shields.io/badge/pypi-v0.4.0-blue.svg?style=flat-square)](https://pypi.org/project/fuzzgpu/)
12
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](https://opensource.org/licenses/MIT)
13
14
  [![Rust](https://img.shields.io/badge/rust-1.87+-orange.svg?style=flat-square)](https://www.rust-lang.org)
14
15
  [![Cross Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux%20%7C%20WASM-lightgrey.svg?style=flat-square)](https://github.com/kuntal-devrat/fuzzgpu)
@@ -31,7 +32,24 @@ No NVIDIA CUDA drivers or complex toolkits required.
31
32
 
32
33
  ---
33
34
 
34
- ## What's New in v0.2.0
35
+ ## What's New in v0.4.0
36
+
37
+ ### Production hardening
38
+ - **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).
39
+ - **`process.cdist` correctness** — the generic path now zeroes below-cutoff scores for scorers without `score_cutoff` support, and the fast path honors `score_multiplier` (cutoff is applied to the raw score, then scaled) — matching rapidfuzz.
40
+ - **Randomized rapidfuzz differential suite** — new `tests/test_rapidfuzz_differential.py` pins every scorer, cutoff, alignment, distance module, editops, and `process` helper to rapidfuzz 3.14.5 across a seeded 200-pair corpus (runs on every push).
41
+ - **Gotoh sentinel** — `NEG_INF` hardened to `i64::MIN/4` so pathological gap penalties can no longer beat it.
42
+ - **CPU-only wheel** — `maturin build --no-default-features` now ships a GPU-free variant, built and smoke-tested in CI.
43
+ - **Flaky stress asserts gated** — wall-clock budgets in `test_stress.py` are disabled via `FUZZGPU_SKIP_PERF_ASSERTS=1` (correctness checks always run).
44
+ - **Accurate GPU timeout message** — readback timeouts now report the actual configured timeout.
45
+
46
+ ### Includes all v0.3.0 fixes
47
+ All fixes from v0.3.0 are included.
48
+
49
+ ---
50
+
51
+ <details>
52
+ <summary><b>Previous (v0.3.0)</b></summary>
35
53
 
36
54
  ### Production hardening
37
55
  - **Kernel `get()` panics eliminated** — all four GPU kernels (`GpuLevenshteinKernel`,
@@ -135,15 +153,14 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
135
153
  ## Benchmark Results
136
154
 
137
155
  *Hardware: Intel(R) Iris(R) Xe Graphics — integrated GPU (Vulkan) + Intel Core i7 (Rayon, all cores)*
138
- *Versions: fuzzgpu 0.2.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
156
+ *Versions: fuzzgpu 0.4.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
139
157
  *Median of 7 runs after warmup. Reproduce: `python benchmarks/bench_compare.py`*
140
158
 
141
159
  > **GPU class note:** These numbers are from an **integrated GPU** (iGPU), which shares memory
142
160
  > bandwidth with the CPU and has a ~1 ms dispatch round-trip. On a **discrete GPU** (dGPU) the
143
161
  > GPU columns improve significantly — expect 3–10× better GPU throughput and GPU routing kicking
144
162
  > in at much smaller batch sizes (threshold drops from ~500 pairs to ~64 pairs automatically).
145
- > Concurrency gains (multiple Python threads, after the wgpu fix ships) add a further 2–4×
146
- > on top for server workloads regardless of GPU class.
163
+ > Concurrent Python-thread dispatch is supported on all backends.
147
164
 
148
165
  ### Levenshtein Batch (1 query × N candidates, 10-char strings)
149
166
  | Batch Size | `fuzzgpu` (GPU) | `fuzzgpu` (CPU) | `rapidfuzz` | vs RF (GPU) | vs RF (CPU) |
@@ -161,7 +178,9 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
161
178
  | **10,000** | 1.39 ms | 1.49 ms | 9.93 ms | 7.14× | 6.67× |
162
179
  | **50,000** | 10.19 ms | 9.91 ms | 66.57 ms | 6.54× | 6.72× |
163
180
 
164
- > **Note:** rapidfuzz's `DamerauLevenshtein` uses Optimal String Alignment (OSA). fuzzgpu implements the **unrestricted** Lowrance-Wagner (1975) algorithm which allows non-adjacent transpositions. For example: `damerau("ca", "abc") == 2` (fuzzgpu) vs `3` (rapidfuzz OSA). Use `fuzzgpu.distance.OSA` for OSA-compatible semantics.
181
+ > **Note:** Both fuzzgpu and rapidfuzz's `DamerauLevenshtein` implement the **unrestricted**
182
+ > Lowrance-Wagner (1975) algorithm (non-adjacent transpositions allowed): `damerau("ca", "abc") == 2`
183
+ > in both. For the restricted variant use `fuzzgpu.distance.OSA` (`== 3`, also matching rapidfuzz).
165
184
 
166
185
  ### Jaro-Winkler Batch (p = 0.1)
167
186
  | Batch Size | `fuzzgpu` (GPU) | `fuzzgpu` (CPU) | `rapidfuzz` | vs RF (GPU) | vs RF (CPU) |
@@ -200,7 +219,7 @@ pip install fuzzgpu
200
219
  ```toml
201
220
  # Rust
202
221
  [dependencies]
203
- fuzzgpu-core = "0.2.0"
222
+ fuzzgpu-core = "0.4.0"
204
223
  ```
205
224
 
206
225
  ---
@@ -248,8 +267,8 @@ from fuzzgpu.fuzz import (
248
267
 
249
268
  ratio("fuzzy was a bear", "fuzzy was a bear") # 100.0
250
269
  partial_ratio("hello", "oh hello there") # 100.0
251
- score, src, dst, length = partial_ratio_alignment("hello", "oh hello there")
252
- # (100.0, 0, 3, 5) ← window starts at char 3 of the longer string
270
+ score, src, dst = partial_ratio_alignment("hello", "oh hello there")
271
+ # ScoreAlignment(score=100.0, src_start=0, src_end=5, dest_start=3, dest_end=8)
253
272
 
254
273
  token_sort_ratio("new york mets", "mets new york") # 100.0
255
274
  token_set_ratio("fuzzy was a bear", "fuzzy bear") # 100.0
@@ -296,8 +315,8 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
296
315
 
297
316
  ```toml
298
317
  [dependencies]
299
- fuzzgpu-core = "0.2.0" # GPU + CPU fallback
300
- # fuzzgpu-core = { version = "0.1.7", default-features = false } # CPU-only
318
+ fuzzgpu-core = "0.4.0" # GPU + CPU fallback
319
+ # fuzzgpu-core = { version = "0.4.0", default-features = false } # CPU-only
301
320
  ```
302
321
 
303
322
  ```rust
@@ -414,7 +433,7 @@ fuzzgpu/
414
433
  │ └── process.py # rapidfuzz.process-compatible helpers
415
434
  ├── fuzz/ # libFuzzer targets + stable self-harness
416
435
  ├── benchmarks/ # Comparative benchmark scripts
417
- ├── tests/ # Python pytest suite (174 tests)
436
+ ├── tests/ # Python pytest suite (278 tests incl. rapidfuzz differential)
418
437
  └── docs/GPU_TESTING.md # Fault injection & GPU test conventions
419
438
  ```
420
439
 
@@ -442,7 +461,7 @@ cargo test --workspace
442
461
  | `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
443
462
  | `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
444
463
  | `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
445
- | `FUZZGPU_SKIP_DISPATCH_LOCK` | Bypass serialization lock (repro only) |
464
+ | `FUZZGPU_SKIP_DISPATCH_LOCK` | Opt-in GPU dispatch serialization (safety valve for the rare gfx-rs/wgpu#10085 crash class on Intel D3D12; dispatch is fully concurrent by default) |
446
465
  | `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
447
466
  | `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
448
467
  | `PROPTEST_CASES` | Override proptest case count |
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fuzzgpu-core"
3
- version = "0.2.0"
3
+ version = "0.4.0"
4
4
  edition = "2021"
5
5
  description = "GPU-accelerated fuzzy string matching engine"
6
6
  license = "MIT"
@@ -618,20 +618,27 @@ pub fn wratio(s1: &str, s2: &str, score_cutoff: f64) -> f64 {
618
618
  len2 as f64 / len1 as f64
619
619
  };
620
620
 
621
- let mut end_ratio = ratio_with_cutoff(s1, s2, score_cutoff);
621
+ // rapidfuzz threads the *mutated* cutoff forward: each step rescales the
622
+ // running cutoff (already divided by the previous step's scale) by its own
623
+ // scale factor, so a low end_ratio at a high user cutoff escalates the
624
+ // effective cutoff past 100 and suppresses the token/partial-token terms.
625
+ // Reusing the original score_cutoff at every step instead let those terms
626
+ // leak through (WRatio score_cutoff parity).
627
+ let mut cutoff = score_cutoff;
628
+ let mut end_ratio = ratio_with_cutoff(s1, s2, cutoff);
622
629
 
623
630
  if len_ratio < 1.5 {
624
- let c = score_cutoff.max(end_ratio) / UNBASE_SCALE;
625
- return end_ratio.max(token_ratio(s1, s2, c) * UNBASE_SCALE);
631
+ cutoff = cutoff.max(end_ratio) / UNBASE_SCALE;
632
+ return end_ratio.max(token_ratio(s1, s2, cutoff) * UNBASE_SCALE);
626
633
  }
627
634
 
628
635
  let partial_scale = if len_ratio <= 8.0 { 0.9 } else { 0.6 };
629
636
 
630
- let c = score_cutoff.max(end_ratio) / partial_scale;
631
- end_ratio = end_ratio.max(partial_ratio(s1, s2, c) * partial_scale);
637
+ cutoff = cutoff.max(end_ratio) / partial_scale;
638
+ end_ratio = end_ratio.max(partial_ratio(s1, s2, cutoff) * partial_scale);
632
639
 
633
- let c = score_cutoff.max(end_ratio) / UNBASE_SCALE;
634
- end_ratio.max(partial_token_ratio(s1, s2, c) * UNBASE_SCALE * partial_scale)
640
+ cutoff = cutoff.max(end_ratio) / UNBASE_SCALE;
641
+ end_ratio.max(partial_token_ratio(s1, s2, cutoff) * UNBASE_SCALE * partial_scale)
635
642
  }
636
643
 
637
644
  /// QRatio: rapidfuzz's quick ratio — 0 for empty inputs (FuzzyWuzzy
@@ -647,12 +654,8 @@ pub fn qratio(s1: &str, s2: &str, score_cutoff: f64) -> f64 {
647
654
  /// Uses the shared-query Myers SIMD fast path when the query is ASCII ≤ 64 bytes
648
655
  /// and all candidates are ASCII — same acceleration as `levenshtein_batch_auto`.
649
656
  pub fn ratio_batch(query: &str, candidates: &[&str]) -> Vec<f64> {
650
- // The indel model (substitution cost=2) does not have a direct Myers
651
- // bit-vector path Myers gives edit distance with unit substitution cost.
652
- // We approximate with the standard Levenshtein batch and then convert:
653
- // indel_dist = 2 * lev_dist when lev path only uses ins/del (no subs).
654
- // For general strings we fall back to the per-pair indel_distance.
655
- // The Rayon parallel path is correct for all inputs.
657
+ // Per-pair ratio over Rayon; each pair takes the ASCII Myers / char-DP
658
+ // fast paths inside indel_distance.
656
659
  candidates.par_iter().map(|c| ratio(query, c)).collect()
657
660
  }
658
661
 
@@ -1154,4 +1157,17 @@ mod tests {
1154
1157
  let r = wratio("new york mets", "new york", 0.0);
1155
1158
  assert!((0.0..=100.0).contains(&r));
1156
1159
  }
1160
+
1161
+ #[test]
1162
+ fn test_wratio_cutoff_threads_rescaled_cutoff() {
1163
+ // rapidfuzz WRatio rescales the running cutoff at each step, so a high
1164
+ // user cutoff suppresses the token terms even when a perfect substring
1165
+ // exists. Regression: fuzzgpu returned 57.0/85.5 where rapidfuzz
1166
+ // returns 0.0 for these inputs.
1167
+ assert_eq!(wratio("new york yankees", "a", 90.0), 0.0);
1168
+ assert_eq!(wratio("a", "ab", 95.0), 0.0);
1169
+ assert_eq!(wratio("hello world", "world", 95.0), 0.0);
1170
+ // The cutoff=0 path is unaffected: the unscaled partial ratio still wins.
1171
+ assert!((wratio("new york yankees", "a", 0.0) - 60.0).abs() < 1e-9);
1172
+ }
1157
1173
  }