Skip to content

Commit

Permalink
[prakriya] Add around 250 taddhita tests
Browse files Browse the repository at this point in the history
This commit massively expands and streamlines the taddhita section.
Although more cleanup work can be done here, there's enough of a
framework that the rest of the rules are easier to fill in.
  • Loading branch information
akprasad committed Sep 29, 2023
1 parent 904564e commit 19e34ce
Show file tree
Hide file tree
Showing 57 changed files with 5,337 additions and 975 deletions.
1 change: 1 addition & 0 deletions vidyut-prakriya/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
www/static/data/
www/static/wasm/
*.log
5 changes: 4 additions & 1 deletion vidyut-prakriya/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ test_tinantas:
--hash "409c5efa5dbcebba7375732a64867f7212ee43d3b112c8c8c494099158e68a0a"
../target/release/test_tinantas \
--test-cases test-files/tinantas-san-kartari.csv \
--hash "da47a054b8f909c9496f042975b0311d77b106208eb1402d2bb81c7a35da2305"
--hash "ec5acedd0e7a5ca478c9ede25ce69daa1f1acaeb7d161c1565e7c505cd843c55"
../target/release/test_tinantas \
--test-cases test-files/tinantas-yan-kartari.csv \
--hash "71cf9817679767971c06bcb806b61f91d29402f27f158837425e02a67a5c0a01"
Expand All @@ -80,6 +80,9 @@ test_subantas:
cargo run --bin test_subantas -- \
--test-cases test-files/subantas.csv

check_rule_coverage:
./scripts/check_rule_coverage.py > report.log


# Performance
# ~~~~~~~~~~~
Expand Down
54 changes: 54 additions & 0 deletions vidyut-prakriya/scripts/check_rule_coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
from pathlib import Path
import re
import glob

RULE_OK = "✅"
RULE_UNTESTED = "⚠️ "
RULE_MISSING = "❌"

def print_legend():
print("===== Legend ======")
print(f"{RULE_OK}\t\tSutra is tested.")
print(f"{RULE_UNTESTED}\t\tSutra is implemented but untested.")
print(f"{RULE_MISSING}\t\tSutra is missing.")
print()
print("These statuses are heuristics. Verify them by checking the underlying code.")
print("===================")

base = Path(__file__).parent.parent
src = base / "src"
tests = base / "tests"

all_rules = []
with open(base / "data/sutrapatha.tsv") as f:
for line in f:
code, text = line.split('\t')
all_rules.append(code)


implemented_rules = set()
for path in glob.glob("**/*.rs", root_dir=src, recursive=True):
with open(src / path) as f:
for line in f:
if m := re.search(r'"(\d+\.\d+\.\d+)', line):
implemented_rules.add(m.group(1))

tested_rules = set()
for path in glob.glob("**/*.rs", root_dir=tests, recursive=True):
with open(tests / path) as f:
for line in f:
if m := re.search(r"(\d+_\d+_\d+)", line):
tested_rules.add(m.group(1).replace('_', '.'))

print_legend()
for rule in all_rules:
status = None
if rule in tested_rules:
status = RULE_OK
elif rule in implemented_rules:
status = RULE_UNTESTED
else:
status = RULE_MISSING
print(f"{status}\t\t{rule}")
print_legend()
38 changes: 22 additions & 16 deletions vidyut-prakriya/src/angasya.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use lazy_static::lazy_static;

