Full leṬ implementation: coverage gaps beyond Phase 1
Status
Issue #236 PR for leṬ Phase 1 fixes:
- pit/Nit fork for the leṬ pratyaya (3.4.94 + 3.4.94.v1 → 3.4.100)
- mip → ni substitution for 1sg (3.4.89 under leṬ)
- Vārttika 3.4.98.v1 for bare-ā 1sg (bhavā, kṛṇavā, bharā)
- Suppression of bhavān 1sg per Kāśikā on 3.4.103
That fixes the current implementation of vidyut leṭ. This issue scopes the remaining work to fix the stem machinery for non–class-1 dhātus.
Corpus validation
Validated against 826 present-stem subjunctive forms in Hellwig's morpho-lexical Rigveda annotation (filtered to tense_mode = "Present conjunctive (subjunctive)").
Coverage by gaṇa
| Gaṇa |
Matched |
Missed |
Total |
Match% |
| 1 Bhvādi |
127 |
195 |
322 |
39.4% |
| 2 Adādi |
17 |
75 |
92 |
18.5% |
| 3 Juhotyādi |
2 |
23 |
25 |
8.0% |
| 4 Divādi |
5 |
16 |
21 |
23.8% |
| 5 Svādi |
0 |
64 |
64 |
0.0% |
| 6 Tudādi |
9 |
14 |
23 |
39.1% |
| 7 Rudhādi |
0 |
0 |
0 |
— |
| 8 Tanādi |
0 |
1 |
1 |
0.0% |
| 9 Kryādi |
0 |
0 |
0 |
— |
| 10 Curādi |
17 |
6 |
23 |
73.9% |
| Total |
177 |
394 |
571 |
31.0% |
Classes 7 and 9 have 0 testable forms — their RV-attested lemmas fell into the matcher-gap pile (nasal-infix complications in lemma matching).
Identified bug categories
Bug A — Class 5 (Svādi) Snu vikaraṇa doesn't apply under leṬ (0% match, 64 forms).
Expected: aś + leṬ → aśnav- + a + t → aśnavat (the -av- is from class-5 Snu vikaraṇa with guṇa o → av before vowel).
Vidyut produces: aSnAt / aSnAti — no -nu-/-nav-.
Largest single bug class. Fixing this alone lifts testable match rate from 31% to ~42%.
Affected sample roots: aś (29 forms), śru (23), ci, cinu, su. Examples:
1.1.3.1 expected=aSnavat got=[aSnAd, aSnAt, aSnAti, aSnuvAte]
1.41.4.1 expected=SfRavat got=[SfRuvAd, SfRuvAt, SfRuvAti]
Bug B — Class 2 (Adādi) wrong agama choice (18.5% match, ~50 misses).
The heuristic in tin_pratyaya.rs:126:
let agama = if uses_sip_vikarana(p, i_dhatu) {
A::aw // short a
} else {
A::Aw // long A
};
For class 2 (root-class, no Sap), uses_sip_vikarana returns false → vidyut picks āṬ (long Ā). Corpus shows aṬ (short a) for these dhātus.
Example: as + leṬ + tip → corpus asat, vidyut asAt.
The long ā in class 1 bhavāti comes from a + a sandhi (7.3.101), not from the agama being āṬ. So aṬ should be the default, and āṬ used in narrower contexts
(likely ātmanepada-specific per Pāṇinian convention).
Bug C — Class 3 (Juhotyādi) reduplicated stem (8% match, 23 misses).
Vidyut produces daDAn / daDAnti instead of corpus daDat / daDan for dhā. The reduplication fires but the agama/grade choice is wrong for class 3.
Example: dhā + leṬ + 3pl → corpus daDan, vidyut daDAn / daDAnti.
Bug D — Stem-substitution edge cases (~30 misses across class 1).
Some lemmas have dhātu substitution rules that should fire under leṬ but don't, or fire incorrectly:
- brū: corpus bravAvahE (1du atm), vidyut produces vacAva / vacAvaH / vacAvahe — vidyut applied the vac-substitution where leṬ should preserve brū-.
- han: corpus hanaH (2sg paras), vidyut produces GnAH / hanAsi — Gn-substitution wrongly active.
Bug E — Matcher / dhātupāṭha coverage gap (255 forms, 30.9% of total).
Corpus lemmas like mAday, coday, kalpay, sUday (causatives), SoSuc, dIdI, carkar, jaNGan, jargur (intensives), Sravasy, AvivAs (denominatives) aren't basic
dhātus — they're derived stems. The validator currently skips these; they need a separate entrypoint that builds the derived stem first, then runs leṬ on it. Not
blocking — out of scope for the gaṇa-coverage work.
Reproduce
use vidyut_prakriya::args::*;
use vidyut_prakriya::Vyakarana;
fn main() {
let v = Vyakarana::new();
for (label, root, gana, p, n, expected) in [
// Class 5 bug
("aś 3sg", "aSU~\\", Gana::Svadi, Purusha::Prathama, Vacana::Eka, "aSnavat"),
// Class 2 bug
("as 3sg", "asa~", Gana::Adadi, Purusha::Prathama, Vacana::Eka, "asat"),
// Class 3 bug
("dhā 3pl", "quDA\\Y", Gana::Juhotyadi, Purusha::Prathama, Vacana::Bahu, "daDan"),
] {
let dhatu = Dhatu::mula(Slp1String::from(root).unwrap(), gana);
let tin = Tinanta::builder()
.dhatu(dhatu).lakara(Lakara::Let)
.prayoga(Prayoga::Kartari).purusha(p).vacana(n)
.build().unwrap();
let got: Vec<String> = v.derive_tinantas(&tin).iter().map(|x| x.text()).collect();
let ok = got.iter().any(|x| x == expected);
println!("{}: expected={} got=[{}] {}",
label, expected, got.join(", "), if ok { "ok" } else { "MISS" });
}
}
Regression baseline
vidyut-prakriya/examples/validate_let_corpus.rs runs the full 826-form validation and prints per-gaṇa coverage. Use as a regression test for any leṬ-related work. Coverage pct should monotonically improve.
Suggested phasing
- Phase 1.A — Class 5 (Snu) vikaraṇa under leṬ. Verify the existing class-5 vikaraṇa code is invoked in the leṬ pipeline. Largest single improvement (+64 forms, ~11pp testable lift).
- Phase 1.B — Class 2 agama choice. Invert the uses_sip_vikarana heuristic; default to aṬ, use āṬ only in specifically-required contexts. Verify against full bhū / kṛ paradigms in kashika_3_4.rs first.
- Phase 1.C — Class 3 reduplicated stem under leṬ. Audit the dvitva pipeline interaction with leṬ.
- Phase 1.D — Stem-substitution audit. Trace why brū → vac, han → ghn, etc. fire under leṬ when they shouldn't (or fire incorrectly).
- Phase 1.E — Derived-stem entrypoint (causatives, intensives, denominatives under leṬ). Lower priority; affects ~30% of corpus but not blocking for basic leṬ correctness.
Each is independently shippable on its own branch off main.
Sūtras and vārttikas in scope
3.4.94, 3.4.94.v1 (Phase 1), 3.4.97, 3.4.98, 3.4.98.v1 (Phase 1), 3.4.99, 3.4.100, 3.4.103 (Kāśikā: lakāra-derived Nit-tva); Phase 1.A–D additionally touch:
3.1.73 (Snu), 2.4.72/2.4.75 (Ślu/luk), 6.4.110 (kṛ → kur), 7.3.84 (guṇa), 7.3.101 (ato dīrgho yañi), 8.2.23, plus the lakāra-stem dispatch in
vikarana.rs:623-634.
Notes
Validation uses Hellwig et al.'s annotated Rigveda (LREC 2018).
Validator script to be added: vidyut-prakriya/examples/validate_let_corpus.rs
Source TSV for all RV forms to be added: leT-rigveda.tsv
Full leṬ implementation: coverage gaps beyond Phase 1
Status
Issue #236 PR for leṬ Phase 1 fixes:
That fixes the current implementation of vidyut leṭ. This issue scopes the remaining work to fix the stem machinery for non–class-1 dhātus.
Corpus validation
Validated against 826 present-stem subjunctive forms in Hellwig's morpho-lexical Rigveda annotation (filtered to tense_mode = "Present conjunctive (subjunctive)").
Coverage by gaṇa
Classes 7 and 9 have 0 testable forms — their RV-attested lemmas fell into the matcher-gap pile (nasal-infix complications in lemma matching).
Identified bug categories
Bug A — Class 5 (Svādi) Snu vikaraṇa doesn't apply under leṬ (0% match, 64 forms).
Expected:
aś + leṬ → aśnav- + a + t → aśnavat(the-av-is from class-5Snuvikaraṇa with guṇao → avbefore vowel).Vidyut produces:
aSnAt / aSnAti— no-nu-/-nav-.Largest single bug class. Fixing this alone lifts testable match rate from 31% to ~42%.
Affected sample roots: aś (29 forms), śru (23), ci, cinu, su. Examples:
1.1.3.1 expected=aSnavat got=[aSnAd, aSnAt, aSnAti, aSnuvAte]1.41.4.1 expected=SfRavat got=[SfRuvAd, SfRuvAt, SfRuvAti]Bug B — Class 2 (Adādi) wrong agama choice (18.5% match, ~50 misses).
The heuristic in
tin_pratyaya.rs:126:For class 2 (root-class, no Sap), uses_sip_vikarana returns false → vidyut picks āṬ (long Ā). Corpus shows aṬ (short a) for these dhātus.
Example: as + leṬ + tip → corpus asat, vidyut asAt.
The long ā in class 1 bhavāti comes from a + a sandhi (7.3.101), not from the agama being āṬ. So aṬ should be the default, and āṬ used in narrower contexts
(likely ātmanepada-specific per Pāṇinian convention).
Bug C — Class 3 (Juhotyādi) reduplicated stem (8% match, 23 misses).
Vidyut produces daDAn / daDAnti instead of corpus daDat / daDan for dhā. The reduplication fires but the agama/grade choice is wrong for class 3.
Example: dhā + leṬ + 3pl → corpus daDan, vidyut daDAn / daDAnti.
Bug D — Stem-substitution edge cases (~30 misses across class 1).
Some lemmas have dhātu substitution rules that should fire under leṬ but don't, or fire incorrectly:
Bug E — Matcher / dhātupāṭha coverage gap (255 forms, 30.9% of total).
Corpus lemmas like mAday, coday, kalpay, sUday (causatives), SoSuc, dIdI, carkar, jaNGan, jargur (intensives), Sravasy, AvivAs (denominatives) aren't basic
dhātus — they're derived stems. The validator currently skips these; they need a separate entrypoint that builds the derived stem first, then runs leṬ on it. Not
blocking — out of scope for the gaṇa-coverage work.
Reproduce
Regression baseline
vidyut-prakriya/examples/validate_let_corpus.rs runs the full 826-form validation and prints per-gaṇa coverage. Use as a regression test for any leṬ-related work. Coverage pct should monotonically improve.
Suggested phasing
Each is independently shippable on its own branch off main.
Sūtras and vārttikas in scope
3.4.94, 3.4.94.v1 (Phase 1), 3.4.97, 3.4.98, 3.4.98.v1 (Phase 1), 3.4.99, 3.4.100, 3.4.103 (Kāśikā: lakāra-derived Nit-tva); Phase 1.A–D additionally touch:
3.1.73 (Snu), 2.4.72/2.4.75 (Ślu/luk), 6.4.110 (kṛ → kur), 7.3.84 (guṇa), 7.3.101 (ato dīrgho yañi), 8.2.23, plus the lakāra-stem dispatch in
vikarana.rs:623-634.
Notes
Validation uses Hellwig et al.'s annotated Rigveda (LREC 2018).
Validator script to be added:
vidyut-prakriya/examples/validate_let_corpus.rsSource TSV for all RV forms to be added:
leT-rigveda.tsv