From 5d6cd17072e6a35259e3fd5e1e5e538339ad32dd Mon Sep 17 00:00:00 2001 From: Arun Prasad Date: Mon, 23 Dec 2024 17:33:45 -0800 Subject: [PATCH] [prakriya] Add better support for kvasu~ In addition: - Simplify binaries that create and test snapshots. - Rename `upadesha` to `aupadeshika` in various functions. --- vidyut-prakriya/Makefile | 98 ++---- .../examples/create_tinantas_babylon.rs | 8 +- vidyut-prakriya/examples/print_prakriyas.rs | 5 +- vidyut-prakriya/src/angasya.rs | 57 +++- vidyut-prakriya/src/angasya/abhyasasya.rs | 5 +- vidyut-prakriya/src/angasya/asiddhavat.rs | 57 ++-- vidyut-prakriya/src/ashtadhyayi.rs | 2 +- vidyut-prakriya/src/bin/create_dhatus.rs | 83 ----- vidyut-prakriya/src/bin/create_krdantas.rs | 110 ------- vidyut-prakriya/src/bin/create_test_file.rs | 95 ------ vidyut-prakriya/src/bin/create_test_files.rs | 310 ++++++++++++++++++ vidyut-prakriya/src/bin/create_tinantas.rs | 150 --------- vidyut-prakriya/src/bin/test_results.rs | 143 ++++---- vidyut-prakriya/src/dhatupatha.rs | 18 +- vidyut-prakriya/src/it_agama.rs | 74 ++--- vidyut-prakriya/src/krt/basic.rs | 2 +- vidyut-prakriya/src/sanadi.rs | 6 +- .../tests/integration/kashika_3_2.rs | 1 - .../tests/integration/kashika_6_4.rs | 2 - .../tests/integration/kashika_7_2.rs | 68 +++- .../tests/integration/regressions.rs | 6 + 21 files changed, 621 insertions(+), 679 deletions(-) delete mode 100644 vidyut-prakriya/src/bin/create_dhatus.rs delete mode 100644 vidyut-prakriya/src/bin/create_krdantas.rs delete mode 100644 vidyut-prakriya/src/bin/create_test_file.rs create mode 100644 vidyut-prakriya/src/bin/create_test_files.rs delete mode 100644 vidyut-prakriya/src/bin/create_tinantas.rs diff --git a/vidyut-prakriya/Makefile b/vidyut-prakriya/Makefile index 4a32fd9..05d837d 100644 --- a/vidyut-prakriya/Makefile +++ b/vidyut-prakriya/Makefile @@ -13,36 +13,10 @@ coverage: # Integration tests # ~~~~~~~~~~~~~~~~~ -# Generates all tinantas supported by the program and writes them to disk. -create_test_files: create_tinantas create_krdantas create_dhatus - -create_tinantas: - cargo build --release --bin create_tinantas - ../target/release/create_tinantas --prayoga kartari > test-files/tinantas-basic-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi Ric > test-files/tinantas-nic-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi san > test-files/tinantas-san-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi yaN > test-files/tinantas-yan-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi yaNluk > test-files/tinantas-yan-luk-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi san,Ric > test-files/tinantas-san-nic-kartari.csv - ../target/release/create_tinantas --prayoga kartari --sanadi Ric,san > test-files/tinantas-nic-san-kartari.csv - ../target/release/create_tinantas --prayoga karmani > test-files/tinantas-basic-karmani.csv - ../target/release/create_tinantas --prayoga karmani --sanadi Ric > test-files/tinantas-nic-karmani.csv - ../target/release/create_tinantas --prayoga karmani --sanadi san > test-files/tinantas-san-karmani.csv - ../target/release/create_tinantas --prayoga karmani --sanadi yaN > test-files/tinantas-yan-karmani.csv - ../target/release/create_tinantas --prayoga karmani --sanadi san,Ric > test-files/tinantas-san-nic-karmani.csv - ../target/release/create_tinantas --prayoga karmani --sanadi Ric,san > test-files/tinantas-nic-san-karmani.csv - -create_krdantas: - cargo build --release --bin create_krdantas - ../target/release/create_krdantas > test-files/krdantas-basic.csv - ../target/release/create_krdantas --sanadi Ric > test-files/krdantas-nic.csv - ../target/release/create_krdantas --sanadi san > test-files/krdantas-san.csv - ../target/release/create_krdantas --sanadi yaN > test-files/krdantas-yan.csv - ../target/release/create_krdantas --sanadi yaNluk > test-files/krdantas-yan-luk.csv - -create_dhatus: - cargo build --release --bin create_dhatus - ../target/release/create_dhatus > test-files/dhatus.csv +# Generates all tinantas, krdantas, and dhatus supported by the program and writes them to disk. +create_test_files: + cargo build --release --bin create_test_files + ../target/release/create_test_files --output-dir test-files # Runs a full evaluation over all forms generated by vidyut-prakriya. `hash` is # the SHA-256 hash of the test file. We use `hash` to verify test file @@ -56,86 +30,62 @@ test_tinantas: cargo build --release --bin test_results ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-basic-kartari.csv \ - --hash "abe62f683a0c3e8cec8f3536e7ea0234ea8af68d6cf7b49e209597eb8f855476" + --test-cases test-files/tinantas-basic.csv \ + --hash "b5af09ca0580ca14484f75618e7515b29c16054111092b5cc550accb244e1e28" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-nic-kartari.csv \ - --hash "9bfa0fd1eb7d49b4cdf15d50d5c1dbc053dfafbe1a4da673ec41a66fdfa2fc9a" + --test-cases test-files/tinantas-nic.csv \ + --hash "d8cf36e3354075b014761ecb39180655f50498c032fd262e0f9f3d7e0558ab95" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-san-kartari.csv \ - --hash "d3cf5ec44079bceb409696598b68bf3f57b604d48e018a3360dcb00ff5c04fb8" + --test-cases test-files/tinantas-san.csv \ + --hash "bb44e1642942c47e8d4fe09cefdab4f005c0b2653e4dc72f847b9cbf33ac9694" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-yan-kartari.csv \ - --hash "1b7d63e8da81ae220a9787b77588d021daeca9696fd58e6ed463bc3e8ac1e8e4" + --test-cases test-files/tinantas-yan.csv \ + --hash "06b136ed48064c00eed2e6320ebdc8b086a0e93bd3dedbb375a3d680f23a14a0" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-yan-luk-kartari.csv \ - --hash "3256297c907d762d0809d38168172fa151e168187542031b09ef7bf460bc4c28" + --test-cases test-files/tinantas-yan-luk.csv \ + --hash "7cd36afdcd38beef9bd66db40e41a080e2db2aea794f6daa06e926096ae48104" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-san-nic-kartari.csv \ - --hash "18d96165568b2fcf470c15aace41454010f548ec4559cdac24b1f1fd209af340" + --test-cases test-files/tinantas-san-nic.csv \ + --hash "c1f561806c1639926621dcabf69a31285b99f00c80e5fa57e3a4a4afa9310499" ../target/release/test_results \ --data-type tinanta \ - --test-cases test-files/tinantas-nic-san-kartari.csv \ - --hash "e396839ebf339561d0dcaf87b695d1675ac113629d0a0becbe695a1ac77926a5" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-basic-karmani.csv \ - --hash "b8540f8aca8eb202fb1cb949ebff90332df7658a2bf94f12542b59196ed80cc8" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-nic-karmani.csv \ - --hash "afb4807a99475dd7480c41f0a4baf59d8bdce1c65a8e5340fcaaf189f190b110" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-san-karmani.csv \ - --hash "9d40a83d67a79556a8c2491430ab5f5884b8a1a89ed64786a45a987637cd7c3f" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-yan-karmani.csv \ - --hash "9311a5467efadbf224b4f9dc6b981eb3845118cc187adeecc957b41c1f3acd78" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-san-nic-karmani.csv \ - --hash "ea21729c7a4ceb7fcc2c66af097a0f053daf06b0e36c9324b8cbd34d82f9fbe7" - ../target/release/test_results \ - --data-type tinanta \ - --test-cases test-files/tinantas-nic-san-karmani.csv \ - --hash "4845c125a3acab60fe9189960ace4402cd244db527bd16f7238930a39c547ba8" + --test-cases test-files/tinantas-nic-san.csv \ + --hash "8e102d104eea6483e82ad2be8a8005716586ce4b0d2aa447fc20ada0f2882158" test_krdantas: cargo build --release --bin test_results ../target/release/test_results \ --data-type krdanta \ --test-cases test-files/krdantas-basic.csv \ - --hash "540f1595ec0ac3957cc00dd236dd6af67307b26cc45312b13e2a164ddfaeb89d" + --hash "4ff8687f9a2c36eddd58a23637983ec87319ed5c4616aabe686d0e2b91a558b2" ../target/release/test_results \ --data-type krdanta \ --test-cases test-files/krdantas-nic.csv \ - --hash "2d912641df671b2f76920efc0ed31d25d8d13a4dffb74afa471351df6ae0bc31" + --hash "2acacdc4000bd02a58905ef431a65d9d3666296ef9ed9ab0571935f7586e12b9" ../target/release/test_results \ --data-type krdanta \ --test-cases test-files/krdantas-san.csv \ - --hash "4870af19eb0e42847f8f1d532e66d71312a702454aee1e47275a953cd56fe8e6" + --hash "294ecfdf8ad81c0164c466b423a3f088f01c7de7894d5efb5fadb74294bf05ff" ../target/release/test_results \ --data-type krdanta \ --test-cases test-files/krdantas-yan.csv \ - --hash "2af8e18fcfd0952679fa69b5011c3b40cdca83b6a899b453d62c6d7a9ebc54a5" + --hash "51d9faea44e8295a8e942a0bab8d8f66d4412ff9767c70d24be4408648b7781f" ../target/release/test_results \ --data-type krdanta \ --test-cases test-files/krdantas-yan-luk.csv \ - --hash "5399c6a8f2d13ba00b0249ee9b9359ef4c6f4f075e6ab459c97b591cecc71545" + --hash "7e28699c1de0739c567b6007cad110487f59a8bbb3ecad31cc51b990840b6a08" test_dhatus: cargo build --release --bin test_results ../target/release/test_results \ --data-type dhatu \ --test-cases test-files/dhatus.csv \ - --hash "793e576b1b24e4982a8f51e4789927786eb17eabbeb0fd5c29dc77d89a8eb4b2" + --hash "0b91b392570b0e08aa4d0373f45f7c28c00abcdb8fde05bd1871d7da26d3efa1" test_subantas: diff --git a/vidyut-prakriya/examples/create_tinantas_babylon.rs b/vidyut-prakriya/examples/create_tinantas_babylon.rs index a6e7b51..f3f37e9 100644 --- a/vidyut-prakriya/examples/create_tinantas_babylon.rs +++ b/vidyut-prakriya/examples/create_tinantas_babylon.rs @@ -149,8 +149,8 @@ fn create_entry( let tinanta = Tinanta::builder() .dhatu(dhatu) .prayoga(prayoga) - .purusha(*purusha) - .vacana(*vacana) + .purusha(purusha) + .vacana(vacana) .pada(pada) .lakara(lakara) .build() @@ -184,7 +184,7 @@ fn create_entry( } // Don't print for last purusha. - if *purusha != Purusha::Uttama { + if purusha != Purusha::Uttama { html_row += "
---" } } @@ -227,7 +227,7 @@ fn run(dp: Dhatupatha, args: Args) { for dhatu_entry in dp { for lakara in Lakara::iter() { for pada in &[DhatuPada::Parasmai, DhatuPada::Atmane] { - let entry = create_entry(&v, &dhatu_entry, args.sanadi, prayoga, *pada, *lakara); + let entry = create_entry(&v, &dhatu_entry, args.sanadi, prayoga, *pada, lakara); if let Some(e) = entry { print!("{}\n{}\n\n", e.search_row, e.html_row); } diff --git a/vidyut-prakriya/examples/print_prakriyas.rs b/vidyut-prakriya/examples/print_prakriyas.rs index 7a661ae..754e3e1 100644 --- a/vidyut-prakriya/examples/print_prakriyas.rs +++ b/vidyut-prakriya/examples/print_prakriyas.rs @@ -44,7 +44,7 @@ fn main() { // Create a basic dhatu with `Dhatu::mula` // // For supported dhatus, see `dhatupatha.tsv`. - let bhu = Dhatu::mula("BU", Gana::Bhvadi); + let bhu = Dhatu::mula(Slp1String::from("BU").expect("ok"), Gana::Bhvadi); let args = Tinanta::builder() .dhatu(bhu) @@ -58,7 +58,8 @@ fn main() { print_prakriyas(&prakriyas); // Create a sannanta dhatu with `with_sanadi`. - let jijnasa = Dhatu::mula("jYA\\", Gana::Kryadi).with_sanadi(&[Sanadi::san]); + let jijnasa = Dhatu::mula(Slp1String::from("jYA\\").expect("ok"), Gana::Kryadi) + .with_sanadi(&[Sanadi::san]); let args = Tinanta::builder() .dhatu(jijnasa) diff --git a/vidyut-prakriya/src/angasya.rs b/vidyut-prakriya/src/angasya.rs index a5b0afd..82986c2 100644 --- a/vidyut-prakriya/src/angasya.rs +++ b/vidyut-prakriya/src/angasya.rs @@ -34,6 +34,7 @@ use crate::core::char_view::IndexPrakriya; use crate::core::operators as op; use crate::core::{Morph, Prakriya, PrakriyaTag as PT, Rule, Rule::Varttika, Tag as T, Term}; use crate::dhatu_gana as gana; +use crate::it_agama; use crate::it_samjna; use crate::sounds as al; use crate::sounds::{s, Set}; @@ -408,6 +409,7 @@ fn try_change_cu_to_ku(p: &mut Prakriya, i: usize) -> Option<()> { if anga.is_abhyasta() { p.run_at("7.3.55", i, op::adi("G")); } else if n.last().has_tag_in(&[T::Yit, T::Rit]) || anga.has_text("hn") { + // GAtaka, Gnanti, ... p.run_at("7.3.54", i, op::adi("G")); } } else if anga.is_u(Au::hi) && anga.is_abhyasta() && !n.last().is(V::caN) { @@ -1393,7 +1395,12 @@ pub fn run_before_dvitva(p: &mut Prakriya, is_lun: bool, skip_at_agama: bool) -> for i in 0..p.len() { // Must run before asiddhavat for sTA + kta -> sTita try_anga_changes_before_t(p, i); - asiddhavat::run_after_guna(p, i); + } + + if !p.terms().iter().any(|t| t.has_u("kvasu~")) { + for i in 0..p.len() { + run_after_it_agama_karya(p, i); + } } // Tries adding tuk-Agama for krt-pratyayas that are pit. @@ -1492,31 +1499,67 @@ pub fn run_before_dvitva(p: &mut Prakriya, is_lun: bool, skip_at_agama: bool) -> Some(()) } +/// Runs rules that should apply only after we have resolved it-Agama. +/// +/// Examples: +/// - Rules that condition on the first sound of a pratyaya. +/// - Rules that condition specifically on iw-Agama. +pub fn run_after_it_agama_karya(p: &mut Prakriya, i: usize) -> Option<()> { + asiddhavat::run_after_guna(p, i); + + Some(()) +} + +/// Runs rules that should apply only after we have resolved both iw-Agama and dvitva. +/// +/// Examples: +/// - Rules that delete 'A' of dhatu if iw-Agama follows. (Should be done after dvitva.) +pub fn run_after_it_agama_karya_and_dvitva_karya(p: &mut Prakriya, i: usize) -> Option<()> { + asiddhavat::run_after_it_agama_karya_and_dvitva_karya(p, i); + try_change_cu_to_ku(p, i); + asiddhavat::run_for_kniti_ardhadhatuke_after_dvitva(p, i); + Some(()) +} + pub fn run_after_dvitva(p: &mut Prakriya) -> Option<()> { - subanta::run(p); + if !p.terms().iter().any(|t| t.has_u("kvasu~")) { + for i in 0..p.len() { + run_after_it_agama_karya_and_dvitva_karya(p, i); + } + } for i in 0..p.len() { - asiddhavat::run_after_dvitva(p, i); + asiddhavat::run_for_kniti_ardhadhatuke_after_dvitva(p, i); + asiddhavat::try_run_kniti_for_dhatu(p, i); } // Must come before asiddhavat rule 6.4.78 (e.g. "iyarti", ekahalmadhya) abhyasasya::run(p); + for i in 0..p.len() { + asiddhavat::try_et_adesha_and_abhyasa_lopa_for_lit(p, i); + } + // ADDED for ciccheda, etc. try_add_tuk_agama(p); for i in 0..p.len() { unknown(p, i); try_tas_asti_lopa(p, i); - try_didhi_vevi_lopa(p, i); } - for i in 0..p.terms().len() { - try_change_cu_to_ku(p, i); + abhyasasya::run_for_sani_or_cani(p); + + for i in 0..p.len() { + let finished = it_agama::run_for_kvasu_pratyaya(p, i); + if finished.unwrap_or(false) { + run_after_it_agama_karya(p, i); + run_after_it_agama_karya_and_dvitva_karya(p, i); + } } - abhyasasya::run_for_sani_or_cani(p); + subanta::run(p); for index in 0..p.len() { try_ato_dirgha(p, index); diff --git a/vidyut-prakriya/src/angasya/abhyasasya.rs b/vidyut-prakriya/src/angasya/abhyasasya.rs index 614dd6f..2909365 100644 --- a/vidyut-prakriya/src/angasya/abhyasasya.rs +++ b/vidyut-prakriya/src/angasya/abhyasasya.rs @@ -312,13 +312,14 @@ fn try_rules_for_lit(p: &mut Prakriya, i: usize) -> Option<()> { let abhyasa = p.get(i)?; let dhatu = p.get(i_dhatu)?; - let last = p.terms().last()?; + let i_n = p.find_next_where(i_dhatu, |t| t.is_pratyaya())?; + let next = p.get(i_n)?; fn add_nut_agama(rule: impl Into, p: &mut Prakriya, i: usize) { op::insert_before(rule.into(), p, i, A::nuw); } - if !last.has_lakara(Lit) { + if !next.has_lakara(Lit) { return None; } diff --git a/vidyut-prakriya/src/angasya/asiddhavat.rs b/vidyut-prakriya/src/angasya/asiddhavat.rs index 0ddc004..2092c97 100644 --- a/vidyut-prakriya/src/angasya/asiddhavat.rs +++ b/vidyut-prakriya/src/angasya/asiddhavat.rs @@ -159,7 +159,7 @@ pub fn try_cinvat_for_bhave_and_karmani_prayoga(p: &mut Prakriya) -> Option<()> /// Runs rules conditioned on a following knit ArdhadhAtuka suffix. /// /// Constraints: must run after dvitva. -fn run_for_kniti_ardhadhatuke_after_dvitva(p: &mut Prakriya, i: usize) -> Option<()> { +pub fn run_for_kniti_ardhadhatuke_after_dvitva(p: &mut Prakriya, i: usize) -> Option<()> { let dhatu = p.get(i)?; let i_n = p.find_next_where(i, |t| !t.is_lupta())?; let n = p.pratyaya(i_n)?; @@ -177,10 +177,8 @@ fn run_for_kniti_ardhadhatuke_after_dvitva(p: &mut Prakriya, i: usize) -> Option Some(()) } -/// Runs rules conditioned on a following `kit` or `Nit` suffix. -/// -/// (6.4.98 - 6.4.126) -fn try_run_kniti_for_dhatu(p: &mut Prakriya, i: usize) -> Option<()> { +/// Runs rules that should be applied only after it-Agama has been decided. +pub fn run_after_it_agama_karya_and_dvitva_karya(p: &mut Prakriya, i: usize) -> Option<()> { let anga = p.get(i)?; let j = p.next_not_empty(i)?; let n = p.pratyaya(j)?; @@ -189,20 +187,40 @@ fn try_run_kniti_for_dhatu(p: &mut Prakriya, i: usize) -> Option<()> { return None; } - let next_is_hi = n.first().has_text("hi"); - if anga.has_text_in(&["gam", "han", "jan", "Kan", "Gas"]) + if anga.has_text_in(&["gam", "han", "Gan", "jan", "Kan", "Gas"]) && n.has_adi(AC) && !p.has(i + 1, |t| t.is(S::Ric)) && !n.last().is(V::aN) { + // jagmatuH, jaGnatuH, jajJe, ... p.run_at("6.4.98", i, op::upadha_lopa); } else if anga.has_u("Basa~") { // TODO: rule is chAndasa, but SK applies it generally? p.run_at("6.4.100", i, op::upadha_lopa); - } else if (anga.has_text("hu") || anga.has_antya(JHAL) || anga.has_u("SAsu~")) && next_is_hi { + } + + Some(()) +} + +/// Runs rules conditioned on a following `kit` or `Nit` suffix. +/// +/// (6.4.98 - 6.4.126) +pub fn try_run_kniti_for_dhatu(p: &mut Prakriya, i: usize) -> Option<()> { + let anga = p.get(i)?; + let j = p.next_not_empty(i)?; + let n = p.pratyaya(j)?; + + if !n.is_knit() { + return None; + } + + let next_is_hi = n.first().has_text("hi"); + if (anga.has_text("hu") || anga.has_antya(JHAL) || anga.has_u("SAsu~")) && next_is_hi { + // juhuDi, BindDi, SADi, ... // HACK to allow SAsu~ so that we can derive SADi. p.run_at("6.4.101", n.start(), op::text("Di")); } else if anga.is(V::ciR) { + // akAri, ahAri, ... p.run_at("6.4.104", n.start(), op::luk); } @@ -330,12 +348,15 @@ fn try_run_kniti_sarvadhatuke(p: &mut Prakriya, i: usize) -> Option<()> { /// Run rules that replace the dhatu's vowel with e and apply abhyasa-lopa. /// Example: `la + laB + e` -> `leBe` -fn try_et_adesha_and_abhyasa_lopa_for_lit(p: &mut Prakriya, i: usize) -> Option<()> { - // Applies only for liw. - if !p.terms().last()?.has_lakara(Lit) { +pub fn try_et_adesha_and_abhyasa_lopa_for_lit(p: &mut Prakriya, i: usize) -> Option<()> { + if i == 0 { return None; } - if i == 0 { + + let n = p.pratyaya(i + 1)?; + + // Applies only for Lit. + if !n.last().has_lakara(Lit) { return None; } @@ -883,7 +904,7 @@ fn try_kr_rule(p: &mut Prakriya, i: usize) -> Option<()> { /// /// A prakriya could have multiple "bha" terms if, for example, we have a pratipadika followed by a /// taddhita-pratyaya followed by a strI-pratyaya. -pub fn try_bhasya_for_index(p: &mut Prakriya, i: usize) -> Option<()> { +fn try_bhasya_for_index(p: &mut Prakriya, i: usize) -> Option<()> { const PRIYA_ADI: &[&str] = &[ "priya", "sTira", @@ -972,7 +993,7 @@ pub fn try_bhasya_for_index(p: &mut Prakriya, i: usize) -> Option<()> { } } else if bha.has_text("pAd") { p.run_at("6.4.130", i, op::text("pad")); - } else if bha.is(K::kvasu) || bha.has_u("vasu~") { + } else if bha.is(K::kvasu) || bha.has_u_in(&["kvasu~", "vasu~"]) { p.run("6.4.131", |p| { p.set(i, op::text("us")); // valAdi is lost, so iw-Agama is also lost. @@ -1210,12 +1231,6 @@ pub fn run_after_guna(p: &mut Prakriya, i: usize) -> Option<()> { Some(()) } -pub fn run_after_dvitva(p: &mut Prakriya, i: usize) -> Option<()> { - run_for_kniti_ardhadhatuke_after_dvitva(p, i); - try_run_kniti_for_dhatu(p, i); - Some(()) -} - pub fn run_final(p: &mut Prakriya, i: usize) -> Option<()> { run_for_final_i_or_u(p, i); try_run_kniti(p, i); @@ -1225,8 +1240,6 @@ pub fn run_final(p: &mut Prakriya, i: usize) -> Option<()> { // here. try_kr_rule(p, i); - try_et_adesha_and_abhyasa_lopa_for_lit(p, i); - let n = p.pratyaya(i + 1)?; if n.has_tag(T::qit) { p.run_at("6.4.143", i, op::ti("")); diff --git a/vidyut-prakriya/src/ashtadhyayi.rs b/vidyut-prakriya/src/ashtadhyayi.rs index d7d6ec3..40b8d63 100644 --- a/vidyut-prakriya/src/ashtadhyayi.rs +++ b/vidyut-prakriya/src/ashtadhyayi.rs @@ -497,7 +497,7 @@ fn run_main_rules(p: &mut Prakriya, dhatu_args: Option<&Dhatu>, args: MainArgs) // Must run before it_agama rules since it affects how those rules are applied. atidesha::run_before_it_agama(p); // Depends on jha_adesha since it conditions on the first sound. - it_agama::run_before_attva(p); + it_agama::run_general_rules(p); // Should come before atidesha rules for ju[hve --> hU]zati (san is kit). samprasarana::run_for_dhatu_before_atidesha(p); // Depends on it_agama for certain rules. diff --git a/vidyut-prakriya/src/bin/create_dhatus.rs b/vidyut-prakriya/src/bin/create_dhatus.rs deleted file mode 100644 index 2ca8311..0000000 --- a/vidyut-prakriya/src/bin/create_dhatus.rs +++ /dev/null @@ -1,83 +0,0 @@ -/*! -Creates a test file containing the inputs to `Vyakarana`'s derivation functions and all of the -padas produced by those inputs. -*/ -use serde::Serialize; -use std::error::Error; -use std::io; -use vidyut_prakriya::args::Sanadi; -use vidyut_prakriya::{Dhatupatha, Vyakarana}; - -#[derive(Debug, Serialize)] -struct Row<'a> { - results: String, - dhatu: &'a str, - gana: &'static str, - number: u16, - sanadi: String, -} - -fn run(dhatupatha: Dhatupatha) -> Result<(), Box> { - let mut wtr = csv::Writer::from_writer(io::stdout()); - let v = Vyakarana::builder().log_steps(false).build(); - - let sanadi: Vec> = vec![ - vec![], - vec![Sanadi::san], - vec![Sanadi::Ric], - vec![Sanadi::yaN], - vec![Sanadi::yaNluk], - vec![Sanadi::san, Sanadi::Ric], - vec![Sanadi::Ric, Sanadi::san], - ]; - - for s in sanadi { - for entry in &dhatupatha { - let dhatu = entry.dhatu().clone().with_sanadi(&s); - - let prakriyas = v.derive_dhatus(&dhatu); - let dhatu_text = &dhatu.aupadeshika().expect("ok"); - let mut results: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); - results.sort(); - results.dedup(); - let results = results.join("|"); - - let sanadi_str = dhatu - .sanadi() - .iter() - .map(|x| x.as_str()) - .fold(String::new(), |b, x| b + x + "+"); - let sanadi_str = sanadi_str.trim_end_matches('+'); - - let row = Row { - results, - dhatu: dhatu_text, - gana: dhatu.gana().expect("ok").as_str(), - number: entry.number(), - sanadi: sanadi_str.to_string(), - }; - wtr.serialize(row)?; - } - } - - wtr.flush()?; - Ok(()) -} - -fn main() { - let dhatus = match Dhatupatha::from_path("data/dhatupatha.tsv") { - Ok(res) => res, - Err(err) => { - println!("{}", err); - std::process::exit(1); - } - }; - - match run(dhatus) { - Ok(()) => (), - Err(err) => { - eprintln!("{}", err); - std::process::exit(1); - } - } -} diff --git a/vidyut-prakriya/src/bin/create_krdantas.rs b/vidyut-prakriya/src/bin/create_krdantas.rs deleted file mode 100644 index a5537f0..0000000 --- a/vidyut-prakriya/src/bin/create_krdantas.rs +++ /dev/null @@ -1,110 +0,0 @@ -/*! -Creates a test file containing the inputs to `Vyakarana`'s derivation functions and all of the -padas produced by those inputs. -*/ -use clap::Parser; -use serde::Serialize; -use std::error::Error; -use std::io; -use vidyut_prakriya::args::{BaseKrt, Gana, Krdanta, Linga, Sanadi, Subanta, Vacana, Vibhakti}; -use vidyut_prakriya::{Dhatupatha, Vyakarana}; - -#[derive(Parser)] -#[command(author, version, about)] -struct Args { - #[arg(long, value_delimiter = ',')] - sanadi: Vec, -} - -#[derive(Debug, Serialize)] -struct Row<'a> { - padas: String, - dhatu: &'a str, - gana: Gana, - number: u16, - sanadi: &'a str, - krt: BaseKrt, - linga: Linga, - vibhakti: Vibhakti, - vacana: Vacana, -} - -/// Creates a collection of (linga, vibhakti, vacana) combinations. -fn linga_vibhakti_vacana_options() -> Vec<(Linga, Vibhakti, Vacana)> { - let mut ret = Vec::new(); - for linga in Linga::iter() { - for vibhakti in Vibhakti::iter() { - for vacana in Vacana::iter() { - ret.push((linga, vibhakti, vacana)) - } - } - } - ret -} - -fn run(dhatupatha: Dhatupatha, args: Args) -> Result<(), Box> { - let mut wtr = csv::Writer::from_writer(io::stdout()); - let v = Vyakarana::builder().log_steps(false).build(); - let lvv = linga_vibhakti_vacana_options(); - - for entry in dhatupatha { - let dhatu = entry.dhatu().clone().with_sanadi(&args.sanadi); - let dhatu_text = &dhatu.aupadeshika().expect("mula"); - let sanadi_str = args - .sanadi - .iter() - .map(|x| x.as_str()) - .fold(String::new(), |b, x| b + x + "+"); - let sanadi_str = sanadi_str.trim_end_matches('+'); - - for krt in BaseKrt::iter() { - let krdanta = Krdanta::builder().dhatu(dhatu.clone()).krt(krt).build()?; - - for (linga, vibhakti, vacana) in lvv.iter().copied() { - let args = Subanta::new(krdanta.clone(), linga, vibhakti, vacana); - let prakriyas = v.derive_subantas(&args); - - let mut padas: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); - padas.sort(); - padas.dedup(); - let padas = padas.join("|"); - - let row = Row { - padas, - dhatu: dhatu_text, - gana: dhatu.gana().expect("ok"), - number: entry.number(), - sanadi: &sanadi_str, - krt, - linga, - vibhakti, - vacana, - }; - wtr.serialize(row)?; - } - } - } - - wtr.flush()?; - Ok(()) -} - -fn main() { - let args = Args::parse(); - - let dhatus = match Dhatupatha::from_path("data/dhatupatha.tsv") { - Ok(res) => res, - Err(err) => { - println!("{}", err); - std::process::exit(1); - } - }; - - match run(dhatus, args) { - Ok(()) => (), - Err(err) => { - eprintln!("{}", err); - std::process::exit(1); - } - } -} diff --git a/vidyut-prakriya/src/bin/create_test_file.rs b/vidyut-prakriya/src/bin/create_test_file.rs deleted file mode 100644 index 6d2e18e..0000000 --- a/vidyut-prakriya/src/bin/create_test_file.rs +++ /dev/null @@ -1,95 +0,0 @@ -/*! -Creates a test file containing the inputs to `Vyakarana`'s derivation functions and all of the -padas produced by those inputs. -*/ -use serde::Serialize; -use std::error::Error; -use std::io; -use vidyut_prakriya::args::{Lakara, Prayoga, Purusha, Tinanta, Vacana}; -use vidyut_prakriya::{Dhatupatha, Vyakarana}; - -const TIN_SEMANTICS: &[(Purusha, Vacana)] = &[ - (Purusha::Prathama, Vacana::Eka), - (Purusha::Prathama, Vacana::Dvi), - (Purusha::Prathama, Vacana::Bahu), - (Purusha::Madhyama, Vacana::Eka), - (Purusha::Madhyama, Vacana::Dvi), - (Purusha::Madhyama, Vacana::Bahu), - (Purusha::Uttama, Vacana::Eka), - (Purusha::Uttama, Vacana::Dvi), - (Purusha::Uttama, Vacana::Bahu), -]; - -#[derive(Debug, Serialize)] -struct Row<'a> { - padas: String, - dhatu: &'a str, - gana: &'static str, - number: u16, - prayoga: &'static str, - lakara: &'static str, - purusha: &'static str, - vacana: &'static str, -} - -fn run(d: Dhatupatha) -> Result<(), Box> { - let mut wtr = csv::Writer::from_writer(io::stdout()); - let v = Vyakarana::builder().log_steps(false).build(); - - for entry in d { - let dhatu = entry.dhatu(); - for lakara in Lakara::iter() { - for (purusha, vacana) in TIN_SEMANTICS { - let prayoga = Prayoga::Kartari; - let tinanta = Tinanta::builder() - .dhatu(dhatu.clone()) - .prayoga(prayoga) - .purusha(*purusha) - .vacana(*vacana) - .lakara(lakara) - .build()?; - - let prakriyas = v.derive_tinantas(&tinanta); - - let dhatu_text = &dhatu.aupadeshika().expect("ok"); - let mut padas: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); - padas.sort(); - let padas = padas.join("|"); - - let row = Row { - padas, - dhatu: dhatu_text, - gana: dhatu.gana().expect("ok").as_str(), - number: entry.number(), - lakara: lakara.as_str(), - purusha: purusha.as_str(), - vacana: vacana.as_str(), - prayoga: prayoga.as_str(), - }; - - wtr.serialize(row)?; - } - } - } - - wtr.flush()?; - Ok(()) -} - -fn main() { - let dhatus = match Dhatupatha::from_path("data/dhatupatha.tsv") { - Ok(res) => res, - Err(err) => { - println!("{}", err); - std::process::exit(1); - } - }; - - match run(dhatus) { - Ok(()) => (), - Err(err) => { - eprintln!("{}", err); - std::process::exit(1); - } - } -} diff --git a/vidyut-prakriya/src/bin/create_test_files.rs b/vidyut-prakriya/src/bin/create_test_files.rs new file mode 100644 index 0000000..5dceee2 --- /dev/null +++ b/vidyut-prakriya/src/bin/create_test_files.rs @@ -0,0 +1,310 @@ +//! Creates all test files for our snapshot tests. +use clap::Parser; +use serde::Serialize; +use std::error::Error; +use std::path::{Path, PathBuf}; +use vidyut_prakriya::args::{ + BaseKrt, Dhatu, Gana, Krdanta, Lakara, Linga, Muladhatu, Prayoga, Purusha, Sanadi, Subanta, + Tinanta, Vacana, Vibhakti, +}; +use vidyut_prakriya::{Dhatupatha, Vyakarana}; + +#[derive(Parser)] +#[command(author, version, about)] +struct Args { + #[arg(long)] + output_dir: PathBuf, +} + +#[derive(Debug, Serialize)] +struct TinantaRow<'a> { + padas: String, + dhatu: &'a str, + gana: Gana, + number: u16, + sanadi: String, + prayoga: Prayoga, + lakara: Lakara, + purusha: Purusha, + vacana: Vacana, +} + +#[derive(Debug, Serialize)] +struct KrdantaRow<'a> { + padas: String, + dhatu: &'a str, + gana: Gana, + number: u16, + sanadi: &'a str, + krt: BaseKrt, + linga: Linga, + vibhakti: Vibhakti, + vacana: Vacana, +} + +#[derive(Debug, Serialize)] +struct DhatuRow<'a> { + results: String, + dhatu: &'a str, + gana: Gana, + number: u16, + sanadi: String, +} + +fn to_mula(dhatu: &Dhatu) -> &Muladhatu { + match dhatu { + Dhatu::Mula(m) => m, + _ => panic!("unknown dhatu"), + } +} + +/// Creates a collection of (lakara, purusha, vacana) combinations. +fn prayoga_lakara_purusha_vacana() -> Vec<(Prayoga, Lakara, Purusha, Vacana)> { + let mut ret = Vec::new(); + for prayoga in Prayoga::iter() { + for lakara in Lakara::iter() { + if lakara == Lakara::Let { + continue; + } + for purusha in Purusha::iter() { + for vacana in Vacana::iter() { + ret.push((prayoga, lakara, purusha, vacana)) + } + } + } + } + ret +} + +/// Creates a collection of (linga, vibhakti, vacana) combinations. +fn linga_vibhakti_vacana_options() -> Vec<(Linga, Vibhakti, Vacana)> { + let mut ret = Vec::new(); + for linga in Linga::iter() { + for vibhakti in Vibhakti::iter() { + for vacana in Vacana::iter() { + ret.push((linga, vibhakti, vacana)) + } + } + } + ret +} + +fn create_tinantas_file( + dhatupatha: &Dhatupatha, + sanadi: &[Sanadi], + output_file: &Path, +) -> Result<(), Box> { + let mut wtr = csv::Writer::from_path(output_file)?; + let v = Vyakarana::builder().log_steps(false).build(); + let plvp = prayoga_lakara_purusha_vacana(); + + for entry in dhatupatha { + let dhatu = to_mula(entry.dhatu()); + + // Add sanadi to the dhatu. + let mut builder = Dhatu::builder() + .aupadeshika(dhatu.aupadeshika()) + .prefixes(dhatu.prefixes()) + .gana(dhatu.gana()) + .sanadi(&sanadi); + if let Some(x) = dhatu.antargana() { + builder = builder.antargana(x); + } + let dhatu = builder.build()?; + let mula = to_mula(&dhatu); + + for (prayoga, lakara, purusha, vacana) in plvp.iter().copied() { + let tinanta = Tinanta::builder() + .dhatu(dhatu.clone()) + .prayoga(prayoga) + .purusha(purusha) + .vacana(vacana) + .lakara(lakara) + .build()?; + + let prakriyas = v.derive_tinantas(&tinanta); + let mut padas: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); + padas.sort(); + padas.dedup(); + let padas = padas.join("|"); + if padas.is_empty() { + continue; + } + + let sanadi_str = dhatu + .sanadi() + .iter() + .map(|x| x.as_str()) + .fold(String::new(), |b, x| b + x + "+"); + let sanadi_str = sanadi_str.trim_end_matches('+'); + + let dhatu_text = mula.aupadeshika(); + let row = TinantaRow { + padas, + dhatu: dhatu_text, + gana: mula.gana(), + number: entry.number(), + sanadi: sanadi_str.to_string(), + lakara, + purusha, + vacana, + prayoga, + }; + + wtr.serialize(row)?; + } + } + + wtr.flush()?; + Ok(()) +} + +fn create_krdantas_file( + dhatupatha: &Dhatupatha, + sanadi: &[Sanadi], + output_file: &Path, +) -> Result<(), Box> { + let mut wtr = csv::Writer::from_path(output_file)?; + let v = Vyakarana::builder().log_steps(false).build(); + let lvv = linga_vibhakti_vacana_options(); + + for entry in dhatupatha { + let dhatu = entry.dhatu().clone().with_sanadi(sanadi); + let dhatu_text = &dhatu.aupadeshika().expect("mula"); + let sanadi_str = sanadi + .iter() + .map(|x| x.as_str()) + .fold(String::new(), |b, x| b + x + "+"); + let sanadi_str = sanadi_str.trim_end_matches('+'); + + for krt in BaseKrt::iter() { + let krdanta = Krdanta::builder().dhatu(dhatu.clone()).krt(krt).build()?; + + for (linga, vibhakti, vacana) in lvv.iter().copied() { + let args = Subanta::new(krdanta.clone(), linga, vibhakti, vacana); + let prakriyas = v.derive_subantas(&args); + + let mut padas: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); + padas.sort(); + padas.dedup(); + let padas = padas.join("|"); + + let row = KrdantaRow { + padas, + dhatu: dhatu_text, + gana: dhatu.gana().expect("ok"), + number: entry.number(), + sanadi: &sanadi_str, + krt, + linga, + vibhakti, + vacana, + }; + wtr.serialize(row)?; + } + } + } + + wtr.flush()?; + Ok(()) +} + +fn create_dhatus_file(dhatupatha: &Dhatupatha, output_file: &Path) -> Result<(), Box> { + let mut wtr = csv::Writer::from_path(output_file)?; + let v = Vyakarana::builder().log_steps(false).build(); + + let sanadi: Vec> = vec![ + vec![], + vec![Sanadi::san], + vec![Sanadi::Ric], + vec![Sanadi::yaN], + vec![Sanadi::yaNluk], + vec![Sanadi::san, Sanadi::Ric], + vec![Sanadi::Ric, Sanadi::san], + ]; + + for s in sanadi { + for entry in dhatupatha { + let dhatu = entry.dhatu().clone().with_sanadi(&s); + + let prakriyas = v.derive_dhatus(&dhatu); + let dhatu_text = &dhatu.aupadeshika().expect("ok"); + let mut results: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); + results.sort(); + results.dedup(); + let results = results.join("|"); + + let sanadi_str = dhatu + .sanadi() + .iter() + .map(|x| x.as_str()) + .fold(String::new(), |b, x| b + x + "+"); + let sanadi_str = sanadi_str.trim_end_matches('+'); + + let row = DhatuRow { + results, + dhatu: dhatu_text, + gana: dhatu.gana().expect("ok"), + number: entry.number(), + sanadi: sanadi_str.to_string(), + }; + wtr.serialize(row)?; + } + } + + Ok(()) +} + +fn run(dhatupatha: Dhatupatha, args: Args) -> Result<(), Box> { + use Sanadi::*; + + let dir = args.output_dir; + + let sanadis = &[ + (vec![], "basic"), + (vec![Ric], "nic"), + (vec![san], "san"), + (vec![yaN], "yan"), + (vec![yaNluk], "yan-luk"), + (vec![san, Ric], "san-nic"), + (vec![Ric, san], "nic-san"), + ]; + + for (sanadis, s_name) in sanadis { + let filename = format!("tinantas-{s_name}.csv"); + println!("Creating {filename}."); + create_tinantas_file(&dhatupatha, &sanadis, &dir.join(filename))?; + } + + for (sanadis, s_name) in sanadis { + let filename = format!("krdantas-{s_name}.csv"); + println!("Creating {filename}."); + create_krdantas_file(&dhatupatha, &sanadis, &dir.join(filename))?; + } + + let filename = "dhatus.csv"; + println!("Creating {filename}."); + create_dhatus_file(&dhatupatha, &dir.join(filename))?; + + Ok(()) +} + +fn main() { + let args = Args::parse(); + + let dhatupatha = match Dhatupatha::from_path("data/dhatupatha.tsv") { + Ok(res) => res, + Err(err) => { + println!("{}", err); + std::process::exit(1); + } + }; + + match run(dhatupatha, args) { + Ok(()) => (), + Err(err) => { + eprintln!("{}", err); + std::process::exit(1); + } + } +} diff --git a/vidyut-prakriya/src/bin/create_tinantas.rs b/vidyut-prakriya/src/bin/create_tinantas.rs deleted file mode 100644 index 1e42c44..0000000 --- a/vidyut-prakriya/src/bin/create_tinantas.rs +++ /dev/null @@ -1,150 +0,0 @@ -/*! -Creates a test file containing the inputs to `Vyakarana`'s derivation functions and all of the -padas produced by those inputs. -*/ -use clap::Parser; -use serde::Serialize; -use std::error::Error; -use std::io; -use vidyut_prakriya::args::{Dhatu, Lakara, Muladhatu, Prayoga, Purusha, Sanadi, Tinanta, Vacana}; -use vidyut_prakriya::{Dhatupatha, Vyakarana}; - -#[derive(Parser)] -#[command(author, version, about)] -struct Args { - #[arg(long)] - prayoga: Option, - #[arg(long, value_delimiter = ',')] - sanadi: Vec, -} - -const TIN_SEMANTICS: &[(Purusha, Vacana)] = &[ - (Purusha::Prathama, Vacana::Eka), - (Purusha::Prathama, Vacana::Dvi), - (Purusha::Prathama, Vacana::Bahu), - (Purusha::Madhyama, Vacana::Eka), - (Purusha::Madhyama, Vacana::Dvi), - (Purusha::Madhyama, Vacana::Bahu), - (Purusha::Uttama, Vacana::Eka), - (Purusha::Uttama, Vacana::Dvi), - (Purusha::Uttama, Vacana::Bahu), -]; - -#[derive(Debug, Serialize)] -struct Row<'a> { - padas: String, - dhatu: &'a str, - gana: &'static str, - number: u16, - sanadi: String, - prayoga: &'static str, - lakara: &'static str, - purusha: &'static str, - vacana: &'static str, -} - -fn to_mula(dhatu: &Dhatu) -> &Muladhatu { - match dhatu { - Dhatu::Mula(m) => m, - _ => panic!("unknown dhatu"), - } -} - -fn run(d: Dhatupatha, args: Args) -> Result<(), Box> { - let mut wtr = csv::Writer::from_writer(io::stdout()); - let v = Vyakarana::builder().log_steps(false).build(); - - let sanadi = args.sanadi; - for entry in d { - let dhatu = to_mula(entry.dhatu()); - - // Add sanadi to the dhatu. - let mut builder = Dhatu::builder() - .aupadeshika(dhatu.aupadeshika()) - .prefixes(dhatu.prefixes()) - .gana(dhatu.gana()) - .sanadi(&sanadi); - if let Some(x) = dhatu.antargana() { - builder = builder.antargana(x); - } - let dhatu = builder.build()?; - let mula = to_mula(&dhatu); - - for prayoga in Prayoga::iter() { - // Filter prayoga based on args - if let Some(p) = args.prayoga { - if prayoga != p { - continue; - } - } - for lakara in Lakara::iter() { - if lakara == Lakara::Let { - continue; - } - for (purusha, vacana) in TIN_SEMANTICS.iter().copied() { - let tinanta = Tinanta::builder() - .dhatu(dhatu.clone()) - .prayoga(prayoga) - .purusha(purusha) - .vacana(vacana) - .lakara(lakara) - .build()?; - - let prakriyas = v.derive_tinantas(&tinanta); - let mut padas: Vec<_> = prakriyas.iter().map(|p| p.text()).collect(); - padas.sort(); - padas.dedup(); - let padas = padas.join("|"); - if padas.is_empty() { - continue; - } - - let sanadi_str = dhatu - .sanadi() - .iter() - .map(|x| x.as_str()) - .fold(String::new(), |b, x| b + x + "+"); - let sanadi_str = sanadi_str.trim_end_matches('+'); - - let dhatu_text = mula.aupadeshika(); - let row = Row { - padas, - dhatu: dhatu_text, - gana: mula.gana().as_str(), - number: entry.number(), - sanadi: sanadi_str.to_string(), - lakara: lakara.as_str(), - purusha: purusha.as_str(), - vacana: vacana.as_str(), - prayoga: prayoga.as_str(), - }; - - wtr.serialize(row)?; - } - } - } - } - - wtr.flush()?; - Ok(()) -} - -fn main() { - let args = Args::parse(); - - let dhatus = match Dhatupatha::from_path("data/dhatupatha.tsv") { - Ok(res) => res, - Err(err) => { - println!("{}", err); - std::process::exit(1); - } - }; - - match run(dhatus, args) { - Ok(()) => (), - Err(err) => { - eprintln!("{}", err); - std::process::exit(1); - } - } -} diff --git a/vidyut-prakriya/src/bin/test_results.rs b/vidyut-prakriya/src/bin/test_results.rs index 793edb7..8870c47 100644 --- a/vidyut-prakriya/src/bin/test_results.rs +++ b/vidyut-prakriya/src/bin/test_results.rs @@ -6,7 +6,8 @@ use std::error::Error; use std::io::Write; use std::path::PathBuf; use vidyut_prakriya::args::{ - BaseKrt, Dhatu, Gana, Krdanta, Linga, Sanadi, Subanta, Tinanta, Vacana, Vibhakti, + BaseKrt, Dhatu, Gana, Krdanta, Lakara, Linga, Prayoga, Purusha, Sanadi, Subanta, Tinanta, + Vacana, Vibhakti, }; use vidyut_prakriya::dhatupatha; use vidyut_prakriya::private::check_file_hash; @@ -25,6 +26,19 @@ struct Args { hash: String, } +#[derive(Debug, Deserialize)] +struct TinantaRow { + padas: String, + dhatu: String, + gana: Gana, + number: u16, + sanadi: String, + prayoga: Prayoga, + lakara: Lakara, + purusha: Purusha, + vacana: Vacana, +} + #[derive(Debug, Deserialize)] struct KrdantaRow { padas: String, @@ -38,6 +52,15 @@ struct KrdantaRow { vacana: Vacana, } +#[derive(Debug, Deserialize)] +struct DhatuRow { + results: String, + dhatu: String, + gana: Gana, + number: u16, + sanadi: String, +} + fn parse_sanadi(val: &str) -> Result, vidyut_prakriya::Error> { if val.is_empty() { Ok(Vec::new()) @@ -48,24 +71,17 @@ fn parse_sanadi(val: &str) -> Result, vidyut_prakriya::Error> { } } -fn test_tinanta(line: &str) -> Result<(), Box> { - let mut reader = csv::ReaderBuilder::new() - .has_headers(false) - .from_reader(line.as_bytes()); - let mut r = csv::StringRecord::new(); - assert!(reader.read_record(&mut r).unwrap()); - - let expected: Vec<_> = r[0].split('|').collect(); - - let upadesha = &r[1]; - let gana = &r[2]; - let number = &r[3]; - let dhatu = dhatupatha::create_dhatu(upadesha, gana.parse()?, number.parse()?)?; - let sanadi = parse_sanadi(&r[4])?; - let prayoga = r[5].parse()?; - let lakara = r[6].parse()?; - let purusha = r[7].parse()?; - let vacana = r[8].parse()?; +fn test_tinanta(r: Result) -> Result<(), Box> { + let r = r?; + + let expected: Vec<_> = r.padas.split('|').collect(); + let aupadeshika = &r.dhatu; + let dhatu = dhatupatha::create_dhatu(aupadeshika, r.gana, r.number)?; + let sanadi = parse_sanadi(&r.sanadi)?; + let prayoga = r.prayoga; + let lakara = r.lakara; + let purusha = r.purusha; + let vacana = r.vacana; // TODO: this is very clumsy! let mut builder = Dhatu::builder() @@ -95,16 +111,16 @@ fn test_tinanta(line: &str) -> Result<(), Box> { actual.dedup(); if expected != actual { - let lakara = &r[5]; - let purusha = &r[6]; - let vacana = &r[7]; - let code = format!("{:0>2}.{:0>4}", gana, number); - let upadesha = dhatu.aupadeshika().expect("ok"); + let lakara = r.lakara; + let purusha = r.purusha; + let vacana = r.vacana; + let code = format!("{:0>2}.{:0>4}", r.gana, r.number); + let aupadeshika = dhatu.aupadeshika().expect("ok"); let mut out = std::io::stdout().lock(); writeln!( out, - "[ FAIL ] {code:<10} {upadesha:<10} {lakara:<10} {purusha:<10} {vacana:<10}" + "[ FAIL ] {code:<10} {aupadeshika:<10} {lakara:<10} {purusha:<10} {vacana:<10}" )?; writeln!(out, " Expected: {:?}", expected)?; writeln!(out, " Actual : {:?}", actual)?; @@ -113,11 +129,10 @@ fn test_tinanta(line: &str) -> Result<(), Box> { Ok(()) } -fn test_krdanta(r: Result) -> Result<(), Box> { - let r = r?; +fn test_krdanta(r: &KrdantaRow) -> Result<(), Box> { let expected: Vec<_> = r.padas.split('|').filter(|x| !x.is_empty()).collect(); - let upadesha = r.dhatu; + let aupadeshika = &r.dhatu; let gana = r.gana; let number = r.number; let sanadi = parse_sanadi(&r.sanadi)?; @@ -127,7 +142,7 @@ fn test_krdanta(r: Result) -> Result<(), Box> let vacana: Vacana = r.vacana; let v = Vyakarana::builder().log_steps(false).build(); - let dhatu = dhatupatha::create_dhatu(upadesha, gana, number)?.with_sanadi(&sanadi); + let dhatu = dhatupatha::create_dhatu(aupadeshika, gana, number)?.with_sanadi(&sanadi); let krdanta = Krdanta::builder().dhatu(dhatu.clone()).krt(krt).build()?; let subanta = Subanta::new(krdanta, linga, vibhakti, vacana); let prakriyas = v.derive_subantas(&subanta); @@ -137,10 +152,10 @@ fn test_krdanta(r: Result) -> Result<(), Box> if expected != actual { let code = format!("{:0>2}.{:0>4}", gana, number); - let upadesha = dhatu.aupadeshika().expect("ok"); + let aupadeshika = dhatu.aupadeshika().expect("ok"); let mut out = std::io::stdout().lock(); - writeln!(out, "[ FAIL ] {code:<10} {upadesha:<10} {krt:<10}")?; + writeln!(out, "[ FAIL ] {code:<10} {aupadeshika:<10} {krt:<10}")?; writeln!(out, " Expected: {:?}", expected)?; writeln!(out, " Actual : {:?}", actual)?; } @@ -148,18 +163,14 @@ fn test_krdanta(r: Result) -> Result<(), Box> Ok(()) } -fn test_dhatu(line: &str) -> Result<(), Box> { - let mut reader = csv::ReaderBuilder::new() - .has_headers(false) - .from_reader(line.as_bytes()); - let mut r = csv::StringRecord::new(); - assert!(reader.read_record(&mut r).unwrap()); +fn test_dhatu(r: Result) -> Result<(), Box> { + let r = r?; - let expected: Vec<_> = r[0].split('|').filter(|x| !x.is_empty()).collect(); - let aupadeshika = &r[1]; - let gana: Gana = r[2].parse()?; - let number: u16 = r[3].parse()?; - let sanadi = parse_sanadi(&r[4])?; + let expected: Vec<_> = r.results.split('|').filter(|x| !x.is_empty()).collect(); + let aupadeshika = &r.dhatu; + let gana: Gana = r.gana; + let number: u16 = r.number; + let sanadi = parse_sanadi(&r.sanadi)?; let dhatu = dhatupatha::create_dhatu(aupadeshika, gana, number)?.with_sanadi(&sanadi); @@ -171,10 +182,10 @@ fn test_dhatu(line: &str) -> Result<(), Box> { if expected != actual { let code = format!("{gana:0>2}.{number:0>4}"); - let upadesha = dhatu.aupadeshika().expect("ok"); + let aupadeshika = dhatu.aupadeshika().expect("ok"); let mut out = std::io::stdout().lock(); - writeln!(out, "[ FAIL ] {code:<10} {upadesha:<10} {sanadi:?}")?; + writeln!(out, "[ FAIL ] {code:<10} {aupadeshika:<10} {sanadi:?}")?; writeln!(out, " Expected: {expected:?}")?; writeln!(out, " Actual : {actual:?}")?; } @@ -186,31 +197,41 @@ fn run(args: Args) -> Result<(), Box> { check_file_hash(&args.test_cases, &args.hash); if args.data_type == "krdanta" { + // Reading krdantas into a vec first leads to a 3x speedup over using par_bridge. + // + // Benchmark: + // + // time ../target/release/test_results \ + // --data-type krdanta \ + // --test-cases test-files/krdantas-basic.csv \ + // --hash "5965c75ef9897df91907148e8b548abf359d4ac89615c073ba4a2c61af9fff54" + // + // Before: Executed in 43.96 secs + // After: Executed in 14.03 secs let mut r = csv::Reader::from_path(&args.test_cases)?; - r.deserialize().par_bridge().for_each(|row| { + let krdantas: Vec = r.deserialize().filter_map(Result::ok).collect(); + krdantas.par_iter().for_each(|row| { match test_krdanta(row) { Ok(()) => (), Err(e) => println!("ERROR: Row is malformed: {e}"), }; }); } else if args.data_type == "tinanta" { - let file = std::fs::read_to_string(&args.test_cases)?; - file.lines() - .skip(1) - .par_bridge() - .for_each(|line| match test_tinanta(line) { - Ok(_) => (), - Err(_) => println!("ERROR: Row is malformed: {line}"), - }); + let mut r = csv::Reader::from_path(&args.test_cases)?; + r.deserialize().par_bridge().for_each(|row| { + match test_tinanta(row) { + Ok(()) => (), + Err(e) => println!("ERROR: Row is malformed: {e}"), + }; + }); } else if args.data_type == "dhatu" { - let file = std::fs::read_to_string(&args.test_cases)?; - file.lines() - .skip(1) - .par_bridge() - .for_each(|line| match test_dhatu(line) { - Ok(_) => (), - Err(_) => println!("ERROR: Row is malformed: {line}"), - }); + let mut r = csv::Reader::from_path(&args.test_cases)?; + r.deserialize().par_bridge().for_each(|row| { + match test_dhatu(row) { + Ok(()) => (), + Err(e) => println!("ERROR: Row is malformed: {e}"), + }; + }); } Ok(()) diff --git a/vidyut-prakriya/src/dhatupatha.rs b/vidyut-prakriya/src/dhatupatha.rs index 2e42332..819771d 100644 --- a/vidyut-prakriya/src/dhatupatha.rs +++ b/vidyut-prakriya/src/dhatupatha.rs @@ -15,7 +15,7 @@ pub struct Entry { } impl Entry { - fn parse(code: &str, upadesha: &str, artha: &str) -> Result { + fn parse(code: &str, aupadeshika: &str, artha: &str) -> Result { let (gana, number) = code.split_once('.').ok_or(Error::InvalidFile)?; let gana = if let Some(stripped) = gana.strip_prefix('0') { stripped.parse()? @@ -23,7 +23,7 @@ impl Entry { gana.parse()? }; let number = number.parse()?; - let dhatu = create_dhatu(upadesha, gana, number)?; + let dhatu = create_dhatu(aupadeshika, gana, number)?; Ok(Self { code: code.to_string(), @@ -76,14 +76,14 @@ pub struct Dhatupatha(Vec); /// /// This function uses the `number` parameter to determine the dhatu's antargana. If you wish to /// specify the antargana explicitly, please construct `Dhatu` directly with [`Dhatu::builder`]. -pub fn create_dhatu(upadesha: impl AsRef, gana: Gana, number: u16) -> Result { - let upadesha = upadesha.as_ref(); +pub fn create_dhatu(aupadeshika: impl AsRef, gana: Gana, number: u16) -> Result { + let aupadeshika = aupadeshika.as_ref(); - let mut builder = Dhatu::builder().aupadeshika(upadesha).gana(gana); + let mut builder = Dhatu::builder().aupadeshika(aupadeshika).gana(gana); if let Some(x) = maybe_find_antargana(gana, number) { builder = builder.antargana(x); } - match upadesha { + match aupadeshika { "i\\N" | "i\\k" => { builder = builder.prefixes(&["aDi"]); } @@ -144,7 +144,7 @@ impl Dhatupatha { Some(x) => x, None => return Err(Error::InvalidFile), }; - let upadesha = match fields.next() { + let aupadeshika = match fields.next() { Some(x) => x, None => return Err(Error::InvalidFile), }; @@ -154,11 +154,11 @@ impl Dhatupatha { }; // If the upadesha is missing, this is a ganasutra -- skip. - if upadesha == "-" { + if aupadeshika == "-" { continue; } - let entry = Entry::parse(code, upadesha, artha)?; + let entry = Entry::parse(code, aupadeshika, artha)?; dhatus.push(entry); } diff --git a/vidyut-prakriya/src/it_agama.rs b/vidyut-prakriya/src/it_agama.rs index 72e3640..7fd8c13 100644 --- a/vidyut-prakriya/src/it_agama.rs +++ b/vidyut-prakriya/src/it_agama.rs @@ -27,6 +27,7 @@ Order of operations: */ use crate::args::Agama as A; +use crate::args::Aupadeshika as Au; use crate::args::BaseKrt as K; use crate::args::Gana::*; use crate::args::Lakara::*; @@ -216,6 +217,38 @@ fn try_dirgha_for_it_agama(p: &mut Prakriya, i_it: usize) -> Option<()> { Some(()) } +pub fn run_for_kvasu_pratyaya(p: &mut Prakriya, i: usize) -> Option { + let _d = p.get_if(i, |t| t.is_dhatu())?; + let _i_n = p.get_if(i + 1, |t| t.has_u("kvasu~"))?; + let mut ip = ItPrakriya::new(p, i, i + 1); + + let dhatu = ip.anga(); + if dhatu.has_u_in(&["ga\\mx~", "ha\\na~", "vida~", "vi\\Sa~"]) { + // jagmivAn, jagamvAn; ... + ip.optional_try_add("7.2.68"); + } else if dhatu.is_u(Au::dfSir) { + // dadfSivAn; dadfSvAn + ip.optional_try_add(Varttika("7.2.68.1")); + } + + let dhatu = ip.anga(); + + // Dhatus that start with vowels (Adivas, ASivas, ...) + let is_ac_adi = dhatu.has_adi(AC); + let is_eka_ac = + dhatu.num_vowels() == 1 && (i > 0 && ip.p.has(i - 1, |t| t.is_abhyasa() && t.is_empty())); + + let code = "7.2.67"; + if is_ac_adi || is_eka_ac || dhatu.has_antya('A') || dhatu.has_u("Gasx~") { + // AdivAn, yayivAn, jakzivAn, ... + ip.try_add(code); + // baBUvAn, ... + ip.try_block(code); + } + + Some(true) +} + fn run_valadau_ardhadhatuke_before_attva_for_term(ip: &mut ItPrakriya) -> Option<()> { let anga = ip.anga(); let n = ip.next(); @@ -230,42 +263,9 @@ fn run_valadau_ardhadhatuke_before_attva_for_term(ip: &mut ItPrakriya) -> Option let ktvi = n.last().is(K::ktvA); if n.has_u("kvasu~") { - // kvasu~ rules should take priority over `li~w` below. - let anga = ip.anga(); - if anga.has_text_in(&["gam", "han", "vid", "viS"]) { - ip.optional_try_add("7.2.68"); - } else if anga.has_text("dfS") { - ip.optional_try_add(Varttika("7.2.68.1")); - } - - let anga = ip.anga(); - - // Per the kashikavrtti, the condition is "kṛtadvirvacanānāṃ dhātūnām ekācām" -- if the dhatu - // *would have* one vowel after dvirvacana and all of the usual procedures there. - - // Dhatus that start with vowels (Adivas, ASivas, ...) - let is_ac_adi = anga.has_adi(AC); - // Dhatus that will start with vowels due to kit-samprasarana (Ucivas, Ijivas, ...). - // NOTE: keep this in sync with the `samprasarana` module. - let will_be_ac_adi = anga.has_u_in(&[ - "va\\ca~", - "ya\\ja~^", - "quva\\pa~^", - "va\\ha~^", - "va\\sa~", - "ve\\Y", - "vye\\Y", - "vada~", - ]); - // Dhatus that undergo ettva-abhyAsalopa (pecivas, Sekivas, ...) - let will_be_eka_ac = is_ac_adi || will_be_ac_adi; - - let code = "7.2.67"; - if will_be_eka_ac || anga.has_antya('A') || anga.has_text("Gas") { - ip.try_add(code); - } else { - ip.try_block(code); - } + // kvasu~ rules take priority over `li~w` below. + // But, defer it-Agama here until we have completed dvitva. + return None; } else if n.has_lakara(Lit) { if anga.has_text("vf") && n.has_u("Tal") { // Exception to krAdi-niyama. @@ -652,7 +652,7 @@ fn run_sarvadhatuke_for_term(ip: &mut ItPrakriya) -> Option<()> { Some(()) } -pub fn run_before_attva(p: &mut Prakriya) -> Option<()> { +pub fn run_general_rules(p: &mut Prakriya) -> Option<()> { // The abhyasa might come second, so match on it specifically. let n = p.terms().len(); debug_assert!(n > 0); diff --git a/vidyut-prakriya/src/krt/basic.rs b/vidyut-prakriya/src/krt/basic.rs index 9dd54b6..71bc548 100644 --- a/vidyut-prakriya/src/krt/basic.rs +++ b/vidyut-prakriya/src/krt/basic.rs @@ -1113,7 +1113,7 @@ fn try_add_krt(kp: &mut KrtPrakriya) -> Option { } K::lyu | K::Rini => { - if is_nandi_grahi_pacadi(&kp) { + if is_nandi_grahi_pacadi(kp) { kp.try_add("3.1.134", krt); } else if krt == K::Rini { // TODO: supi diff --git a/vidyut-prakriya/src/sanadi.rs b/vidyut-prakriya/src/sanadi.rs index a75c077..f573cf4 100644 --- a/vidyut-prakriya/src/sanadi.rs +++ b/vidyut-prakriya/src/sanadi.rs @@ -35,12 +35,12 @@ impl<'a> SanadiPrakriya<'a> { p: &mut Prakriya, i_base: usize, rule: impl Into, - upadesha: &str, + aupadeshika: &str, func: impl Fn(&mut Prakriya), ) { p.run(rule, |p| { // TODO: do others. (Refactoring.) These are the most important. - let sanadi = match upadesha { + let sanadi = match aupadeshika { "san" => Term::from(Sanadi::san), "yaN" => Term::from(Sanadi::yaN), "Ric" => Term::from(Sanadi::Ric), @@ -48,7 +48,7 @@ impl<'a> SanadiPrakriya<'a> { "kyac" => Term::from(Sanadi::kyac), "kAmyac" => Term::from(Sanadi::kAmyac), _ => { - let mut t = Term::make_upadesha(upadesha); + let mut t = Term::make_upadesha(aupadeshika); t.add_tags(&[T::Pratyaya]); t } diff --git a/vidyut-prakriya/tests/integration/kashika_3_2.rs b/vidyut-prakriya/tests/integration/kashika_3_2.rs index d709228..8a49d9a 100644 --- a/vidyut-prakriya/tests/integration/kashika_3_2.rs +++ b/vidyut-prakriya/tests/integration/kashika_3_2.rs @@ -1044,7 +1044,6 @@ fn sutra_3_2_107() { assert_has_krdanta(&[], &d("pA\\", Bhvadi), Krt::kvasu, &["papivas"]); } -#[ignore] #[test] fn sutra_3_2_108() { let sad = d("za\\dx~", Bhvadi); diff --git a/vidyut-prakriya/tests/integration/kashika_6_4.rs b/vidyut-prakriya/tests/integration/kashika_6_4.rs index 0c15aa5..51e4333 100644 --- a/vidyut-prakriya/tests/integration/kashika_6_4.rs +++ b/vidyut-prakriya/tests/integration/kashika_6_4.rs @@ -268,7 +268,6 @@ fn sutra_6_4_21() { assert_has_krdanta(&[], &dhurv, Krt::ktin, &["DUrti"]); } -#[ignore] #[test] fn sutra_6_4_22() { assert_has_sip(&[], &d("asa~", Adadi), Lot, &["eDi", "stAt"]); @@ -1934,7 +1933,6 @@ fn sutra_6_4_130() { assert_has_taddhita(&vyaghrapad, T::yak, &["vEyAGrapadya"]); } -#[ignore] #[test] fn sutra_6_4_131() { let vidvas = krdanta(&[], &d("vida~", Adadi), Krt::Satf); diff --git a/vidyut-prakriya/tests/integration/kashika_7_2.rs b/vidyut-prakriya/tests/integration/kashika_7_2.rs index d62738f..2d08385 100644 --- a/vidyut-prakriya/tests/integration/kashika_7_2.rs +++ b/vidyut-prakriya/tests/integration/kashika_7_2.rs @@ -17,6 +17,11 @@ fn assert_has_san_ta(prefixes: &[&str], dhatu: &Dhatu, expected: &[&str]) { assert_has_ta(prefixes, &san(&dhatu), Lat, expected); } +fn assert_has_kvasu_su(dhatu: &Dhatu, expected: &[&str]) { + let vas = krdanta(&[], dhatu, Krt::kvasu); + assert_has_sup_1s(&vas, Pum, expected); +} + #[test] fn sutra_7_2_1() { assert_has_tip(&[], &d("ci\\Y", Svadi), Lun, &["acEzIt"]); @@ -1150,25 +1155,58 @@ fn sutra_7_2_66() { } #[test] -fn sutra_7_2_68() { - let assert_has_kvasu = |d, exp| { - assert_has_krdanta(&[], &d, Krt::kvasu, exp); - }; +fn sutra_7_2_67() { + // ekAc + assert_has_kvasu_su(&d("a\\da~", Adadi), &["AdivAn", "jakzivAn"]); + assert_has_kvasu_su(&d("aSa~", Kryadi), &["ASivAn"]); + assert_has_kvasu_su(&d("qupa\\ca~^z", Bhvadi), &["pecivAn"]); + assert_has_kvasu_su(&d("Sa\\kx~", Svadi), &["SekivAn"]); + + // At + assert_has_kvasu_su(&d("yA\\", Adadi), &["yayivAn"]); + assert_has_kvasu_su(&d("zWA\\", Bhvadi), &["tasTivAn"]); - assert_has_kvasu(d("ga\\mx~", Bhvadi), &["jagmivas", "jaganvas"]); - assert_has_kvasu(d("ha\\na~", Adadi), &["jaGnivas", "jaGanvas"]); - assert_has_kvasu( - d("vida~", Adadi), + // Gas + assert_has_kvasu_su(&d("Gasx~", Bhvadi), &["jakzivAn"]); + + // ekAc? + assert_has_kvasu_su(&d("Bi\\di~^r", Rudhadi), &["biBidvAn"]); + assert_has_kvasu_su(&d("Ci\\di~^r", Rudhadi), &["cicCidvAn"]); + assert_has_kvasu_su(&d("BU", Bhvadi), &["baBUvAn"]); + assert_has_kvasu_su(&d("SriY", Bhvadi), &["SiSrivAn"]); + + // TODO: double check these. + assert_has_kvasu_su( + &d("daridrA", Adadi), &[ - "vividivas", - "vividvas", - "vidAmAsivas", - "vidAmbaBUvas", - "vidAYcakfvas", + "dadaridrvAn", + "daridrAYcakfvAn", + "daridrAmbaBUvAn", + "daridrAmAsivAn", ], ); - assert_has_kvasu(d("vi\\Sa~", Tudadi), &["viviSivas", "viviSvas"]); - assert_has_kvasu(d("df\\Si~r", Bhvadi), &["dadfSivas", "dadfSvas"]); +} + +#[test] +fn sutra_7_2_68() { + assert_has_kvasu_su(&d("ga\\mx~", Bhvadi), &["jagmivAn", "jaganvAn"]); + assert_has_kvasu_su(&d("ha\\na~", Adadi), &["jaGnivAn", "jaGanvAn"]); + assert_has_kvasu_su( + &d("vida~", Adadi), + &[ + "vividivAn", + "vividvAn", + "vidAmAsivAn", + "vidAmbaBUvAn", + "vidAYcakfvAn", + ], + ); + assert_has_kvasu_su(&d("vi\\Sa~", Tudadi), &["viviSivAn", "viviSvAn"]); +} + +#[test] +fn sutra_7_2_68_v1() { + assert_has_kvasu_su(&d("df\\Si~r", Bhvadi), &["dadfSivAn", "dadfSvAn"]); } #[test] diff --git a/vidyut-prakriya/tests/integration/regressions.rs b/vidyut-prakriya/tests/integration/regressions.rs index bfa50ab..9620c97 100644 --- a/vidyut-prakriya/tests/integration/regressions.rs +++ b/vidyut-prakriya/tests/integration/regressions.rs @@ -273,3 +273,9 @@ fn iccha_nipatana() { assert_has_krdanta(&[], &d("izu~", Tudadi), Krt::Sa, &["icCA"]); assert_has_krdanta(&[], &d("izu~", Tudadi), Krt::vuY, &[]); } + +// Tests (Bas -> Bs) + (hi -> Di) for asiddhavat rules. +#[test] +fn babdhi() { + assert_has_sip(&[], &d("Basa~", Juhotyadi), Lot, &["babDi", "babDAt"]); +}