skrutable 2.1.3__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {skrutable-2.1.3 → skrutable-2.3.0}/PKG-INFO +1 -1
- skrutable-2.3.0/src/skrutable/__init__.py +1 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/config.json +5 -1
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/meter_identification.py +228 -51
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/meter_patterns.py +14 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/scansion.py +1 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable.egg-info/PKG-INFO +1 -1
- skrutable-2.1.3/src/skrutable/__init__.py +0 -1
- {skrutable-2.1.3 → skrutable-2.3.0}/LICENSE.md +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/README.md +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/setup.cfg +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/setup.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/config.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/generate_scheme_vectors.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/impossible_bigrams.json +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/manual.md +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/phonemes.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/run_examples.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/scheme_detection.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/scheme_maps.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/scheme_vectors.json +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/scheme_vectors_mbh.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/splitting.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/transliteration.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable/virAma_avoidance.py +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable.egg-info/SOURCES.txt +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable.egg-info/dependency_links.txt +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable.egg-info/requires.txt +0 -0
- {skrutable-2.1.3 → skrutable-2.3.0}/src/skrutable.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.3.0"
|
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
"max score" : 9,
|
|
13
13
|
"anuṣṭubh, full, both halves perfect)" : 9,
|
|
14
14
|
"anuṣṭubh, full, one half perfect, one imperfect)" : 7,
|
|
15
|
+
"anuṣṭubh, full, both halves imperfect)": 5,
|
|
16
|
+
"anuṣṭubh, full, one half perfect, one length error)": 6,
|
|
17
|
+
"anuṣṭubh, full, one half imperfect, one length error)": 4,
|
|
15
18
|
"anuṣṭubh, half, single half perfect)" : 9,
|
|
19
|
+
"anuṣṭubh, half, single half imperfect)": 5,
|
|
16
20
|
"samavṛtta, perfect" : 9,
|
|
17
21
|
"samavṛtta, imperfect (3)" : 6,
|
|
18
22
|
"samavṛtta, imperfect (2)" : 5,
|
|
@@ -22,7 +26,7 @@
|
|
|
22
26
|
"viṣamavṛtta, perfect" : 9,
|
|
23
27
|
"upajāti, perfect" : 7,
|
|
24
28
|
"upajāti, imperfect" : 6,
|
|
25
|
-
"upajāti, non-triṣṭubh, perfect" : 5,
|
|
29
|
+
"upajāti, non-triṣṭubh, perfect" : 4.5,
|
|
26
30
|
"upajāti, triṣṭubh-jagatī-saṃkara, perfect" : 4,
|
|
27
31
|
"upajāti, non-triṣṭubh, imperfect" : 3,
|
|
28
32
|
"jāti, perfect" : 8,
|
|
@@ -3,6 +3,8 @@ from skrutable import meter_patterns
|
|
|
3
3
|
from skrutable.config import load_config_dict_from_json_file
|
|
4
4
|
import re
|
|
5
5
|
from copy import copy
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Optional
|
|
6
8
|
|
|
7
9
|
# load config variables
|
|
8
10
|
config = load_config_dict_from_json_file()
|
|
@@ -12,6 +14,24 @@ default_resplit_keep_midpoint = config["default_resplit_keep_midpoint"] # e.g.
|
|
|
12
14
|
disable_non_trizwuB_upajAti = config["disable_non_trizwuB_upajAti"] # e.g. True
|
|
13
15
|
meter_scores = config["meter_scores"] # dict
|
|
14
16
|
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Diagnostic:
|
|
20
|
+
perfect_id_label: Optional[str] = None # 'pathyā', 'ma-vipulā', etc.; None if imperfect
|
|
21
|
+
imperfect_id_label: Optional[str] = None # 'asamīcīnā ma-vipulā', etc.; None if perfect or unidentified
|
|
22
|
+
failure_code: Optional[str] = None # short internal code, e.g. 'hahn_general_2'; None if perfect
|
|
23
|
+
problem_syllables: dict = field(default_factory=lambda: {'odd': [], 'even': []})
|
|
24
|
+
|
|
25
|
+
def perfect(self):
|
|
26
|
+
return self.perfect_id_label is not None
|
|
27
|
+
|
|
28
|
+
def imperfect(self):
|
|
29
|
+
return self.imperfect_id_label is not None
|
|
30
|
+
|
|
31
|
+
def length_error(self):
|
|
32
|
+
return self.failure_code in ('hypermetric', 'hypometric')
|
|
33
|
+
|
|
34
|
+
|
|
15
35
|
class VerseTester(object):
|
|
16
36
|
"""
|
|
17
37
|
Internal agent-style object.
|
|
@@ -29,6 +49,7 @@ class VerseTester(object):
|
|
|
29
49
|
self.resplit_option = default_resplit_option # string
|
|
30
50
|
self.resplit_keep_midpoint = default_resplit_keep_midpoint # bool
|
|
31
51
|
self.identification_attempt_count = 0
|
|
52
|
+
self._anuzwuB_half_cache = {} # cleared per wiggle_identify run
|
|
32
53
|
|
|
33
54
|
def combine_results(self, Vrs, new_label, new_score):
|
|
34
55
|
old_label = Vrs.meter_label or ''
|
|
@@ -55,24 +76,55 @@ class VerseTester(object):
|
|
|
55
76
|
"""
|
|
56
77
|
Accepts two strings of syllable weights (e.g. 'llglgllg').
|
|
57
78
|
Tries to match to known odd-even 'anuṣṭubh' foot pairings:
|
|
58
|
-
|
|
79
|
+
pathyā
|
|
59
80
|
vipulā (4.5 subtypes: na, ra, ma, bha, and variant bha).
|
|
60
|
-
Returns
|
|
81
|
+
Returns Diagnostic with perfect_id_label set if match found, None otherwise.
|
|
61
82
|
|
|
62
83
|
"""
|
|
63
|
-
# check even pāda
|
|
64
|
-
regex = re.compile(meter_patterns.anuzwuB_pAda['even'])
|
|
65
|
-
if not re.match(regex, even_pAda_weights):
|
|
66
|
-
return None
|
|
67
|
-
|
|
68
|
-
# check odd pāda (both 'paTyA' and 'vipulA')
|
|
69
|
-
for weights_pattern in meter_patterns.anuzwuB_pAda['odd'].keys():
|
|
70
|
-
regex = re.compile(weights_pattern)
|
|
71
|
-
if re.match(regex, odd_pAda_weights):
|
|
72
|
-
return meter_patterns.anuzwuB_pAda['odd'][weights_pattern]
|
|
73
84
|
|
|
85
|
+
cache_key = (odd_pAda_weights, even_pAda_weights)
|
|
86
|
+
if cache_key in self._anuzwuB_half_cache:
|
|
87
|
+
return self._anuzwuB_half_cache[cache_key]
|
|
88
|
+
|
|
89
|
+
# check lengths first; length_error only reported when exactly one pāda is off
|
|
90
|
+
even_len_ok = len(even_pAda_weights) == 8
|
|
91
|
+
odd_len_ok = len(odd_pAda_weights) == 8
|
|
92
|
+
if not even_len_ok and not odd_len_ok:
|
|
93
|
+
result = None # both wrong: bad split, not credible
|
|
94
|
+
elif not even_len_ok:
|
|
95
|
+
code = 'hypermetric' if len(even_pAda_weights) > 8 else 'hypometric'
|
|
96
|
+
result = Diagnostic(failure_code=code, problem_syllables={'odd': [], 'even': list(range(len(even_pAda_weights)))})
|
|
97
|
+
elif not odd_len_ok:
|
|
98
|
+
code = 'hypermetric' if len(odd_pAda_weights) > 8 else 'hypometric'
|
|
99
|
+
result = Diagnostic(failure_code=code, problem_syllables={'odd': list(range(len(odd_pAda_weights))), 'even': []})
|
|
74
100
|
else:
|
|
75
|
-
|
|
101
|
+
# check even pāda
|
|
102
|
+
if not re.match(meter_patterns.anuzwuB_pAda['even'], even_pAda_weights):
|
|
103
|
+
result = None
|
|
104
|
+
for weights_pattern, (label, problem_syls, code) in meter_patterns.anuzwuB_pAda_asamIcIna['even'].items():
|
|
105
|
+
if re.match(weights_pattern, even_pAda_weights):
|
|
106
|
+
result = Diagnostic(imperfect_id_label=label, failure_code=code, problem_syllables={'odd': [], 'even': problem_syls})
|
|
107
|
+
break
|
|
108
|
+
if result is None:
|
|
109
|
+
result = Diagnostic(imperfect_id_label='asamīcīnā, [caturthāt] pathyā yujo j', failure_code='hahn_general_4', problem_syllables={'odd': [], 'even': [4, 5, 6]})
|
|
110
|
+
else:
|
|
111
|
+
# check odd pāda (both 'paTyA' and 'vipulA')
|
|
112
|
+
result = None
|
|
113
|
+
for weights_pattern, label in meter_patterns.anuzwuB_pAda['odd'].items():
|
|
114
|
+
if re.match(weights_pattern, odd_pAda_weights):
|
|
115
|
+
result = Diagnostic(perfect_id_label=label)
|
|
116
|
+
break
|
|
117
|
+
if result is None:
|
|
118
|
+
# check for broken conditioning on odd pāda
|
|
119
|
+
for weights_pattern, (label, problem_syls, code) in meter_patterns.anuzwuB_pAda_asamIcIna['odd'].items():
|
|
120
|
+
if re.match(weights_pattern, odd_pAda_weights):
|
|
121
|
+
result = Diagnostic(imperfect_id_label=label, failure_code=code, problem_syllables={'odd': problem_syls, 'even': []})
|
|
122
|
+
break
|
|
123
|
+
if result is None:
|
|
124
|
+
result = Diagnostic(imperfect_id_label='asamīcīnā, [vipulāyām asatyām] ya[gaṇaḥ] [ayujo] caturthāt [syāt]', failure_code='hahn_paTyA', problem_syllables={'odd': [4, 5, 6], 'even': []})
|
|
125
|
+
|
|
126
|
+
self._anuzwuB_half_cache[cache_key] = result
|
|
127
|
+
return result
|
|
76
128
|
|
|
77
129
|
def test_as_anuzwuB(self, Vrs):
|
|
78
130
|
# >> def test_as_zloka(self, Vrs):
|
|
@@ -81,52 +133,99 @@ class VerseTester(object):
|
|
|
81
133
|
Determines whether first four lines of Verse's syllable_weights is anuṣṭubh.
|
|
82
134
|
Internally sets Verse parameters if identified as such.
|
|
83
135
|
Tests halves ab and cd independently, reports if either half found to be valid.
|
|
84
|
-
Returns
|
|
136
|
+
Returns Diagnostic if anuṣṭubh, or None if not.
|
|
85
137
|
"""
|
|
86
138
|
|
|
87
139
|
w_p = Vrs.syllable_weights.split('\n') # weights by pāda
|
|
88
140
|
|
|
89
141
|
# make sure full four pādas
|
|
90
142
|
try: w_p[3]
|
|
91
|
-
except IndexError: return
|
|
143
|
+
except IndexError: return None
|
|
92
144
|
|
|
93
145
|
# test each half
|
|
94
|
-
|
|
95
|
-
|
|
146
|
+
pAdas_ab_result = self.test_as_anuzwuB_half(w_p[0], w_p[1])
|
|
147
|
+
pAdas_cd_result = self.test_as_anuzwuB_half(w_p[2], w_p[3])
|
|
148
|
+
|
|
149
|
+
if pAdas_ab_result is None and pAdas_cd_result is None:
|
|
150
|
+
ardham_eva_result = self.test_as_anuzwuB_half(w_p[0] + w_p[1], w_p[2] + w_p[3])
|
|
151
|
+
if ardham_eva_result is None:
|
|
152
|
+
return None
|
|
153
|
+
if ardham_eva_result.perfect():
|
|
154
|
+
Vrs.meter_label = f"anuṣṭubh (ardham eva: {ardham_eva_result.perfect_id_label})"
|
|
155
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, half, single half perfect)"]
|
|
156
|
+
Vrs.diagnostic = ardham_eva_result
|
|
157
|
+
return ardham_eva_result
|
|
158
|
+
elif ardham_eva_result.imperfect():
|
|
159
|
+
Vrs.meter_label = f"anuṣṭubh (ardham eva: {ardham_eva_result.imperfect_id_label})"
|
|
160
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, half, single half imperfect)"]
|
|
161
|
+
Vrs.diagnostic = ardham_eva_result
|
|
162
|
+
return ardham_eva_result
|
|
163
|
+
else:
|
|
164
|
+
return None
|
|
96
165
|
|
|
97
|
-
|
|
166
|
+
if pAdas_ab_result is None or pAdas_cd_result is None:
|
|
167
|
+
return None
|
|
98
168
|
|
|
99
169
|
# both halves perfect
|
|
100
170
|
|
|
101
|
-
if
|
|
102
|
-
Vrs.meter_label = "anuṣṭubh (1,2:
|
|
171
|
+
if pAdas_ab_result.perfect() and pAdas_cd_result.perfect():
|
|
172
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.perfect_id_label}; 3,4: {pAdas_cd_result.perfect_id_label})"
|
|
103
173
|
Vrs.identification_score = meter_scores["anuṣṭubh, full, both halves perfect)"]
|
|
104
|
-
|
|
174
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
175
|
+
return pAdas_ab_result
|
|
105
176
|
|
|
106
177
|
# one half imperfect
|
|
107
178
|
|
|
108
|
-
elif
|
|
109
|
-
Vrs.meter_label = "anuṣṭubh (1,2:
|
|
179
|
+
elif pAdas_ab_result.imperfect() and pAdas_cd_result.perfect():
|
|
180
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.imperfect_id_label}; 3,4: {pAdas_cd_result.perfect_id_label})"
|
|
110
181
|
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half perfect, one imperfect)"]
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
182
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
183
|
+
return pAdas_ab_result
|
|
184
|
+
elif pAdas_ab_result.perfect() and pAdas_cd_result.imperfect():
|
|
185
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.perfect_id_label}; 3,4: {pAdas_cd_result.imperfect_id_label})"
|
|
114
186
|
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half perfect, one imperfect)"]
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Vrs.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
187
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
188
|
+
return pAdas_cd_result
|
|
189
|
+
|
|
190
|
+
# both halves imperfect
|
|
191
|
+
|
|
192
|
+
elif pAdas_ab_result.imperfect() and pAdas_cd_result.imperfect():
|
|
193
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.imperfect_id_label}; 3,4: {pAdas_cd_result.imperfect_id_label})"
|
|
194
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, full, both halves imperfect)"]
|
|
195
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
196
|
+
return pAdas_ab_result
|
|
197
|
+
|
|
198
|
+
# one half perfect, one length error
|
|
199
|
+
|
|
200
|
+
elif pAdas_ab_result.length_error() and pAdas_cd_result.perfect():
|
|
201
|
+
code = pAdas_ab_result.failure_code
|
|
202
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: ?? {code}; 3,4: {pAdas_cd_result.perfect_id_label})"
|
|
203
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half perfect, one length error)"]
|
|
204
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
205
|
+
return pAdas_cd_result
|
|
206
|
+
elif pAdas_ab_result.perfect() and pAdas_cd_result.length_error():
|
|
207
|
+
code = pAdas_cd_result.failure_code
|
|
208
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.perfect_id_label}; 3,4: ?? {code})"
|
|
209
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half perfect, one length error)"]
|
|
210
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
211
|
+
return pAdas_ab_result
|
|
212
|
+
|
|
213
|
+
# one half imperfect, one length error
|
|
214
|
+
|
|
215
|
+
elif pAdas_ab_result.length_error() and pAdas_cd_result.imperfect():
|
|
216
|
+
code = pAdas_ab_result.failure_code
|
|
217
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: ?? {code}; 3,4: {pAdas_cd_result.imperfect_id_label})"
|
|
218
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half imperfect, one length error)"]
|
|
219
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
220
|
+
return pAdas_cd_result
|
|
221
|
+
elif pAdas_ab_result.imperfect() and pAdas_cd_result.length_error():
|
|
222
|
+
code = pAdas_cd_result.failure_code
|
|
223
|
+
Vrs.meter_label = f"anuṣṭubh (1,2: {pAdas_ab_result.imperfect_id_label}; 3,4: ?? {code})"
|
|
224
|
+
Vrs.identification_score = meter_scores["anuṣṭubh, full, one half imperfect, one length error)"]
|
|
225
|
+
Vrs.diagnostic = {'ab': pAdas_ab_result, 'cd': pAdas_cd_result}
|
|
226
|
+
return pAdas_ab_result
|
|
227
|
+
|
|
228
|
+
return None
|
|
130
229
|
|
|
131
230
|
def count_pAdasamatva(self, Vrs):
|
|
132
231
|
"""
|
|
@@ -188,23 +287,61 @@ class VerseTester(object):
|
|
|
188
287
|
meter_label += ' [%d: %s]' % ( len(w_to_id), g_to_id )
|
|
189
288
|
|
|
190
289
|
score = meter_scores["samavṛtta, perfect"]
|
|
290
|
+
imperfect_note = None
|
|
191
291
|
|
|
192
292
|
if self.pAdasamatva_count == 3:
|
|
193
|
-
|
|
293
|
+
imperfect_note = "? 3 eva pādāḥ yuktāḥ"
|
|
294
|
+
meter_label += " (%s)" % imperfect_note
|
|
194
295
|
score = meter_scores["samavṛtta, imperfect (3)"]
|
|
195
296
|
elif self.pAdasamatva_count == 2:
|
|
196
|
-
|
|
297
|
+
imperfect_note = "? 2 eva pādāḥ yuktāḥ"
|
|
298
|
+
meter_label += " (%s)" % imperfect_note
|
|
197
299
|
score = meter_scores["samavṛtta, imperfect (2)"]
|
|
198
300
|
elif self.pAdasamatva_count == 0:
|
|
199
|
-
|
|
301
|
+
imperfect_note = "1 eva pādaḥ"
|
|
302
|
+
meter_label += " (%s)" % imperfect_note
|
|
200
303
|
score = meter_scores["samavṛtta, quarter, perfect"]
|
|
201
304
|
|
|
202
305
|
# experimental penalty, can later incorporate into config meter_scores
|
|
203
|
-
if
|
|
306
|
+
if "ajñātasamavṛtta" in meter_label:
|
|
204
307
|
score -= 2
|
|
205
308
|
|
|
309
|
+
# build diagnostic
|
|
310
|
+
problem_syllables = {}
|
|
311
|
+
canonical = w_to_id # includes final anceps
|
|
312
|
+
for pada_num, w in enumerate(wbp[:4], start=1):
|
|
313
|
+
if w == canonical:
|
|
314
|
+
problem_syllables[pada_num] = []
|
|
315
|
+
elif len(w) != len(canonical):
|
|
316
|
+
problem_syllables[pada_num] = list(range(len(w)))
|
|
317
|
+
else:
|
|
318
|
+
# compare position-by-position; final anceps always matches
|
|
319
|
+
problem_syllables[pada_num] = [
|
|
320
|
+
j for j in range(len(w) - 1) if w[j] != canonical[j]
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
# collect any hyper/hypometric notes for imperfect_id_label
|
|
324
|
+
length_notes = []
|
|
325
|
+
for pada_num, w in enumerate(wbp[:4], start=1):
|
|
326
|
+
if len(w) > len(canonical):
|
|
327
|
+
length_notes.append("pāda %d hypermetric" % pada_num)
|
|
328
|
+
elif len(w) < len(canonical):
|
|
329
|
+
length_notes.append("pāda %d hypometric" % pada_num)
|
|
330
|
+
|
|
331
|
+
if imperfect_note is None:
|
|
332
|
+
base_label = meter_label
|
|
333
|
+
diagnostic = Diagnostic(perfect_id_label=base_label, problem_syllables=problem_syllables)
|
|
334
|
+
else:
|
|
335
|
+
full_imperfect = imperfect_note
|
|
336
|
+
if length_notes:
|
|
337
|
+
full_imperfect += "; " + "; ".join(length_notes)
|
|
338
|
+
diagnostic = Diagnostic(imperfect_id_label=full_imperfect, problem_syllables=problem_syllables)
|
|
339
|
+
|
|
206
340
|
# may tie with pre-existing result (e.g., upajāti)
|
|
341
|
+
old_score = Vrs.identification_score
|
|
207
342
|
self.combine_results(Vrs, new_label=meter_label, new_score=score)
|
|
343
|
+
if score >= old_score:
|
|
344
|
+
Vrs.diagnostic = diagnostic
|
|
208
345
|
|
|
209
346
|
|
|
210
347
|
|
|
@@ -241,19 +378,25 @@ class VerseTester(object):
|
|
|
241
378
|
Vrs.identification_score = meter_scores["ardhasamavṛtta, perfect, unknown"]
|
|
242
379
|
|
|
243
380
|
Vrs.meter_label = meter_label
|
|
381
|
+
Vrs.diagnostic = Diagnostic(perfect_id_label=meter_label, problem_syllables={1: [], 2: [], 3: [], 4: []})
|
|
244
382
|
|
|
245
383
|
|
|
246
384
|
def evaluate_upajAti(self, Vrs):
|
|
247
385
|
# sufficient length similarity already assured, now just evaluate
|
|
248
386
|
|
|
249
387
|
wbp = Vrs.syllable_weights.split('\n') # weights by pāda
|
|
250
|
-
|
|
388
|
+
wbp_lens_orig = [ len(line) for line in wbp ]
|
|
389
|
+
wbp_lens = list(wbp_lens_orig)
|
|
251
390
|
gs_to_id = Vrs.gaRa_abbreviations.split('\n')
|
|
252
391
|
|
|
253
392
|
# special exception for triṣṭubh-jagatī mix
|
|
254
393
|
# see Karashima 2016 "The Triṣṭubh-Jagatī Verses in the Saddharmapuṇḍarīka"
|
|
255
394
|
unique_sorted_lens = list(set(wbp_lens))
|
|
256
395
|
unique_sorted_lens.sort()
|
|
396
|
+
|
|
397
|
+
# track which original pada indices (0-based) are excluded
|
|
398
|
+
excluded_indices = []
|
|
399
|
+
|
|
257
400
|
if unique_sorted_lens != [11, 12]:
|
|
258
401
|
|
|
259
402
|
# if imperfect, exclude all info for lines of non-majority lengths
|
|
@@ -266,6 +409,7 @@ class VerseTester(object):
|
|
|
266
409
|
for i, weights in enumerate(wbp):
|
|
267
410
|
if len(weights) != most_freq_pAda_len:
|
|
268
411
|
to_exclude.append(i)
|
|
412
|
+
excluded_indices = list(to_exclude)
|
|
269
413
|
for i in reversed(to_exclude): # delete in descending index order, avoid index errors
|
|
270
414
|
del wbp[i]
|
|
271
415
|
del wbp_lens[i]
|
|
@@ -339,7 +483,7 @@ class VerseTester(object):
|
|
|
339
483
|
else:
|
|
340
484
|
score = meter_scores["none found"]
|
|
341
485
|
|
|
342
|
-
|
|
486
|
+
imperfect_note = None
|
|
343
487
|
overall_meter_label = "upajāti %s: %s" % (
|
|
344
488
|
family,
|
|
345
489
|
combined_meter_labels
|
|
@@ -349,9 +493,39 @@ class VerseTester(object):
|
|
|
349
493
|
len(wbp_lens) != 4 and
|
|
350
494
|
unique_sorted_lens != [11, 12]
|
|
351
495
|
): # not perfect and also not triṣṭubh-jagatī-saṃkara
|
|
352
|
-
|
|
496
|
+
imperfect_note = "? %d eva pādāḥ yuktāḥ" % len(wbp_lens)
|
|
497
|
+
overall_meter_label += " (%s)" % imperfect_note
|
|
498
|
+
|
|
499
|
+
# build diagnostic: problem_syllables keyed 1–4
|
|
500
|
+
# included pādas: no positional errors (upajāti pādas are heterogeneous by design)
|
|
501
|
+
# excluded pādas: hyper/hypometric
|
|
502
|
+
most_freq_len = wbp_lens[0] if wbp_lens else None
|
|
503
|
+
problem_syllables = {}
|
|
504
|
+
length_notes = []
|
|
505
|
+
for pada_num in range(1, 5):
|
|
506
|
+
orig_len = wbp_lens_orig[pada_num - 1] if pada_num - 1 < len(wbp_lens_orig) else None
|
|
507
|
+
if pada_num - 1 in excluded_indices:
|
|
508
|
+
problem_syllables[pada_num] = list(range(orig_len)) if orig_len is not None else []
|
|
509
|
+
if orig_len is not None and most_freq_len is not None:
|
|
510
|
+
if orig_len > most_freq_len:
|
|
511
|
+
length_notes.append("pāda %d hypermetric" % pada_num)
|
|
512
|
+
else:
|
|
513
|
+
length_notes.append("pāda %d hypometric" % pada_num)
|
|
514
|
+
else:
|
|
515
|
+
problem_syllables[pada_num] = []
|
|
516
|
+
|
|
517
|
+
if imperfect_note is None:
|
|
518
|
+
diagnostic = Diagnostic(perfect_id_label=overall_meter_label, problem_syllables=problem_syllables)
|
|
519
|
+
else:
|
|
520
|
+
full_imperfect = imperfect_note
|
|
521
|
+
if length_notes:
|
|
522
|
+
full_imperfect += "; " + "; ".join(length_notes)
|
|
523
|
+
diagnostic = Diagnostic(imperfect_id_label=full_imperfect, problem_syllables=problem_syllables)
|
|
353
524
|
|
|
525
|
+
old_score = Vrs.identification_score
|
|
354
526
|
self.combine_results(Vrs, overall_meter_label, score)
|
|
527
|
+
if score >= old_score:
|
|
528
|
+
Vrs.diagnostic = diagnostic
|
|
355
529
|
|
|
356
530
|
|
|
357
531
|
def is_vizamavftta(self, Vrs):
|
|
@@ -363,6 +537,7 @@ class VerseTester(object):
|
|
|
363
537
|
if (gs_to_id[0],gs_to_id[1],gs_to_id[2],gs_to_id[3]) == (a, b, c, d):
|
|
364
538
|
Vrs.identification_score = meter_scores["viṣamavṛtta, perfect"]
|
|
365
539
|
Vrs.meter_label = meter_patterns.vizamavftta_by_4_tuple[(a, b, c, d)]
|
|
540
|
+
Vrs.diagnostic = Diagnostic(perfect_id_label=Vrs.meter_label, problem_syllables={1: [], 2: [], 3: [], 4: []})
|
|
366
541
|
return True
|
|
367
542
|
|
|
368
543
|
else:
|
|
@@ -494,6 +669,7 @@ class VerseTester(object):
|
|
|
494
669
|
else: # if all four pAdas proven valid, i.e., if no breaks
|
|
495
670
|
Vrs.meter_label = jAti_name + " (%s)" % str(std_pattern)[1:-1]
|
|
496
671
|
Vrs.identification_score = meter_scores["jāti, perfect"]
|
|
672
|
+
Vrs.diagnostic = Diagnostic(perfect_id_label=Vrs.meter_label, problem_syllables={1: [], 2: [], 3: [], 4: []})
|
|
497
673
|
|
|
498
674
|
# should be combining results in case of previous match
|
|
499
675
|
|
|
@@ -540,8 +716,8 @@ class VerseTester(object):
|
|
|
540
716
|
|
|
541
717
|
# anuzwuB
|
|
542
718
|
|
|
543
|
-
|
|
544
|
-
if
|
|
719
|
+
anuzwuB_diagnostic = self.test_as_anuzwuB(Vrs) # Diagnostic if successful, None if not
|
|
720
|
+
if anuzwuB_diagnostic and Vrs.identification_score == meter_scores["max score"]:
|
|
545
721
|
return 1
|
|
546
722
|
|
|
547
723
|
# samavftta, upajAti, vizamavftta, ardhasamavftta
|
|
@@ -557,7 +733,7 @@ class VerseTester(object):
|
|
|
557
733
|
|
|
558
734
|
success_jAti = self.test_as_jAti(Vrs)
|
|
559
735
|
|
|
560
|
-
if
|
|
736
|
+
if anuzwuB_diagnostic or success_samavftta_etc or success_jAti:
|
|
561
737
|
return 1
|
|
562
738
|
else:
|
|
563
739
|
return 0
|
|
@@ -613,6 +789,7 @@ class MeterIdentifier(object):
|
|
|
613
789
|
pAda_brs, quarter_len):
|
|
614
790
|
"""Returns a list for MeterIdentifier.Verses_found"""
|
|
615
791
|
|
|
792
|
+
self._anuzwuB_half_cache = {}
|
|
616
793
|
pos_iterators = {}
|
|
617
794
|
for k in ['ab', 'bc', 'cd']:
|
|
618
795
|
if (
|
|
@@ -47,6 +47,20 @@ anuzwuB_pAda = {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
anuzwuB_pAda_asamIcIna = {
|
|
51
|
+
'odd' : {
|
|
52
|
+
'^.ll.{5}$' : ('asamīcīnā, na prathamāt snau', [1, 2], 'hahn_general_2'), # syllables 2–3 both light
|
|
53
|
+
'^.{4}ggg.$' : ('asamīcīnā, ma-vipulāyāḥ paścād raḥ syāt', [1, 2, 3], 'hahn_vipulA_3'), # ma-vipulā conditioning violated
|
|
54
|
+
'^.{4}gll.$' : ('asamīcīnā, bha-vipulāyāḥ paścād raḥ syāt', [1, 2, 3], 'hahn_vipulA_2'), # bha-vipulā conditioning violated
|
|
55
|
+
'^.{3}llll.$' : ('asamīcīnā, na-vipulāyāḥ paścād guruḥ syāt', [3], 'hahn_vipulA_1'), # na-vipulā conditioning violated
|
|
56
|
+
'^.{3}lglg.$' : ('asamīcīnā, ra-vipulāyāḥ paścād guruḥ syāt', [3], 'hahn_vipulA_4'), # ra-vipulā conditioning violated
|
|
57
|
+
},
|
|
58
|
+
'even' : {
|
|
59
|
+
'^.ll.{5}$' : ('asamīcīnā, na prathamāt snau', [1, 2], 'hahn_general_2'), # syllables 2–3 both light
|
|
60
|
+
'^.glg.{4}$' : ('asamīcīnā, [na] dvitīyacaturthayo raḥ', [1, 2, 3], 'hahn_general_3'), # ra-gaṇa at syllables 2–4
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
"""
|
|
51
65
|
samavṛtta
|
|
52
66
|
|
|
@@ -34,6 +34,7 @@ class Verse(object):
|
|
|
34
34
|
self.gaRa_abbreviations = None # string, may contain newlines
|
|
35
35
|
self.meter_label = None # string
|
|
36
36
|
self.identification_score = 0 # int
|
|
37
|
+
self.diagnostic = None # Diagnostic or dict of Diagnostics, set by meter_identification
|
|
37
38
|
|
|
38
39
|
def summarize(self,
|
|
39
40
|
show_weights=True, show_morae=True, show_gaRas=True, # part_A
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.1.3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|