lazy_static! {
static ref AC: Set = s("ac");
static ref UK: Set = s("uk");
static ref DANTYA: Set = s("tu~ v");
static ref OSHTHYA: Set = s("pu~ v");
static ref II: Set = s("i");
Expand Down Expand Up @@ -312,6 +313,7 @@ pub fn try_pratyaya_adesha(p: &mut Prakriya) -> Option<()> {

let i = len - 1;
let last = p.get_if(i, |t| t.is_pratyaya())?;
let prev = p.get(i - 1)?;

if last.has_text_in(&["yu~", "vu~"]) {
if last.has_text("yu~") {
Expand All @@ -322,13 +324,16 @@ pub fn try_pratyaya_adesha(p: &mut Prakriya) -> Option<()> {
} else if let Some(sub) = replace_pha_dha_and_others(last) {
p.op_term("7.1.2", i, op::adi(sub));
} else if last.has_adi('W') {
// Run 7.3.50 because it has no clear place otherwise.
p.op_term("7.3.50", i, |t| t.set_adi("ik"));
// Run 7.3.50 and 7.3.51 because they have no clear place otherwise.
if prev.has_suffix_in(&["is", "us", "t"]) || prev.has_antya(&*UK) {
p.op_term("7.3.51", i, |t| t.set_adi("k"));
} else {
p.op_term("7.3.50", i, |t| t.set_adi("ik"));
}

// 7.1.34 (daDyA -> daDyO) happens later on after the dhatu's vowel change (DyE -> DyA)

// -tAt substitution needs to occur early because it conditions samprasarana.
} else if p.has(i, |t| t.has_tag(T::Tin) && t.has_text_in(&["tu", "hi"])) {
// -tAt substitution needs to occur early because it conditions samprasarana.
// N is to block pit-guNa, not for replacement of the last letter.
op::optional_adesha("7.1.35", p, i, "tAta~N");
}
Expand Down Expand Up @@ -671,35 +676,36 @@ fn try_sarvadhatuke(p: &mut Prakriya) -> Option<()> {
}

/// (7.4.21 - 7.4.31)
fn try_change_dhatu_before_y(p: &mut Prakriya) -> Option<()> {
let i = p.find_first(T::Dhatu)?;
fn try_change_anga_before_y(p: &mut Prakriya) -> Option<()> {
p.debug("try_change");
let i = p.find_first_where(|t| t.is_dhatu() || t.is_pratipadika())?;
let i_n = p.find_next_where(i, |t| !t.is_empty())?;
let dhatu = p.get(i)?;
let anga = p.get(i)?;
let n = p.view(i_n)?;

let mut temp = CompactString::new("");
temp.replace_range(.., &dhatu.text);
temp.replace_range(.., &anga.text);

let akrt_sarva = !n.has_tag_in(&[T::Sarvadhatuka, T::Krt]);
let has_upasarga = i > 0 && p.has(i - 1, |t| t.has_tag(T::Upasarga));
let yi_kniti = n.has_adi('y') && n.is_knit();

if dhatu.has_u("SIN") && n.has_tag(T::Sarvadhatuka) {
if anga.has_u("SIN") && n.has_tag(T::Sarvadhatuka) {
p.op_term("7.4.21", i, op::text("Se"));
} else if dhatu.has_u("SIN") && yi_kniti {
} else if anga.has_u("SIN") && yi_kniti {
p.op_term("7.4.22", i, op::text("Say"));
p.set(i, |t| t.force_save_sthanivat());
} else if has_upasarga && yi_kniti && dhatu.has_u("Uha~\\") {
} else if has_upasarga && yi_kniti && anga.has_u("Uha~\\") {
// Example: sam[u]hyate
p.op_term("7.4.23", i, op::adi("u"));
} else if has_upasarga
&& yi_kniti
&& dhatu.has_u("i\\R")
&& anga.has_u("i\\R")
&& p.terms().last()?.has_lakshana("li~N")
{
// Example: ud[i]yAt
p.op_term("7.4.24", i, op::adi("i"));
} else if dhatu.has_antya('f') {
} else if anga.has_antya('f') {
let dhatu = p.get(i)?;
let n = p.view(i_n)?;
let is_sha_or_yak = n.has_u_in(&["Sa", "yak"]);
Expand All @@ -726,10 +732,10 @@ fn try_change_dhatu_before_y(p: &mut Prakriya) -> Option<()> {
// mantrIyati
p.op_term("7.4.27", i, op::antya("rI"));
}
} else if dhatu.has_u_in(&["GrA\\", "DmA\\"]) && n.has_u("yaN") {
} else if anga.has_u_in(&["GrA\\", "DmA\\"]) && n.has_u("yaN") {
p.op_term("7.4.31", i, op::antya("I"));
} else if n.has_adi('y') {
let sub = al::to_dirgha(dhatu.antya()?)?;
let sub = al::to_dirgha(anga.antya()?)?;
if n.has_u("cvi") {
p.op_term("7.4.26", i, op::antya(&sub.to_string()));
} else if akrt_sarva && n.is_knit() {
Expand Down Expand Up @@ -1589,7 +1595,7 @@ pub fn run_before_dvitva(p: &mut Prakriya) -> Option<()> {
p.debug("==== Guna-vrddhi ====");
guna_vrddhi::run(p);

try_change_dhatu_before_y(p);
try_change_anga_before_y(p);
try_cchvoh(p);

// Must precede ft-AdeSa (f -> ir)
Expand Down
6 changes: 3 additions & 3 deletions vidyut-prakriya/src/angasya/abhyasasya.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn try_abhyasa_lopa_and_dhatu_change_before_san(p: &mut Prakriya) -> Option<()>
Some(())
}

/// `i` is the index of an abhyasa..
/// `i` is the index of an abhyasa.
fn run_for_sani_or_cani_at_index(p: &mut Prakriya, i: usize) -> Option<()> {
const SMR_DR: &[&str] = &[
"smf",
Expand Down Expand Up @@ -161,7 +161,7 @@ fn run_for_sani_or_cani_at_index(p: &mut Prakriya, i: usize) -> Option<()> {
p.op_term("7.4.79", i, op::antya("i"));
} else if abhyasa.has_antya(&*UU) && anga.has_adi(&*PU_YAN_J) && anga.has_at(1, &*AA) {
p.op_term("7.4.80", i, op::antya("i"));
} else if anga.has_u_in(SRU_ADI) && anga.has_upadha('a') {
} else if anga.has_u_in(SRU_ADI) && p.has(i + 2, |t| !t.has_u("san")) {
// Example: sru -> sisrAvayizyati
// Note that this rule must run after guna for the upadha check to be meaningful.
p.op_optional("7.4.81", op::t(i, op::antya("i")));
Expand Down Expand Up @@ -260,7 +260,7 @@ fn try_general_rules(p: &mut Prakriya, i: usize) -> Option<()> {
let abhyasa = p.get(i)?;
if al::is_dirgha(abhyasa.antya()?) {
let val = al::to_hrasva(abhyasa.antya()?)?;
p.op_term("7.4.60", i, op::antya(&val.to_string()));
p.op_term("7.4.59", i, op::antya(&val.to_string()));
}

if p.has(i, |t| t.has_antya('f')) {
Expand Down
39 changes: 39 additions & 0 deletions vidyut-prakriya/src/angasya/asiddhavat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,8 @@ pub fn bhasya(p: &mut Prakriya) -> Option<()> {
}
} else if ani && bha.ends_with("an") {
p.step("6.4.167");
} else if bha.has_text_in(&["Atman", "aDvan"]) && next.has_u("Ka") {
p.step("6.4.169");
} else if bha.has_text("ahan") {
if next.has_u_in(&["wac", "KA"]) {
p.op_term("6.4.145", i, op::ti(""));
Expand All @@ -1005,6 +1007,43 @@ pub fn bhasya(p: &mut Prakriya) -> Option<()> {
}
} else if bha.has_antya('A') && bha.is_dhatu() {
p.op_term("6.4.140", i, op::antya(""));
} else if (bha.has_u("daRqin") && next.has_u("Pak"))
|| (bha.has_u("hastin") && next.has_u("Pak"))
|| (bha.has_u("aTarvan") && next.has_u("Wak"))
|| (bha.has_u("jihmASin") && next.has_u("Qak"))
|| (bha.has_u("vAsin") && next.has_u("PiY"))
|| (bha.has_u("BrURahan") && next.has_u("zyaY"))
|| (bha.has_u("DIvat") && next.has_u("zyaY"))
|| (bha.has_u("sarayU") && next.has_u("aR"))
|| (bha.has_u("ikzvAku") && next.has_u_in(&["aY", "aR"]))
|| (bha.has_u("mitrayu") && next.has_u("QaY"))
|| (bha.has_u("hiraRya") && next.has_u("mayaw"))
{
let code = "6.4.174";
let sub = if bha.has_u("daRqin") {
"daRqinAyana"
} else if bha.has_u("hastin") {
"hAstinAyana"
} else if bha.has_u("aTarvan") {
"aTarvaRika"
} else if bha.has_u("jihmASin") {
"jEhmASineya"
} else if bha.has_u("vAsin") {
"vAsinAyani"
} else if bha.has_u("BrURahan") {
"BrORahatya"
} else if bha.has_u("DIvat") {
"DEvatya"
} else if bha.has_u("sarayU") {
"sArava"
} else if bha.has_u("ikzvAku") {
"EkzvAka"
} else if bha.has_u("mitrayu") {
"mEtreya"
} else {
"hiraRmaya"
};
p.op(code, op::nipatana(sub));
} else if bha.has_antya(&*UU) && taddhita {
if next.has_tag(T::Qit) && !bha.has_text("kadrU") {
p.op_term("6.4.147", i, |t| t.set_antya(""));
Expand Down
64 changes: 32 additions & 32 deletions vidyut-prakriya/src/angasya/guna_vrddhi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,43 +60,43 @@ fn try_taddhita_vrddhi(p: &mut Prakriya, i: usize) -> Option<()> {
let anga = p.get(i)?;
let n = p.get_if(i + 1, |t| t.is_taddhita())?;

if anga.has_text_in(&["devikA", "SiMSapA", "dityavAh", "dIrGasatra", "Sreyas"]) {
// dAvikA, ...
let adi_ac = anga.text.find(al::is_ac)?;
p.op_term("7.3.1", i, |t| {
t.set_at(adi_ac, "A");
});

return Some(());
}

let rule = if n.has_tag_in(&[T::Yit, T::Rit]) {
Some("7.2.117")
"7.2.117"
} else if n.has_tag(T::kit) {
Some("7.2.118")
"7.2.118"
} else {
None
return None;
};

if let Some(rule) = rule {
if anga.has_u_in(DVARA_ADI) {
// dvAra -> dOvArika, ...
p.op_term("7.3.4", i, |t| {
let i_yan = t.text.rfind(|c| c == 'y' || c == 'v').expect("ok");
if t.text.get(i_yan..i_yan + 1) == Some("y") {
t.text.insert(i_yan, 'E');
} else {
t.text.insert(i_yan, 'O');
}
});
} else {
let adi_ac = anga.text.find(al::is_ac)?;
let ac = anga.get_at(adi_ac)?;
let vrddhi = al::to_vrddhi(ac)?;
p.op_term(rule, i, |t| {
t.set_at(adi_ac, vrddhi);
});
}
if anga.has_text_in(&["devikA", "SiMSapA", "dityavAh", "dIrGasatra", "Sreyas"]) {
// dAvikA, ...
let adi_ac = anga.text.find(al::is_ac)?;
p.op_term("7.3.1", i, |t| t.set_at(adi_ac, "A"));
} else if anga.has_text_in(&["kekaya", "mitrayu", "pralaya"]) {
p.op_term("7.3.2", i, |t| t.find_and_replace_text("y", "iy"));
} else if anga.text.starts_with("vy") {
// HACK: should properly be only with vi-upasarga.
// TODO: also apply for sv-, .etc.
p.op_term("7.3.3", i, |t| t.text.replace_range(..2, "vEy"));
} else if anga.has_u_in(DVARA_ADI) {
// dvAra -> dOvArika, ...
p.op_term("7.3.4", i, |t| {
let i_yan = t.text.rfind(|c| c == 'y' || c == 'v').expect("ok");
if t.text.get(i_yan..i_yan + 1) == Some("y") {
t.text.insert(i_yan, 'E');
} else {
t.text.insert(i_yan, 'O');
}
});
} else if anga.has_text("nyagroDa") {
p.op_term("7.3.5", i, |t| t.text.replace_range(..2, "nEy"));
} else {
let adi_ac = anga.text.find(al::is_ac)?;
let ac = anga.get_at(adi_ac)?;
let vrddhi = al::to_vrddhi(ac)?;
p.op_term(rule, i, |t| {
t.set_at(adi_ac, vrddhi);
});
}

Some(())
Expand Down
Loading

0 comments on commit 19e34ce

Please sign in to comment.