Rule-based morphological tokenizer for Emakhuwa (Bantu P.31)
Project description
emakhuwa-tokenizer
emakhuwa-tokenizer/ ├── AGENTS.md, BOOTSTRAP.md, HEARTBEAT.md, IDENTITY.md # workspace/agent docs ├── SOUL.md, TASK.md, TOOLS.md, USER.md, README.md ├── LICENSE ├── config.yaml ├── pyproject.toml, pytest.ini # project/build config │ ├── analysis/ # linguistic data │ ├── morpheme_inventory.json │ ├── noun_class_table.json │ └── verb_paradigms.json │ ├── evaluation/ # eval results & gold sets │ ├── error_analysis.md │ ├── gold_errors.json / gold_standard.json │ ├── gold_standard_results.json / results.json │ └── pytest_output.txt │ ├── reference/ │ └── MORPHOLOGY_REFERENCE.md │ ├── rules/ # morphology rule definitions │ ├── extensions.json, imbrication.json │ ├── morphophonology.json, negation.json │ ├── noun_classes.json, spelling_normalization.json │ └── verb_template.json │ ├── scripts/ │ ├── evaluate.py, evaluate_gold.py │ └── phase1_analyze.py │ ├── src/emakhuwa_tokenizer/ # main package │ ├── init.py, cli.py, tokenizer.py │ ├── decision.py, glosser.py, imbrication.py │ ├── lemmatizer.py, lexicon.py, lookup.py │ ├── models.py, morphophonology.py, normalizer.py │ ├── rules.py, segmenter.py, sentence.py │ └── rule_data/ # packaged copies of rules/*.json │ ├── init.py │ └── *.json (extensions, imbrication, morphophonology, ...) │ └── tests/ └── test_tokenizer.py
Rule-based morphological tokenizer for Emakhuwa / Makhuwa (Bantu P.31), focused on morphologically informed segmentation, root identification, and word-class prediction.
The package implements a transparent linguistic pipeline for Emakhuwa morphology: spelling normalization, morphophonological reversal, template-based verb parsing, noun-class analysis, extension handling, imbrication, and lexicon-assisted segmentation.
Linguistic background
Emakhuwa is a Bantu language of Mozambique with rich agglutinative morphology. A useful morphological tokenizer must handle phenomena such as:
- noun-class prefixes:
mu-,a-,mi-,ma-,e-,i-, locatives, and agentive patterns - verbal template slots:
NEG-SM-TAM-OP-ROOT-EXT-FV - subject/object marker allomorphy
- TAM markers such as
naa-,ho-,nni- - derivational extensions: applicative, causative, reciprocal, passive, stative, intensive
- vowel-height harmony in extensions
- imbrication in recent-past forms
- spelling and apostrophe normalization
Installation
pip install emakhuwa-tokenizer
For development:
git clone <repo-url>
cd emakhuwa-tokenizer
pip install -e .[dev]
pytest
Quick start
from emakhuwa_tokenizer import tokenize, tokenize_sentence, lemmatize, load_tokenizer
analysis = tokenize("kinaavaha")
print(analysis.root)
print([(m.form, m.slot, m.gloss) for m in analysis.morphemes])
# Reuse a tokenizer instance for many words
tok = load_tokenizer()
for word in ["kinaavaha", "nkivahale", "kivanje"]:
print(tok.analyze_word(word).to_dict())
print(lemmatize("kinaavaha")) # ovaha
results = tokenize_sentence("Mwana anaavaha mwalimu ehuku")
for r in results:
print(f"{r.surface_form}: {r.root} ({r.word_class})")
Sentence example:
>>> from emakhuwa_tokenizer import tokenize_sentence
>>> results = tokenize_sentence("Mwana anaavaha mwalimu ehuku")
>>> for r in results:
... print(f"{r.surface_form}: {r.root} ({r.word_class})")
Mwana: ana (noun)
anaavaha: vah (verb)
mwalimu: alimu (noun)
ehuku: huku (noun)
Example output shape:
{
"surface_form": "kinaavaha",
"normalized_form": "kinaavaha",
"root": "vah",
"word_class": "verb",
"tam": "PRES/FUT",
"morphemes": [
{"form": "ki", "slot": "SM", "gloss": "1SG"},
{"form": "naa", "slot": "TAM", "gloss": "PRES/FUT"},
{"form": "vah", "slot": "ROOT", "gloss": "vah"},
{"form": "a", "slot": "FV", "gloss": "FV.IND/IMP/INF"}
]
}
CLI usage
The package installs two equivalent commands:
emakhuwa-tokenize kinaavaha
makhuwa-tokenize kinaavaha
Text output:
Word: kinaavaha
Class: verb
Root: vah
Lemma: ovaha
Morphemes:
ki- [SM ] 1SG
naa- [TAM ] PRES/FUT
vah- [ROOT ] give
-a [FV ] indicative
Confidence: 0.95
Path: rule
Analyze a sentence:
emakhuwa-tokenize "Mwana anaavaha mwalimu ehuku"
Only lemmas:
emakhuwa-tokenize --lemma kinaavaha
JSON output:
emakhuwa-tokenize --json kinaavaha nkivahale
For one word, JSON output is a single object. For multiple words or sentence input, it is an array of objects.
{
"word": "kinaavaha",
"word_class": "verb",
"root": "vah",
"lemma": "ovaha",
"morphemes": [
{"form": "ki", "slot": "SM", "gloss": "1SG"},
{"form": "naa", "slot": "TAM", "gloss": "PRES/FUT"},
{"form": "vah", "slot": "ROOT", "gloss": "give"},
{"form": "a", "slot": "FV", "gloss": "indicative"}
],
"confidence": 0.95,
"path": "rule"
}
Verbose analysis:
emakhuwa-tokenize --verbose kivanje
Process a file, one word per line:
emakhuwa-tokenize --file words.txt --json
Use a custom dictionary/training data directory:
emakhuwa-tokenize --data-dir data/ kinaavaha
API reference
tokenize(word: str) -> MorphToken
Tokenize a single Emakhuwa word using the packaged rule system.
from emakhuwa_tokenizer import tokenize
analysis = tokenize("kivanje")
load_tokenizer(data_dir: str | None = None) -> Tokenizer
Create a reusable tokenizer. If data_dir is supplied, the tokenizer can build a training lexicon from that directory. If omitted, it uses packaged JSON rules only.
from emakhuwa_tokenizer import load_tokenizer
tok = load_tokenizer()
analysis = tok.analyze_word("nkivahale")
lemmatize(word: str) -> str
Return a citation-form lemma. Verbs are returned as infinitives (o- + root + -a); nouns return the identified bare stem/root.
from emakhuwa_tokenizer import lemmatize
print(lemmatize("kinaavaha")) # ovaha
tokenize_sentence(text: str) -> list[MorphToken]
Split a sentence on whitespace/punctuation and analyze each word in order.
from emakhuwa_tokenizer import tokenize_sentence
results = tokenize_sentence("Mwana anaavaha mwalimu ehuku")
MorphToken
Dataclass representing one analyzed word.
Important fields:
surface_formnormalized_formmorphemesrootword_classnoun_classtamconfidenceglossdiagnostics
Use to_dict() for JSON serialization.
Morpheme
Dataclass representing one morpheme.
Important fields:
formslotglosspositionunderlyingconfidence
Architecture overview
raw word
↓
spelling normalization
↓
exact dictionary lookup, optional
↓
rule-based segmentation
├─ noun-class and relational-prefix analysis
├─ verb-template parser: NEG-SM-TAM-OP-ROOT-EXT-FV
├─ extension and vowel-harmony handling
├─ imbrication reversal
└─ morphophonological candidate handling
↓
decision routing and confidence scoring
↓
MorphToken output
Rules are externalized as JSON under emakhuwa_tokenizer/rule_data/:
morphophonology.jsonverb_template.jsonnoun_classes.jsonextensions.jsonimbrication.jsonnegation.jsonspelling_normalization.json
Evaluation
The current external gold-standard benchmark contains 272 manually annotated items.
Final Phase 8/9 metrics on evaluation/gold_standard.json:
| Metric | Score |
|---|---|
| Boundary precision | 0.7938 |
| Boundary recall | 0.8110 |
| Boundary F1 | 0.8023 |
| Lemma/root accuracy | 0.8566 |
| Word-class accuracy | 0.7647 |
Test suite:
pytest tests/ -v
3 passed
Development
Run tests:
pytest
Run external gold evaluation:
python scripts/evaluate_gold.py
Build package:
python -m build
cd C:\Users\t-fali\Pictures\mystuff\Consutorias\MAPA\emakhuwa-tokenizer
pip install -e .
emakhuwa-tokenize --json "kinohimeryakani"
emakhuwa-tokenize "Mwana anaavaha mwalimu ehuku"
emakhuwa-tokenize --lemma "kinaavaha"
pytest tests/ -v
Contributing
Contributions are welcome, especially:
- additional manually verified gold data
- dialect-specific spelling normalization rules
- improved finite-state morphology rules
- better handling of lexicalized nouns/adjectives
- documentation of Emakhuwa morpheme inventories
Please keep linguistic rules transparent and prefer JSON-rule updates over opaque model behavior when possible.
License
MIT License. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 emakhuwa_tokenizer-0.1.0.tar.gz.
File metadata
- Download URL: emakhuwa_tokenizer-0.1.0.tar.gz
- Upload date:
- Size: 37.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2a7051444b56a9dfc46a3b8c0cc060435209c2dae34ff616421f7ce736dfd13
|
|
| MD5 |
874683dd393cdcd76a0db145b05575cf
|
|
| BLAKE2b-256 |
4c52483abd80d52624423617aeb1acdb88dfb267e1adf5967a768e8479cc40b5
|
File details
Details for the file emakhuwa_tokenizer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: emakhuwa_tokenizer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 40.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2557e76ff43d46b07d121a416351455fc5d6e378ff061f1afc64ac14844a24ac
|
|
| MD5 |
3b6a0ab42e33b57bc9f41a5e9fcab9ec
|
|
| BLAKE2b-256 |
1608c476940e153e0aeee08f7a0dd85f00ac94dc25a79711b33f7136adbb36ef
|