Skip to content

Commit

Permalink
[prakriya] Fix prakriya for jIyAt and others
Browse files Browse the repository at this point in the history
With this fix, we correctly apply 6.1.108 and 6.4.2 for the derivation
of `jIyAt` (`jyA`) and others.
  • Loading branch information
akprasad committed Apr 22, 2024
1 parent 03afd20 commit c886f28
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 27 deletions.
5 changes: 4 additions & 1 deletion vidyut-prakriya/src/angasya.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@ fn add_num(t: &mut Term) {

/// Runs rules that lengthen a vowel in the anga.
fn try_do_dirgha(p: &mut Prakriya, i_anga: usize) -> Option<()> {
p.debug(format!("TRY DO HALAH {i_anga}"));
let anga = p.get_if(i_anga, |t| t.is_anga())?;
let n = p.get_if(i_anga + 1, |t| t.is_pratyaya())?;
// Also include yAsut-Agama for ji + yAs + t --> jIyAt.
// TODO: extend?
let n = p.get_if(i_anga + 1, |t| t.is_pratyaya() || t.has_u("yAsu~w"))?;

// Exclude tin -- otherwise, we get "daDAntaH" instead of "daDantaH".
// "kvisāhacaryeṇa tiṅbhinnasyaiva jhalādestatra grahaṇāt" -- Balamanorama on 6.4.48.
Expand Down
43 changes: 31 additions & 12 deletions vidyut-prakriya/src/samprasarana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::core::{Code, Prakriya};
/// - Must follow atidesha so that suffixes have the kit/Nit annotations necessary to cause
/// samprasanara.
use crate::dhatu_gana as gana;
use crate::sounds;

fn is_vaci_svapi(t: &Term) -> bool {
t.is_dhatu()
Expand Down Expand Up @@ -64,11 +65,11 @@ fn find_samprasarana_match(p: &Prakriya, i: usize) -> Option<&'static str> {
];
const AFTER: &[&str] = &[
// vaci-svapi
"uc", "uc", "sup", "ij", "up", "uh", "us", "u", "vI", "hU", "ud", "SU",
"uac", "uac", "suap", "iaj", "uap", "uah", "uas", "ue", "vie", "hue", "uad", "Sui",
// grahi-jyA
"gfh", "ji", "uy", "uy", "viD", "uS", "vic", "vfsc", "pfC", "Bfsj",
"gfah", "jiA", "uay", "uay", "viaD", "uaS", "viac", "vfasc", "pfaC", "Bfasj",
// other rules
"sim", "sim",
"siam", "siam",
];
debug_assert!(BEFORE.len() == AFTER.len());

Expand All @@ -80,15 +81,32 @@ fn find_samprasarana_match(p: &Prakriya, i: usize) -> Option<&'static str> {
}
}

// Deletes the vowel that follows the samprasarana vowel.
//
// Example: "uac" --> "uc"
fn run_samprasaranac_ca(p: &mut Prakriya, i_dhatu: usize) -> Option<()> {
// The code here is inelegant, but it works.
let dhatu = p.get(i_dhatu)?;
for i in 0..dhatu.len() - 1 {
if let (Some(x), Some(y)) = (dhatu.get_at(i), dhatu.get_at(i + 1)) {
if sounds::is_ac(x) && sounds::is_ac(y) {
p.run_at("6.1.108", i_dhatu, |t| t.set_at(i + 1, ""));
return Some(());
}
}
}

Some(())
}

