Skip to content

A complete implementation of लेट् present class beyond phase 1 #239

Description

@yajnadevam

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

  1. 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).
  2. 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.
  3. Phase 1.C — Class 3 reduplicated stem under leṬ. Audit the dvitva pipeline interaction with leṬ.
  4. Phase 1.D — Stem-substitution audit. Trace why brū → vac, han → ghn, etc. fire under leṬ when they shouldn't (or fire incorrectly).
  5. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions