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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ablaut-0.1.2-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: ablaut-0.1.2-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 174.7 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
799071f8e57290e3d9d5ce704b95865cb0ed69c1e9f9966bbfa8f6ef475084a8
|
|
| MD5 |
6f80687fced1479ce8e29805e94d15b6
|
|
| BLAKE2b-256 |
62516ca66d24f0a2c891793f1b2277256a475ce60e374dae0b7f36715ecc70a5
|
Provenance
The following attestation bundles were made for ablaut-0.1.2-cp311-abi3-win_amd64.whl:
Publisher:
wheels.yml on v4nn4/ablaut
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ablaut-0.1.2-cp311-abi3-win_amd64.whl -
Subject digest:
799071f8e57290e3d9d5ce704b95865cb0ed69c1e9f9966bbfa8f6ef475084a8 - Sigstore transparency entry: 2480807799
- Sigstore integration time:
-
Permalink:
v4nn4/ablaut@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/v4nn4
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Trigger Event:
release
-
Statement type:
File details
Details for the file ablaut-0.1.2-cp311-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: ablaut-0.1.2-cp311-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 311.4 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ef64f740f06a12363a054ae1115ab15a181024a59312c7537be3ffe34ddc038
|
|
| MD5 |
c805a9a4bbc4a32a2acd20e476ec8a54
|
|
| BLAKE2b-256 |
1c68ac25c05f2b72b6113e5887a7b82aa1d6601f79909ab0cc4f2257e25ac6e7
|
Provenance
The following attestation bundles were made for ablaut-0.1.2-cp311-abi3-manylinux_2_34_x86_64.whl:
Publisher:
wheels.yml on v4nn4/ablaut
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ablaut-0.1.2-cp311-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
5ef64f740f06a12363a054ae1115ab15a181024a59312c7537be3ffe34ddc038 - Sigstore transparency entry: 2480807887
- Sigstore integration time:
-
Permalink:
v4nn4/ablaut@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/v4nn4
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Trigger Event:
release
-
Statement type:
File details
Details for the file ablaut-0.1.2-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: ablaut-0.1.2-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 275.8 kB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10a7268bd060f5e4f7d5412f464c286f54a8ad9ae235fec9048ad032425515fb
|
|
| MD5 |
3761c9d854763444272766b217da3326
|
|
| BLAKE2b-256 |
a36656c74176b16d303c5dc4c3c8935dac93a1a586682d8a13eb54958461d224
|
Provenance
The following attestation bundles were made for ablaut-0.1.2-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
wheels.yml on v4nn4/ablaut
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ablaut-0.1.2-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
10a7268bd060f5e4f7d5412f464c286f54a8ad9ae235fec9048ad032425515fb - Sigstore transparency entry: 2480807842
- Sigstore integration time:
-
Permalink:
v4nn4/ablaut@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/v4nn4
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@9be8c4b88e3053fdd7835fecf553232bac03ebdf -
Trigger Event:
release
-
Statement type: