ablaut
A fast, correct German verb conjugator.
The name is the German term for the vowel gradation in singen, sang, gesungen: Jacob Grimm formalized its seven classes in 1819, and they still describe every strong verb in the language.
Highlights
- Measured correctness. Every generated form is validated against two machine-readable gold standards: 99.2% agreement with UniMorph deu (194k forms) and 98.0% with the Wiktextract extraction (794k forms, including analytic tenses and the perfect auxiliary). Where the two sources agree with each other, ablaut has zero known errors; every remaining disagreement is ruled on in a published adjudication log with references to standard grammars.
- Generalizes to unseen verbs. A rule engine with a curated exception lexicon, not a lookup table: novel verbs (googeln, downloaden) conjugate correctly. On verbs outside its lexicon, agreement with UniMorph is 99.55%.
- Fast and small. No I/O, no runtime data files, no dependencies in the core crate. A complete conjugation table (100+ forms) takes microseconds; the entire engine compiles to a 106 KB WebAssembly binary (about 45 KB gzipped).
- Permissively licensed. MIT OR Apache-2.0, including the lexicon: no ShareAlike obligations.
Usage
Rust
cargo add ablaut
use ablaut::{AnalyticTense, Mood, Number, Person, Tense, Verb};
let v = Verb::from_infinitive("aufstehen")?;
v.conjugate(Tense::Present, Mood::Indicative, Person::First, Number::Singular);
// "stehe auf"
v.conjugate(Tense::Preterite, Mood::Indicative, Person::Third, Number::Singular);
// "stand auf"
v.analytic(AnalyticTense::Perfect, Mood::Indicative, Person::First, Number::Singular);
// "bin aufgestanden"
v.past_participle(); // "aufgestanden"
v.zu_infinitive(); // "aufzustehen"
v.imperative(Number::Singular); // Some("steh auf"); None for modals
The full paradigm as one struct: ablaut::table::Table::build(&v).
Python
pip install ablaut
import ablaut
c = ablaut.conjugate("aufstehen")
c.present[0] # "stehe auf"
c.perfect[0] # "bin aufgestanden"
c.auxiliary # "sein"
c.zu_infinitive # "aufzustehen"
c.imperative # [None, None] for modals
Wheels are abi3 (Python 3.11+); no Rust toolchain needed.
WebAssembly
wasm-pack build --target web -- --features wasm
import init, { conjugate } from "./pkg/ablaut.js";
await init();
const c = conjugate("aufstehen");
c.present[0]; // "stehe auf"
c.zuInfinitive; // "aufzustehen"
Coverage
All synthetic and analytic forms of standard German:
- Tenses and moods: Präsens, Präteritum, Perfekt, Plusquamperfekt, Futur I/II, Konjunktiv I and II in all tenses (the würde-form is Futur I Konjunktiv II), processual and statal passive
- Non-finite and imperative: both participles, zu-infinitive, perfect infinitive, imperatives including the adhortative (stehen wir auf!) and polite (stehen Sie auf!) forms
- All five inflection classes: weak (the productive default), strong (ablaut, with 2/3sg stem alternation: sprichst, hältst), mixed (dachte), preterite-present (the modals and wissen: ich kann, no imperative), and suppletive (sein, werden, tun)
- The prefix system: separable (stehe auf, aufgestanden, aufzustehen), inseparable (verstanden), fused compounds that never split (lobsingen: lobsang, lobgesungen), multiword lemmas (Rad fahren: fahre Rad, Rad gefahren), and per-lexeme rulings for dual-behavior prefixes (umarmen vs untertauchen)
- Orthographic surface rules: e-epenthesis (arbeitest, bewillkommnest), s-coalescence (du lässt), schwa elision (ich sammle), the Latinate -ieren participle (studiert but geschmiert), and per-lexeme perfect auxiliaries (aufstehen: sein)
The exception lexicon (data/verbs.tsv, about 900
human-readable rulings) is compiled into the binary.
How correctness is verified
src/bin/golden.rs diffs every generated form against the gold data
(scripts/fetch_unimorph.sh, scripts/fetch_kaikki.sh) and CI fails if
accuracy regresses below pinned thresholds. scripts/cross_oracle.py
cross-examines the two oracles against each other: they agree on 98.9% of
their 195k shared slots, and triaging ablaut's mismatches against that
agreement separates genuine bugs from gold-data errors.
The method has found real errors in the gold data itself, documented in
docs/adjudications.tsv: UniMorph gives the
Konjunktiv II of nennen as nannte (correct: nennte) and marks
wisse! as nonexistent; Wiktionary assigns wachen the auxiliary sein
and conjugates entgelten weak. One caveat: both oracles derive from
Wiktionary, so their agreement is strong but not fully independent
evidence.
Design
The architecture is a productive default rule plus a finite table of stored
exceptions, which is precisely the dual-mechanism model of inflection
(Marcus, Pinker et al., 1995) for which German morphology is the canonical
test case. Features follow the UniMorph schema.
docs/design.md maps the whole domain in four layers
and doubles as the design spec.
License
MIT OR Apache-2.0.
Data provenance: the exception lexicon is independently curated factual data about standard German (principal parts, prefix behavior, auxiliaries), hand-verified row by row. UniMorph (CC BY-SA 3.0) and Wiktextract (CC BY-SA) are used as test oracles only: fetched at development time, never shipped.
Metadata
Release files for ablaut 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ablaut-0.1.4-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| ablaut-0.1.4-cp311-abi3-manylinux_2_34_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ x86-64 | Details |
| ablaut-0.1.4-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 771.6 kB
Release files / ablaut-0.1.4-cp311-abi3-win_amd64.whl
| Download URL | ablaut-0.1.4-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 177.9 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
99899bcf64d090008930e35fcb02a3423a6d619cb17a0b2888071ed2e56b4792
|
|
BLAKE2b-256 checksum How to use checksums |
4b3e906651eb58bc1a04a4b08b8b8ebff8fec4e0c61cfd4b49d0fa62e9eb9e93
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency logRelease files / ablaut-0.1.4-cp311-abi3-manylinux_2_34_x86_64.whl
| Download URL | ablaut-0.1.4-cp311-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 315.2 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e90f03808ff1b148a20b2c5801406b93ecfb980fb1433f5d1ce7be5b05e32ff6
|
|
BLAKE2b-256 checksum How to use checksums |
8072c47288aed874edfc59b2aae6c5b850785ae6cc9a815d97aa8245c65c91e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency logRelease files / ablaut-0.1.4-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | ablaut-0.1.4-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 278.5 kB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f4d5869305e69f079d76b01e9fdbd9a7dcb695ee32c1e5a6610f1d42cffe254a
|
|
BLAKE2b-256 checksum How to use checksums |
502cc8f09d387db309619456c09693c65fbee0cf20fbdc550b9aaaee02c60a73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency log