feat(python): add native distribution and release infrastructure
- add the Rust-backed Python API with PyStemmer compatibility - distribute standard compiled models as a separate Python package - generate model artifacts during builds instead of storing them in Git - add GitHub release and Pages-backed package index workflows - add Python tests, benchmarks, documentation, and Gradle integration - refresh the documentation site, branding, and language benchmarks
This commit is contained in:
@@ -6,16 +6,16 @@ This benchmark is the clearest demonstration of the Radixor quality/speed envelo
|
||||
|
||||
| Used rows | Actual row ratio | All exact | Changed exact | Root preserved | Speed ms/op | Error ms | ns/token |
|
||||
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| 100% | 100.000% | 97.478% | 97.197% | 97.552% | 20.627 | 2.117 | 98.0 |
|
||||
| 90% | 90.000% | 97.047% | 94.913% | 97.613% | 21.713 | 2.104 | 103.2 |
|
||||
| 80% | 80.000% | 96.635% | 92.768% | 97.661% | 17.408 | 1.438 | 82.7 |
|
||||
| 70% | 70.000% | 96.209% | 90.565% | 97.705% | 16.946 | 1.531 | 80.5 |
|
||||
| 60% | 60.000% | 95.750% | 88.384% | 97.703% | 15.735 | 1.278 | 74.8 |
|
||||
| 50% | 50.000% | 95.262% | 86.107% | 97.690% | 14.714 | 1.089 | 69.9 |
|
||||
| 40% | 40.000% | 94.753% | 83.855% | 97.643% | 15.090 | 1.254 | 71.7 |
|
||||
| 30% | 30.000% | 94.208% | 81.651% | 97.537% | 13.773 | 1.071 | 65.4 |
|
||||
| 20% | 20.000% | 93.633% | 79.366% | 97.416% | 15.396 | 2.497 | 73.1 |
|
||||
| 10% | 10.000% | 92.868% | 76.516% | 97.204% | 16.970 | 2.847 | 80.6 |
|
||||
| 100% | 100.000% | 97.478% | 97.197% | 97.552% | 15.064 | 0.658 | 71.6 |
|
||||
| 90% | 90.000% | 97.047% | 94.913% | 97.613% | 17.798 | 2.161 | 84.6 |
|
||||
| 80% | 80.000% | 96.635% | 92.768% | 97.661% | 13.900 | 0.941 | 66.0 |
|
||||
| 70% | 70.000% | 96.209% | 90.565% | 97.705% | 14.809 | 1.376 | 70.3 |
|
||||
| 60% | 60.000% | 95.750% | 88.384% | 97.703% | 13.186 | 0.930 | 62.6 |
|
||||
| 50% | 50.000% | 95.262% | 86.107% | 97.690% | 12.852 | 0.943 | 61.1 |
|
||||
| 40% | 40.000% | 94.753% | 83.855% | 97.643% | 12.358 | 0.831 | 58.7 |
|
||||
| 30% | 30.000% | 94.208% | 81.651% | 97.537% | 11.657 | 0.921 | 55.4 |
|
||||
| 20% | 20.000% | 93.633% | 79.366% | 97.416% | 11.494 | 1.256 | 54.6 |
|
||||
| 10% | 10.000% | 92.868% | 76.516% | 97.204% | 9.895 | 0.925 | 47.0 |
|
||||
|
||||
## Column Meanings
|
||||
|
||||
|
||||
@@ -4,25 +4,25 @@ The values below are environment-specific and must not be read as universal perf
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Benchmark date | 2026-07-23 (Europe/Prague) |
|
||||
| Benchmark date | 2026-08-10 (Europe/Prague) |
|
||||
| Corpus command | `./gradlew benchmarkCorpusReport --no-daemon` |
|
||||
| Exact-root accuracy command | Direct JMH execution of the four `*BenchmarkQuality` classes selected in `stemmer-accuracy-2026-07-23.txt`; timing scores are discarded |
|
||||
| Exact-root accuracy command | `tools/run-published-accuracy-benchmarks.sh 2026-08-10`; all four `*BenchmarkQuality` classes are selected and timing scores are discarded |
|
||||
| Stemming-quality command | `./gradlew stemmingQuality --no-daemon` |
|
||||
| Published speed command | `tools/run-published-speed-benchmarks.sh 2026-07-23` |
|
||||
| Published speed run interval | 2026-07-23 12:58:50 to 15:15:43 Europe/Prague (2 h 16 min 53 s, including idle intervals and both JMH suites) |
|
||||
| Published speed command | `tools/run-published-speed-benchmarks.sh 2026-08-10` |
|
||||
| Published speed run interval | 2026-08-10 16:22:33 to 18:36:41 Europe/Prague (2 h 14 min 8 s, including idle intervals and both JMH suites) |
|
||||
| Stabilization intervals | 120 s before the main speed matrix; 60 s between the main matrix and coverage-speed suite |
|
||||
| Corpus and command report | `build/reports/jmh/benchmark-corpora.csv` |
|
||||
| Exact-root reports | `build/reports/jmh/stemmer-accuracy-2026-07-23.csv` and `.txt` |
|
||||
| Speed reports | `build/reports/jmh/stemmer-speed-2026-07-23.csv` and `.txt` |
|
||||
| English coverage accuracy reports | `build/reports/jmh/english-coverage-accuracy-2026-07-23.csv` and `.txt` |
|
||||
| English coverage speed reports | `build/reports/jmh/english-coverage-speed-2026-07-23.csv` and `.txt` |
|
||||
| Exact-root reports | `build/reports/jmh/stemmer-accuracy-2026-08-10.csv` and `.txt` |
|
||||
| Speed reports | `build/reports/jmh/stemmer-speed-2026-08-10.csv` and `.txt` |
|
||||
| English coverage accuracy reports | `build/reports/jmh/english-coverage-accuracy-2026-08-10.csv` and `.txt` |
|
||||
| English coverage speed reports | `build/reports/jmh/english-coverage-speed-2026-08-10.csv` and `.txt` |
|
||||
| Stemming-quality reports | `build/reports/stemming-quality/stemming-quality.csv` and `.md` |
|
||||
| Environment report | `build/reports/jmh/performance-environment-2026-07-23.txt` |
|
||||
| Selected speed methods | `build/reports/jmh/published-speed-benchmarks-2026-07-23.txt` |
|
||||
| Environment report | `build/reports/jmh/performance-environment-2026-08-10.txt` |
|
||||
| Selected speed methods | `build/reports/jmh/published-speed-benchmarks-2026-08-10.txt` |
|
||||
| Comparison scope | Same-language methods used by the 20 language pages; `PolishPolimorfStemmerComparisonBenchmark`, all quality methods, the separate CISTEM gold-standard experiment, and internal trie microbenchmarks are excluded |
|
||||
| Model scope | Exactly the 20 IDs declared by `Language.defaultModelId()`; Polish uses `pl-pl-unimorph`, and `pl-pl-polimorf` is not measured |
|
||||
| Core base commit | `1f1b03c6a8d36a0918b92ebde698e5379a2a5946` |
|
||||
| Measured source state | `release@4.0.0-dirty`; exact tracked changes and untracked-source checksums are retained as `measured-source-2026-07-23.patch` and `measured-untracked-2026-07-23.sha256` |
|
||||
| Core base commit | `b45e143c8484c2ae1d6e31069a2e67232c4f7f29` |
|
||||
| Measured source state | `release@4.1.0-dirty`; exact tracked changes and untracked-source checksums are retained as `measured-source-2026-08-10.patch` and `measured-untracked-2026-08-10.sha256` |
|
||||
| JMH version | 1.37 |
|
||||
| Speed benchmark mode | Average time, `time/op` |
|
||||
| Score unit | `ns/op`; language pages additionally derive `ms/op` and `ns/token` |
|
||||
@@ -32,21 +32,21 @@ The values below are environment-specific and must not be read as universal perf
|
||||
| Speed threads | 1 |
|
||||
| Speed fork heap | Fixed `-Xms6g -Xmx6g` |
|
||||
| Reported uncertainty | JMH `Score Error (99.9%)` over 30 measured samples |
|
||||
| Observed relative uncertainty | Main speed matrix: maximum 11.945%, with 6 of 102 rows above 10%; coverage-speed curve: maximum 16.775%, with 3 of 10 rows above 10%; no published row exceeded 20% |
|
||||
| Observed relative uncertainty | Main speed matrix: maximum 10.607%, with 2 of 105 rows above 10%; coverage-speed curve: maximum 12.142%, with 2 of 10 rows above 10%; no published row exceeded 20% |
|
||||
| Deterministic measurements | Corpus, patch-command distribution, exact-root counters, coverage accuracy, and pairwise stemming quality are evaluated without interpreting runtime scores; no warmup is required |
|
||||
| JVM reported by JMH | JDK 25.0.3, OpenJDK 64-Bit Server VM, 25.0.3+9 |
|
||||
| Java runtime | OpenJDK Runtime Environment, Red Hat build 25.0.3+9 |
|
||||
| JVM reported by JMH | JDK 25.0.4, OpenJDK 64-Bit Server VM, 25.0.4+7 |
|
||||
| Java runtime | OpenJDK Runtime Environment, Red Hat build 25.0.4+7 |
|
||||
| JVM invoker | `/usr/lib/jvm/java-25-openjdk/bin/java` |
|
||||
| Operating system | Fedora Linux 44 (MATE-Compiz) |
|
||||
| Kernel | Linux 7.1.4-200.fc44.x86_64 |
|
||||
| Kernel | Linux 7.1.7-200.fc44.x86_64 |
|
||||
| Architecture | x86_64 |
|
||||
| CPU | AMD Ryzen 5 8600G w/ Radeon 760M Graphics |
|
||||
| CPU | AMD Ryzen 5 7600 6-Core Processor |
|
||||
| Physical / logical CPUs | 6 / 12 |
|
||||
| CPU frequency policy | `amd-pstate-epp`; governor `performance` on every logical CPU; EPP `performance`; boost enabled |
|
||||
| CPU affinity | Scheduler default; no explicit pinning |
|
||||
| Installed memory | 60 GiB reported by the operating system |
|
||||
| Pre-run idle state | Load average 0.25 / 0.36 / 0.71 after the 120 s idle interval; CPU Tctl 40.2 degrees Celsius; swap unused |
|
||||
| End-of-run state | Load average 1.16 / 1.28 / 1.32; CPU Tctl 60.5 degrees Celsius |
|
||||
| Installed memory | 61 GiB reported by the operating system |
|
||||
| Pre-run idle state | Load average 0.16 / 0.42 / 0.88 after the 120 s idle interval; CPU Tctl 57.4 degrees Celsius; swap unused |
|
||||
| End-of-run state | Load average 1.59 / 1.49 / 1.36; CPU Tctl 78.1 degrees Celsius |
|
||||
| Power and idle policy | Developer workstation on stable power; screensaver, suspend, and hibernation disabled |
|
||||
| Concurrent project work | None during the published speed and coverage-speed run |
|
||||
|
||||
@@ -67,15 +67,15 @@ The JMH runtime classpath contains the optional model artifact because it is a s
|
||||
Generated local report files for this benchmark update:
|
||||
|
||||
- `build/reports/jmh/benchmark-corpora.csv`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-07-23.csv`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-07-23.txt`
|
||||
- `build/reports/jmh/stemmer-speed-2026-07-23.csv`
|
||||
- `build/reports/jmh/stemmer-speed-2026-07-23.txt`
|
||||
- `build/reports/jmh/english-coverage-accuracy-2026-07-23.csv`
|
||||
- `build/reports/jmh/english-coverage-accuracy-2026-07-23.txt`
|
||||
- `build/reports/jmh/english-coverage-speed-2026-07-23.csv`
|
||||
- `build/reports/jmh/english-coverage-speed-2026-07-23.txt`
|
||||
- `build/reports/jmh/performance-environment-2026-07-23.txt`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-08-10.csv`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-08-10.txt`
|
||||
- `build/reports/jmh/stemmer-speed-2026-08-10.csv`
|
||||
- `build/reports/jmh/stemmer-speed-2026-08-10.txt`
|
||||
- `build/reports/jmh/english-coverage-accuracy-2026-08-10.csv`
|
||||
- `build/reports/jmh/english-coverage-accuracy-2026-08-10.txt`
|
||||
- `build/reports/jmh/english-coverage-speed-2026-08-10.csv`
|
||||
- `build/reports/jmh/english-coverage-speed-2026-08-10.txt`
|
||||
- `build/reports/jmh/performance-environment-2026-08-10.txt`
|
||||
- `build/reports/stemming-quality/stemming-quality.csv`
|
||||
- `build/reports/stemming-quality/stemming-quality.md`
|
||||
- `build/reports/stemming-quality/metric-correlations-pearson.csv`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The stemmer comparison suite measures Radixor and Java stemmers on the same language and deterministic Radixor model dictionary-derived data. Published Radixor rows in this refresh use contracted compiled patch tries, where uniform preferred-command subtrees are collapsed into accepting leaves before the trie is frozen for lookup. For each language, the registered default model resource stores the expected root as the first tab-separated field on a line and its surface forms on the same line. Every single-token field on that line can therefore be paired with the same expected root.
|
||||
|
||||
Published speed results come only from the exact method selection retained in `published-speed-benchmarks-2026-07-23.txt`. Internal `FrequencyTrie*` microbenchmarks, quality methods, the CISTEM gold-standard experiment, and the optional `PolishPolimorfStemmerComparisonBenchmark` are not part of those results.
|
||||
Published speed results come only from the exact method selection retained in `published-speed-benchmarks-2026-08-10.txt`. Internal `FrequencyTrie*` microbenchmarks, quality methods, the CISTEM gold-standard experiment, and the optional `PolishPolimorfStemmerComparisonBenchmark` are not part of those results. The Snowball 3.1.0 refresh adds direct Czech, Persian, and Polish workloads; the existing Radixor and Lucene workload domains are unchanged.
|
||||
|
||||
## Benchmark Passes
|
||||
|
||||
@@ -41,8 +41,8 @@ For right-to-left Radixor languages, patch application uses the traversal direct
|
||||
|
||||
The quality pass reports exact-root agreement against the expected root from the default-model dictionary line. External-stemmer counters are written to:
|
||||
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-07-23.csv`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-07-23.txt`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-08-10.csv`
|
||||
- `build/reports/jmh/stemmer-accuracy-2026-08-10.txt`
|
||||
|
||||
Accuracy is computed from standard JMH secondary rows:
|
||||
|
||||
|
||||
@@ -4,19 +4,28 @@
|
||||
|
||||
- Machine-readable CSV: [stemming-quality.csv](../data/stemming-quality.csv)
|
||||
- SHA-256 record: [stemming-quality.sha256](../data/stemming-quality.sha256)
|
||||
- SHA-256: `edf16b07be8a535943ddf37caeb8807755c95e9e1fb13244145f28be74b491d8`
|
||||
- Complete scenarios: 308
|
||||
- SHA-256: `d34f325da320a2e040b54d8d8b5c216d70448f08cfb8659a423e99882aa1afb5`
|
||||
- Complete scenarios: 314
|
||||
- Authoritative language universe: 20 languages
|
||||
- Language-page scenarios: 308 across 20 benchmark pages
|
||||
- Language-page scenarios: 314 across 20 benchmark pages
|
||||
|
||||
The CSV contains the model ID, independent model version, descriptor SHA-256, raw pair counts, raw over/under numerators and denominators, candidate statistics, and relation metrics. Reserved partition-metric columns remain empty because the gold standard is an overlapping cover. Documentation is regenerated from this file rather than manually transcribed. Publication fails when any row uses a model other than the language's registered default.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
./gradlew stemmingQuality
|
||||
./gradlew publishStemmingQualityDocumentation
|
||||
./gradlew verifyStemmingQualityDocumentation
|
||||
./gradlew --no-daemon stemmingQuality \
|
||||
publishStemmingQualityDocumentation \
|
||||
verifyStemmingQualityDocumentation
|
||||
./gradlew --no-daemon benchmarkCorpusReport writeJmhRuntimeClasspath
|
||||
tools/run-published-accuracy-benchmarks.sh 2026-08-10
|
||||
tools/run-published-speed-benchmarks.sh 2026-08-10
|
||||
python3 tools/update-benchmark-documentation.py \
|
||||
--corpus build/reports/jmh/benchmark-corpora.csv \
|
||||
--accuracy build/reports/jmh/stemmer-accuracy-2026-08-10.csv \
|
||||
--speed build/reports/jmh/stemmer-speed-2026-08-10.csv \
|
||||
--coverage-accuracy build/reports/jmh/english-coverage-accuracy-2026-08-10.csv \
|
||||
--coverage-speed build/reports/jmh/english-coverage-speed-2026-08-10.csv
|
||||
./gradlew test
|
||||
./gradlew prepareMkDocsSource
|
||||
mkdocs build --strict --config-file build/mkdocs/mkdocs.yml
|
||||
@@ -59,18 +68,19 @@ The Pages workflow publishes that staged documentation together with Javadoc, JU
|
||||
|
||||
## Performance benchmark reproduction
|
||||
|
||||
The current speed and coverage-speed command is:
|
||||
The current accuracy, speed, and coverage commands are:
|
||||
|
||||
```bash
|
||||
./gradlew writeJmhRuntimeClasspath --no-daemon
|
||||
tools/run-published-speed-benchmarks.sh 2026-07-23
|
||||
./gradlew --no-daemon benchmarkCorpusReport writeJmhRuntimeClasspath
|
||||
tools/run-published-accuracy-benchmarks.sh 2026-08-10
|
||||
tools/run-published-speed-benchmarks.sh 2026-08-10
|
||||
```
|
||||
|
||||
The runner refuses to start unless every CPU uses the `performance` governor, materializes the exact selected benchmark list, rejects quality/Polimorf/gold-standard methods, and requires the Hebrew speed path. It records hardware, JVM, source-state, JAR, classpath, corpus, quality, load, temperature, and governor provenance before running. The exact JMH configuration is listed in [Environment and reports](environment.md). Quality and performance reports are separate datasets and are not combined into an undocumented scalar.
|
||||
The speed runner refuses to start unless every CPU uses the `performance` governor, materializes the exact selected benchmark list, rejects quality/Polimorf/gold-standard methods, and requires the Hebrew speed path. It records hardware, JVM, source-state, JAR, classpath, corpus, quality, load, temperature, and governor provenance before running. The accuracy runner evaluates all four exact-root benchmark classes and verifies that every new Snowball 3.1.0 candidate exposes all six accuracy counters. The exact JMH configuration is listed in [Environment and reports](environment.md). Quality and performance reports are separate datasets and are not combined into an undocumented scalar.
|
||||
|
||||
## Recorded and unavailable provenance
|
||||
|
||||
The performance documentation records its 2026-07-23 environment, JDK 25.0.3, operating system, hardware, base revision, exact dirty patch, untracked-source checksums, executable JMH JAR checksum, and model descriptor checksums. The quality CSV embeds model identity and checksum in every row; run date, core source state, JVM, OS, and hardware are shared provenance on the environment page.
|
||||
The performance documentation records its 2026-08-10 environment, JDK, operating system, hardware, base revision, exact dirty patch, untracked-source checksums, executable JMH JAR checksum, and model descriptor checksums. The quality CSV embeds model identity and checksum in every row; run date, core source state, JVM, OS, and hardware are shared provenance on the environment page.
|
||||
|
||||
Exact immutable upstream revisions were not recorded for every legacy UniMorph import. That limitation remains explicit in model descriptors and cannot be repaired from filesystem timestamps. Dependency versions reproducible from repository configuration include Apache Lucene 10.5.0, Morfologik 2.1.9, the Ukrainian dictionary artifact 4.9.1, and JMH 1.37.
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ The JMH adapter registry is authoritative for evaluated implementations and lang
|
||||
|
||||
| Family or implementation | Upstream / attribution | Tested version or revision | Evaluated scope | Output capability and adapter behaviour | Interpretation notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Radixor | Egothor / Radixor project | Base commit and measured working-tree state recorded on the environment page | All 20 reconciled default model languages; all 20 have benchmark pages | Deterministic preferred patch via `get`; ranked distinct alternatives via `getAll`; primary is always included | Model-dictionary-derived compiled patch trie. Default rows use each language's stable default model ID. |
|
||||
| Radixor | Egothor / Radixor project | Base commit and measured working-tree state recorded on the environment page | All 20 reconciled default model languages; all 20 have benchmark pages | Deterministic preferred patch via `get`; ranked distinct alternatives via `getAll`; primary is always included | Dictionary-trained compiled patch trie. Default rows use each language's stable default model ID. |
|
||||
| Apache Lucene language stem filters | Apache Lucene project | 10.5.0 | Adapter-declared language-specific subsets | TokenFilter lifecycle and language normalization match JMH; normally single-output | Light, minimal, possessive, and language stem filters deliberately implement different scopes. Narrow scope is not a defect. |
|
||||
| Apache Lucene SnowballFilter | Apache Lucene project using Snowball algorithms | Lucene 10.5.0 | Snowball-supported subset of Radixor languages | Single primary token emitted through the Lucene TokenFilter path | Includes TokenStream overhead and required normalization. |
|
||||
| Official Snowball Java | Snowball project | Repository preparation downloads the configured upstream Java distribution; an immutable revision was not recorded in the quality CSV | Same-language adapter subset | Direct generated Java API; single output | Rule-based suffix algorithms provide broad baselines rather than dictionary-root guarantees. |
|
||||
| Official Snowball Java | Snowball project | 3.1.0 source distribution; SHA-256 `5dab34d491f55f47b6e971569ffe6aadf5991512c648ddfe5d331b494cf6d655` | 17 same-language direct adapters, including the Czech, Persian, and Polish stemmers added in 3.1.0 | Direct generated Java API; single output | Rule-based suffix algorithms provide broad baselines rather than dictionary-root guarantees. Lucene 10.5.0 does not yet expose the three new algorithms through `SnowballFilter`, so those rows are direct-only. |
|
||||
| Lucene Stempel | Apache Lucene / Polish stemming tables | Lucene 10.5.0 | Polish | Direct and TokenFilter paths where registered; single primary output | Table-driven Polish implementation. |
|
||||
| Morfologik | Morfologik project; Lucene integration by Apache Lucene | Morfologik 2.1.9, Lucene integration 10.5.0; Ukrainian dictionary artifact 4.9.1 | Registered Polish and Ukrainian paths | Deterministic first lemma for primary comparison; all distinct lemma strings for candidate policies | Several analyses may share a lemma and are deduplicated by exact string equality. |
|
||||
| Hunspell via Lucene | Hunspell dictionaries from the `wooorm/dictionaries` repository; adapter by Apache Lucene | Lucene 10.5.0; dictionary repository revision was not recorded | Configured German, English, Spanish, French, Dutch, Polish, and Ukrainian dictionaries | First emitted stem is primary; all distinct stems at the token position are candidates | Dictionary content and affix rules differ by language. |
|
||||
|
||||
Reference in New Issue
Block a user