Verb Architecture
This document describes how verbs, tenses, moods, conjugations, and participles are represented in the application. It defines both the linguistic concepts being modeled and the technical implementation used in the database and Rails models.
Key features:
- Cleanly separates lemma, infinitive, participles, and finite forms
- Supports compound tenses and gendered participles
- Links conjugations and infinitives to example sentences
- Provides single-table lookup for efficient queries
- Ready to load large datasets (Verbix, Wiktionary, custom corpora)
1. Linguistic Model
1.1 Core linguistic concepts
| Concept | Description | Example (French aller) |
|---|---|---|
| Lemma (base verb) | The canonical dictionary form of a verb. | aller |
| Infinitive | The unconjugated form that names the action. Some languages have multiple infinitive variants (e.g. German Infinitiv I/II). | aller, sein, gegangen sein |
| Participle / Verbal | A non-finite verb form used to build compound tenses or adjectives. Participles can vary by gender/number (French, Italian). | allé, allée, allés, allées |
| Mood | Expresses the speaker’s attitude (statement, doubt, command…). | Indicatif, Subjonctif, Impératif |
| Tense | Places the action in time within a mood. | Présent, Passé composé, Imparfait |
| Person / Number | Distinguishes the subject performing the action (1st, 2nd, 3rd; singular/plural). | je vais, nous allons |
| Conjugation | A fully inflected finite form (person × mood × tense). | vais, allions, j’allais |
| Compound Tense | A multi-word construction: auxiliary (avoir/être) + participle. | je suis allé(e) |
| Surface form | The final written version including elisions and contractions. | j’ai, j’allais, l’ai vu |
| Negative form | Morphologically negated variant (Turkish, sometimes Romance). | Turkish gelmedim = “I didn’t come” |
1.2 Supported languages and variations
| Language | Notes |
|---|---|
| French | Uses être/avoir auxiliaries; participles agree in gender/number. Elisions (j’ai) handled via full_form. |
| German | Has Infinitiv I/II and Partizip I/II; modeled with variant and type_key. |
| Turkish | Negative forms stored via negative flag. No participle gender/number agreement. |
| English & Romance (ES, IT, PT, RO) | Straightforward conjugation grids; optional clitic attachment handled in surface text. |
| (Future extension) | Model supports Slavic aspect, Arabic gendered conjugations, Asian non-finite constructions through later features columns. |
2. Data Model Overview
The verb system is decomposed into five primary entities plus two link tables for sentence matching.
2.1 Entities and relationships
verb_lemmas
├── has_many infinitives
├── has_many verbals
└── has_many conjugations ── belongs_to tenses
sentences
├── has_many sentence_conjugations ── belongs_to conjugations
└── has_many sentence_infinitives ─── belongs_to infinitives
3. Technical Implementation
3.1 verb_lemmas
Stores one lemma per language.
| Column | Type | Description |
|---|---|---|
language |
CHAR(2) | ISO language code (fr, de, tr, …) |
lemma |
string | Dictionary form |
common |
boolean | Whether frequently used |
regular_overall |
boolean | Global regularity (optional) |
english_translation |
string | Optional gloss |
Indexes: (language, lemma) unique
Associations: has_many :infinitives, :verbals, :conjugations
3.2 tenses
Defines each language’s moods and tenses.
| Column | Type | Example |
|---|---|---|
language |
CHAR(2) | fr |
mood |
string | Indicatif |
tense_name |
string | Passé composé |
common_tense |
boolean | Commonly used tense |
Unique (language, mood, tense_name) ensures canonical labels.
3.3 infinitives
Per-lemma infinitive forms, allowing multiple variants.
| Column | Description |
|---|---|
form |
Text of the infinitive (e.g. aller) |
search_form |
Stripped form for matching |
variant |
default, perfect, etc. |
sentences_matched |
Boolean; has been matched to sentences |
language, lemma |
Cached from parent |
3.4 verbals
All participles and gerunds.
| Column | Description |
|---|---|
type_key |
e.g. present_participle, past_participle, partizip_ii |
form |
Surface form (e.g. allé) |
gender, number |
For agreement forms (m/f, sg/pl) |
language, lemma |
Cached |
Examples for aller:
allé (m.sg), allée (f.sg), allés (m.pl), allées (f.pl)
3.5 conjugations
Each finite verb form (1–6 persons).
| Column | Description |
|---|---|
verb_lemma_id, tense_id |
Foreign keys |
person_seq |
1–6 (language-agnostic order) |
person_label |
je, tu, il, nous, … |
form |
Bare conjugated form (ai) |
full_form |
Final surface string (j'ai) |
search_form |
Stripped form for matching (j ai) |
regular |
Boolean; per-form irregularity |
negative |
Boolean (for Turkish, optional) |
sentences_matched |
Boolean; has been matched to sentences |
language, lemma, mood, tense_name |
Cached for fast queries |
Indexes:
(verb_lemma_id, tense_id, person_seq)unique(language, lemma)for lemma lookups(language, sentences_matched)for batch processing(search_form)for matching
3.6 Sentence linking tables
| Table | Purpose |
|---|---|
sentence_conjugations |
Links sentences to specific conjugations |
sentence_infinitives |
Links sentences to infinitives |
sentence_conjugations caches: language, lemma, mood, tense_name, person_seq, person_label, conj_form
sentence_infinitives caches: language, lemma
These enable fast queries without joins. See sentence_matching.md for details on the matching system.
4. Model Layer (Rails)
4.1 Core verb models
class VerbLemma < ApplicationRecord
has_many :infinitives, :verbals, :conjugations
validates :language, presence: true, length: {is: 2}
validates :lemma, presence: true
end
class Tense < ApplicationRecord
has_many :conjugations
validates :language, presence: true, length: {is: 2}
validates :mood, :tense_name, presence: true
end
class Infinitive < ApplicationRecord
belongs_to :verb_lemma
has_many :sentence_infinitives
has_many :sentences, through: :sentence_infinitives
before_validation :cache_parent_fields
before_save :set_search_form # Strips special chars for matching
end
class Verbal < ApplicationRecord
belongs_to :verb_lemma
validates :type_key, :form, presence: true
validates :gender, inclusion: {in: %w[m f n], allow_nil: true}
validates :number, inclusion: {in: %w[sg pl], allow_nil: true}
before_validation :cache_parent_fields
end
class Conjugation < ApplicationRecord
belongs_to :verb_lemma
belongs_to :tense
has_many :sentence_conjugations
has_many :sentences, through: :sentence_conjugations
validates :person_seq, inclusion: {in: 1..6}
validates :full_form, presence: true
before_validation :cache_parent_fields
before_save :set_search_form # Strips special chars for matching
end
4.2 Sentence linking
class Sentence < ApplicationRecord
has_many :sentence_conjugations
has_many :sentence_infinitives
has_many :conjugations, through: :sentence_conjugations
has_many :infinitives, through: :sentence_infinitives
end
class SentenceConjugation < ApplicationRecord
belongs_to :sentence
belongs_to :conjugation
before_validation :cache_fields # Caches denormalized lookup fields
end
class SentenceInfinitive < ApplicationRecord
belongs_to :sentence
belongs_to :infinitive
before_validation :cache_fields # Caches denormalized lookup fields
end
5. Example: French aller
| Mood | Tense | Person | form |
full_form |
|---|---|---|---|---|
| Indicatif | Présent | je | vais | je vais |
| Indicatif | Imparfait | je | allais | j’allais |
| Indicatif | Passé composé | je | suis | je suis allé(e) (via participle) |
| Subjonctif | Présent | je | aille | j’aille |
Participles (verbals):
| type_key | gender | number | form |
|---|---|---|---|
| past_participle | m | sg | allé |
| past_participle | f | sg | allée |
| past_participle | m | pl | allés |
| past_participle | f | pl | allées |
6. Query patterns
# All conjugations for a verb
Conjugation.for_lemma('fr', 'aller').order(:mood, :tense_name, :person_seq)
# All participles for a verb
Verbal.where(language: 'fr', lemma: 'aller', type_key: 'past_participle')
# Find sentences using a verb in a specific tense
SentenceConjugation.where(language: 'fr', lemma: 'aller', mood: 'Indicatif', tense_name: 'Présent')
# Find all conjugations in a sentence
sentence.conjugations # via has_many :through
# Find all sentences containing a conjugation
conjugation.sentences # via has_many :through
7. Performance
Cached fields (language, lemma, mood, tense_name) on conjugations enable single-table queries without joins. The search_form field pre-strips special characters for efficient text matching.
8. Future Extensions
| Feature | Where to add |
|---|---|
| Aspect pairs (Slavic) | verb_lemmas.aspect_class, partner_verb_id |
| Politeness / formality | conjugations.features JSONB |
| Gendered conjugations (Arabic/Hindi) | conjugations.features or additional slot table |
| Non-inflecting languages | allow person_seq = NULL |
| Audio & phonetic data | separate pronunciations table |
9. Sentence Matching
The system automatically links verb conjugations and infinitives to example sentences using PostgreSQL full-text search. The matching system:
- Uses GIN indexes for fast, language-specific matching
- Processes conjugations and infinitives to find containing sentences
- Tracks processing status with
sentences_matchedflags - Supports batch processing via rake tasks and async background jobs
- Only processes sentences ≤80 characters for performance
See sentence_matching.md for complete documentation of the matching system, including:
- Detailed matching algorithm
- Background jobs and rake tasks
- Query patterns and performance characteristics
10. Summary
This architecture cleanly separates lemmas, infinitives, participles, and finite forms while supporting compound tenses, gendered participles, and efficient sentence linking. Denormalized fields enable fast queries without joins, and the system is ready to load large datasets from Verbix, Wiktionary, or custom corpora.