/// Runs a hacky version of samprasarana that runs 6.1.108 (samprasAraNAcca) immediately.
///
/// TODO: properly annotate 6.1.108 and related rules here.
fn do_samprasarana(rule: Code, p: &mut Prakriya, i_dhatu: usize) -> Option<()> {
let after = find_samprasarana_match(p, i_dhatu)?;
fn do_samprasarana_for_dhatu(rule: Code, p: &mut Prakriya, i_dhatu: usize) -> Option<()> {
let new_text = find_samprasarana_match(p, i_dhatu)?;
p.run_at(rule, i_dhatu, |t| {
t.set_text(after);
t.set_text(new_text);
t.add_tag(T::FlagSamprasarana);
});
run_samprasaranac_ca(p, i_dhatu);
Some(())
}

Expand All @@ -99,6 +117,7 @@ fn do_samprasarana_for_abhyasa(rule: Code, p: &mut Prakriya, i_abhyasa: usize) -
t.set_text(after);
t.add_tag(T::FlagSamprasarana);
});
run_samprasaranac_ca(p, i_dhatu);
Some(())
}

Expand Down Expand Up @@ -156,10 +175,10 @@ pub fn run_for_dhatu_after_atidesha(p: &mut Prakriya) -> Option<()> {
let is_ve = dhatu.has_u("ve\\Y");
if dhatu.has_u("Yizva\\pa~") && n.has_u("Ric") && p.has(i_n + 1, |t| t.has_u("caN")) {
// asUzupat
do_samprasarana("6.1.18", p, i);
do_samprasarana_for_dhatu("6.1.18", p, i);
} else if dhatu.has_u_in(&["Yizva\\pa~", "syamu~", "vye\\Y"]) && n_is_yan {
// sozupyate, sesimyate, vevIyate
do_samprasarana("6.1.19", p, i);
do_samprasarana_for_dhatu("6.1.19", p, i);
} else if dhatu.has_u("vaSa~") && n_is_yan {
// vAvaSyate (exception to grahi-jyA-...)
p.step("6.1.20");
Expand Down Expand Up @@ -203,12 +222,12 @@ pub fn run_for_dhatu_after_atidesha(p: &mut Prakriya) -> Option<()> {
} else {
// General rules
if is_vaci_svapi(dhatu) && n.has_tag(T::kit) {
do_samprasarana("6.1.15", p, i);
do_samprasarana_for_dhatu("6.1.15", p, i);
} else if is_grahi_jya(dhatu) && n.is_knit() {
if dhatu.has_u("pra\\Ca~") && n.has_u("naN") {
// Per ashtadhyayi.com, skip samprasarana for praC + naN.
} else {
do_samprasarana("6.1.16", p, i);
do_samprasarana_for_dhatu("6.1.16", p, i);
if p.has(i, |t| t.has_text("uy") && t.has_u("vayi~")) {
optional_set_text("6.1.39", p, "uv");
}
Expand Down
65 changes: 51 additions & 14 deletions vidyut-prakriya/test_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,23 +996,27 @@ fn debug_text(rule: Rule) -> String {
/// Nicely prints out the given prakriyas.
pub fn print_all_prakriyas(prakriyas: &[Prakriya]) {
for p in prakriyas {
for step in p.history() {
let mut result = String::new();
for (i, t) in step.result().iter().enumerate() {
if i != 0 {
result += " + ";
}
if t.was_changed() {
result += &format!("[{}]", t.text());
} else {
result += t.text();
}
print_prakriya(p);
}
}

pub fn print_prakriya(p: &Prakriya) {
for step in p.history() {
let mut result = String::new();
for (i, t) in step.result().iter().enumerate() {
if i != 0 {
result += " + ";
}
if t.was_changed() {
result += &format!("[{}]", t.text());
} else {
result += t.text();
}
println!("{} --> {}", debug_text(step.rule()), result);
}
println!("{:?}", p.rule_choices());
println!();
println!("{} --> {}", debug_text(step.rule()), result);
}
println!("{:?}", p.rule_choices());
println!();
}

// Heavy assert helpers
Expand All @@ -1038,3 +1042,36 @@ pub fn assert_has_results(prakriyas: Vec<Prakriya>, expected: &[&str]) {

assert_eq!(expected, actuals);
}

pub fn assert_matches_prakriya(p: &Prakriya, expected: &[(Rule, Vec<&str>)]) {
let mut i_start = 0;
for (e_rule, e_result) in expected {
let i = p.history()[i_start..]
.iter()
.enumerate()
.find(|(_, x)| x.rule() == *e_rule)
.map(|x| x.0);

if i.is_none() {
print_prakriya(p);
assert!(
false,
"Could not find expected rule {:?} in prakriya.",
e_rule
);
}

i_start += i.unwrap();

let step = &p.history()[i_start];
let items: Vec<_> = step.result().iter().map(|x| x.text()).collect();
if &items != e_result {
print_prakriya(p);
assert!(
false,
"Mismatch for prakriya on code {:?}, {}.",
e_rule, i_start
);
}
}
}
37 changes: 37 additions & 0 deletions vidyut-prakriya/tests/prakriyas.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Tests that verify that a prakriya has a specific format.
//!
//! TODO: add tests from the पाणिनीयव्याकरणोदाहरणकोषः
extern crate test_utils;
use test_utils::*;
use vidyut_prakriya::args::Gana::*;
use vidyut_prakriya::args::*;
use vidyut_prakriya::Rule;

#[test]
fn bhavadi() {
let bhu = d("BU", Bhvadi);
let args = Tinanta::builder()
.dhatu(bhu)
.prayoga(Prayoga::Kartari)
.purusha(Purusha::Prathama)
.vacana(Vacana::Eka)
.lakara(Lakara::Lat)
.build()
.unwrap();
let t = Tester::default();
let ps = t.derive_tinantas(&args);
let p = ps.iter().find(|p| p.text() == "Bavati").unwrap();

use Rule::Ashtadhyayi as A;

assert_matches_prakriya(
p,
&[
(A("1.3.1"), vec!["BU"]),
(A("3.4.78"), vec!["BU", "tip"]),
(A("3.1.68"), vec!["BU", "Sap", "ti"]),
(A("7.3.84"), vec!["Bo", "a", "ti"]),
(A("6.1.78"), vec!["Bav", "a", "ti"]),
],
);
}
37 changes: 37 additions & 0 deletions vidyut-prakriya/tests/regressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ extern crate test_utils;
use test_utils::*;
use vidyut_prakriya::args::Gana::*;
use vidyut_prakriya::args::Lakara::*;
use vidyut_prakriya::args::*;
use vidyut_prakriya::Rule;

#[test]
fn ambibat() {
Expand Down Expand Up @@ -41,3 +43,38 @@ fn irshy_san_lan() {
&["Erzyiyizat", "Erzyizizat"],
);
}

/// Fixes https://github.com/ambuda-org/vidyut/issues/118
///
/// This test verifies the following:
/// - We correctly apply 6.4.108.
/// - We lengthen the dhatu's vowel with 6.4.2.
#[test]
fn jiyat_prakriya() {
let jya = d("jyA\\", Kryadi);
let args = Tinanta::builder()
.dhatu(jya)
.prayoga(Prayoga::Kartari)
.purusha(Purusha::Prathama)
.vacana(Vacana::Eka)
.lakara(Lakara::AshirLin)
.build()
.unwrap();
let t = Tester::default();
let ps = t.derive_tinantas(&args);
let p = ps.iter().find(|p| p.text() == "jIyAt").unwrap();

use Rule::Ashtadhyayi as A;

assert_matches_prakriya(
p,
&[
(A("1.3.1"), vec!["jyA\\"]),
(A("3.4.116"), vec!["jyA", "ti"]),
(A("6.1.16"), vec!["jiA", "yAs", "st"]),
(A("6.1.108"), vec!["ji", "yAs", "st"]),
(A("6.4.2"), vec!["jI", "yAs", "st"]),
(A("8.4.56"), vec!["jI", "yA", "t"]),
],
);
}

0 comments on commit c886f28

Please sign in to comment.