From 856a3019ed9850bbd640cc1c579b119afcf34962 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Thu, 4 Jun 2026 15:12:29 +0530 Subject: [PATCH 01/29] feat(ta): add cardinal TN tagger, verbalizer and test cases Signed-off-by: surendran-246 --- .../text_normalization/ta/__init__.py | 0 .../ta/data/numbers/digit.tsv | 9 + .../ta/data/numbers/teens_and_ties.tsv | 18 ++ .../ta/data/numbers/zero.tsv | 1 + .../text_normalization/ta/graph_utils.py | 225 ++++++++++++++++++ .../text_normalization/ta/taggers/__init__.py | 0 .../text_normalization/ta/taggers/cardinal.py | 34 +++ .../text_normalization/ta/utils.py | 74 ++++++ .../ta/verbalizers/__init__.py | 0 .../ta/verbalizers/cardinal.py | 34 +++ test_cases_cardinal.txt | 28 +++ 11 files changed, 423 insertions(+) create mode 100644 nemo_text_processing/text_normalization/ta/__init__.py create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv create mode 100644 nemo_text_processing/text_normalization/ta/graph_utils.py create mode 100644 nemo_text_processing/text_normalization/ta/taggers/__init__.py create mode 100644 nemo_text_processing/text_normalization/ta/taggers/cardinal.py create mode 100644 nemo_text_processing/text_normalization/ta/utils.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/__init__.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py create mode 100644 test_cases_cardinal.txt diff --git a/nemo_text_processing/text_normalization/ta/__init__.py b/nemo_text_processing/text_normalization/ta/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv new file mode 100644 index 000000000..d61749cbd --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv @@ -0,0 +1,9 @@ +1 ஒன்று +2 இரண்டு +3 மூன்று +4 நான்கு +5 ஐந்து +6 ஆறு +7 ஏழு +8 எட்டு +9 ஒன்பது \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv new file mode 100644 index 000000000..51bfd3800 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv @@ -0,0 +1,18 @@ +10 பத்து +11 பதினொன்று +12 பன்னிரண்டு +13 பதின்மூன்று +14 பதினான்கு +15 பதினைந்து +16 பதினாறு +17 பதினேழு +18 பதினெட்டு +19 பத்தொன்பது +20 இருபது +30 முப்பது +40 நாற்பது +50 ஐம்பது +60 அறுபது +70 எழுபது +80 எண்பது +90 தொண்ணூறு \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv new file mode 100644 index 000000000..13de36a14 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv @@ -0,0 +1 @@ +0 சுழியம் \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py new file mode 100644 index 000000000..e8543d9ad --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -0,0 +1,225 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright 2015 and onwards Google, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +import string +from pathlib import Path +from typing import Dict + +import pynini +from pynini import Far +from pynini.export import export +from pynini.lib import byte, pynutil, utf8 + +NEMO_CHAR = utf8.VALID_UTF8_CHAR +NEMO_DIGIT = byte.DIGIT + +NEMO_HI_DIGIT = pynini.union("०", "१", "२", "३", "४", "५", "६", "७", "८", "९").optimize() +NEMO_HI_NON_ZERO = pynini.union("१", "२", "३", "४", "५", "६", "७", "८", "९").optimize() +NEMO_HI_ZERO = "०" +# Combined Hindi and Arabic digits for graphs that need to accept both +NEMO_ALL_DIGIT = pynini.union(NEMO_HI_DIGIT, NEMO_DIGIT).optimize() +NEMO_ALL_ZERO = pynini.union("०", "0").optimize() +NEMO_ALL_NON_ZERO = pynini.union(NEMO_HI_NON_ZERO, "1", "2", "3", "4", "5", "6", "7", "8", "9").optimize() + +HI_DEDH = "डेढ़" # 1.5 +HI_DHAI = "ढाई" # 2.5 +HI_SAVVA = "सवा" # quarter more (1.25) +HI_SADHE = "साढ़े" # half more (X.5) +HI_PAUNE = "पौने" # quarter less (0.75) + +# Hindi decimal representations +HI_POINT_FIVE = ".५" # .5 +HI_ONE_POINT_FIVE = "१.५" # 1.5 +HI_TWO_POINT_FIVE = "२.५" # 2.5 +HI_DECIMAL_25 = ".२५" # .25 +HI_DECIMAL_75 = ".७५" # .75 + +# Arabic/English decimal representations +EN_POINT_FIVE = ".5" +EN_ONE_POINT_FIVE = "1.5" +EN_TWO_POINT_FIVE = "2.5" +EN_DECIMAL_25 = ".25" +EN_DECIMAL_75 = ".75" + +# Combined Hindi and English decimal patterns +POINT_FIVE = pynini.union(HI_POINT_FIVE, EN_POINT_FIVE).optimize() +ONE_POINT_FIVE = pynini.union(HI_ONE_POINT_FIVE, EN_ONE_POINT_FIVE).optimize() +TWO_POINT_FIVE = pynini.union(HI_TWO_POINT_FIVE, EN_TWO_POINT_FIVE).optimize() +DECIMAL_25 = pynini.union(HI_DECIMAL_25, EN_DECIMAL_25).optimize() +DECIMAL_75 = pynini.union(HI_DECIMAL_75, EN_DECIMAL_75).optimize() + +# Symbol constants +HI_BY = "बाई" +LOWERCASE_X = "x" +UPPERCASE_X = "X" +ASTERISK = "*" +HYPHEN = "-" +SLASH = "/" +COMMA = "," +PERIOD = "." +HI_PERIOD = "।" + +NEMO_LOWER = pynini.union(*string.ascii_lowercase).optimize() +NEMO_UPPER = pynini.union(*string.ascii_uppercase).optimize() +NEMO_ALPHA = pynini.union(NEMO_LOWER, NEMO_UPPER).optimize() +NEMO_HEX = pynini.union(*string.hexdigits).optimize() +NEMO_NON_BREAKING_SPACE = u"\u00a0" +NEMO_SPACE = " " +NEMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", u"\u00a0").optimize() +NEMO_NOT_SPACE = pynini.difference(NEMO_CHAR, NEMO_WHITE_SPACE).optimize() +NEMO_NOT_QUOTE = pynini.difference(NEMO_CHAR, r'"').optimize() +TO_LOWER = pynini.union(*[pynini.cross(x, y) for x, y in zip(string.ascii_uppercase, string.ascii_lowercase)]) +TO_UPPER = pynini.invert(TO_LOWER) +NEMO_SIGMA = pynini.closure(NEMO_CHAR) + + +delete_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE)) +delete_zero_or_one_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE, 0, 1)) +insert_space = pynutil.insert(" ") +delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") +delete_preserve_order = pynini.closure( + pynutil.delete(" preserve_order: true") + | (pynutil.delete(" field_order: \"") + NEMO_NOT_QUOTE + pynutil.delete("\"")) +) + + +MIN_NEG_WEIGHT = -0.0001 +MIN_POS_WEIGHT = 0.0001 +INPUT_CASED = "cased" +INPUT_LOWER_CASED = "lower_cased" +MINUS = pynini.union(" ऋणात्मक ", " ऋणात्मक ").optimize() + + +def capitalized_input_graph( + graph: 'pynini.FstLike', original_graph_weight: float = None, capitalized_graph_weight: float = None +) -> 'pynini.FstLike': + """ + Allow graph input to be capitalized, e.g. for ITN) + + Args: + graph: FstGraph + original_graph_weight: weight to add to the original `graph` + capitalized_graph_weight: weight to add to the capitalized graph + """ + capitalized_graph = pynini.compose(TO_LOWER + NEMO_SIGMA, graph).optimize() + + if original_graph_weight is not None: + graph = pynutil.add_weight(graph, weight=original_graph_weight) + + if capitalized_graph_weight is not None: + capitalized_graph = pynutil.add_weight(capitalized_graph, weight=capitalized_graph_weight) + + graph |= capitalized_graph + return graph + + +def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): + """ + Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. + + Args: + file_name: exported file name + graphs: Mapping of a rule name and Pynini WFST graph to be exported + """ + exporter = export.Exporter(file_name) + for rule, graph in graphs.items(): + exporter[rule] = graph.optimize() + exporter.close() + logging.info(f'Created {file_name}') + + +def convert_space(fst) -> 'pynini.FstLike': + """ + Converts space to nonbreaking space. + Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty" + This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it. + + Args: + fst: input fst + + Returns output fst where breaking spaces are converted to non breaking spaces + """ + return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) + + +class GraphFst: + """ + Base class for all grammar fsts. + + Args: + name: name of grammar class + kind: either 'classify' or 'verbalize' + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, name: str, kind: str, deterministic: bool = True): + self.name = name + self.kind = kind + self._fst = None + self.deterministic = deterministic + + self.far_path = Path(os.path.dirname(__file__) + '/grammars/' + kind + '/' + name + '.far') + if self.far_exist(): + self._fst = Far(self.far_path, mode="r", arc_type="standard", far_type="default").get_fst() + + def far_exist(self) -> bool: + """ + Returns true if FAR can be loaded + """ + return self.far_path.exists() + + @property + def fst(self) -> 'pynini.FstLike': + return self._fst + + @fst.setter + def fst(self, fst): + self._fst = fst + + def add_tokens(self, fst) -> 'pynini.FstLike': + """ + Wraps class name around to given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + return pynutil.insert(f"{self.name} {{ ") + fst + pynutil.insert(" }") + + def delete_tokens(self, fst) -> 'pynini.FstLike': + """ + Deletes class name wrap around output of given fst + + Args: + fst: input fst + + Returns: + Fst: fst + """ + res = ( + pynutil.delete(f"{self.name}") + + delete_space + + pynutil.delete("{") + + delete_space + + fst + + delete_space + + pynutil.delete("}") + ) + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) diff --git a/nemo_text_processing/text_normalization/ta/taggers/__init__.py b/nemo_text_processing/text_normalization/ta/taggers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py new file mode 100644 index 000000000..f336995de --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -0,0 +1,34 @@ +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst +from nemo_text_processing.text_normalization.ta.utils import get_abs_path + + +class CardinalFst(GraphFst): + """ + Classifies cardinal numbers, e.g. 5 -> cardinal { integer: "" } + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + + # Load the three data files as transducers (number -> word) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + teens_and_ties = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) + + # TODO 1: Combine the three transducers into one grammar so it accepts + # a single digit (1-9), zero (0), OR a two-digit number. + # Hint: the union operator in pynini is | + graph = digit | zero | teens_and_ties # <-- complete this + graph = graph.optimize() + + # TODO 2: Wrap the word in the token field the verbalizer expects: + # produce integer: "" + # Hint: pynutil.insert("text") writes literal text into the output. + final_graph = pynutil.insert('integer: "') + graph + pynutil.insert('"') + + # add_tokens() turns it into: cardinal { integer: "" } + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() diff --git a/nemo_text_processing/text_normalization/ta/utils.py b/nemo_text_processing/text_normalization/ta/utils.py new file mode 100644 index 000000000..5d314506e --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/utils.py @@ -0,0 +1,74 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import csv +import os +import pynini + + +def get_abs_path(rel_path): + """ + Get absolute path + + Args: + rel_path: relative path to this file + + Returns absolute path + """ + return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path + + +def load_labels(abs_path): + """ + loads relative path file as dictionary + + Args: + abs_path: absolute path + + Returns dictionary of mappings + """ + label_tsv = open(abs_path, encoding="utf-8") + labels = list(csv.reader(label_tsv, delimiter="\t")) + label_tsv.close() + return labels + + +def augment_labels_with_punct_at_end(labels): + """ + augments labels: if key ends on a punctuation that value does not have, add a new label + where the value maintains the punctuation + + Args: + labels : input labels + Returns: + additional labels + """ + res = [] + for label in labels: + if len(label) > 1: + if label[0][-1] == "." and label[1][-1] != ".": + res.append([label[0], label[1] + "."] + label[2:]) + return res + + +def apply_fst(text, fst): + """Given a string input, returns the output string + produced by traversing the path with lowest weight. + If no valid path accepts input string, returns an + error. + """ + try: + print(pynini.shortestpath(text @ fst).string()) + except pynini.FstOpError: + print(f"Error: No valid output with given input: '{text}'") diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py b/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py new file mode 100644 index 000000000..9dbde23e2 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py @@ -0,0 +1,34 @@ +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import ( + NEMO_NOT_QUOTE, + GraphFst, + delete_space, +) + + +class CardinalFst(GraphFst): + """ + Verbalizes cardinals, e.g. cardinal { integer: "" } -> + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic) + + # TODO 3: Remove integer: " before the word and the closing " after it, + # keeping the word itself. + # Hint: pynutil.delete("text") deletes literal text; + # NEMO_NOT_QUOTE matches any character that is not a quote. + graph = ( + pynutil.delete("integer:") + + delete_space + + pynutil.delete('"') + + pynini.closure(NEMO_NOT_QUOTE, 1) # <-- keep the word (1 or more non-quote chars) + + pynutil.delete('"') + ) + + # delete_tokens() removes the surrounding cardinal { ... } + delete_tokens = self.delete_tokens(graph) + self.fst = delete_tokens.optimize() + \ No newline at end of file diff --git a/test_cases_cardinal.txt b/test_cases_cardinal.txt new file mode 100644 index 000000000..c3da1bbbc --- /dev/null +++ b/test_cases_cardinal.txt @@ -0,0 +1,28 @@ +0~சுழியம் +1~ஒன்று +2~இரண்டு +3~மூன்று +4~நான்கு +5~ஐந்து +6~ஆறு +7~ஏழு +8~எட்டு +9~ஒன்பது +10~பத்து +11~பதினொன்று +12~பன்னிரண்டு +13~பதின்மூன்று +14~பதினான்கு +15~பதினைந்து +16~பதினாறு +17~பதினேழு +18~பதினெட்டு +19~பத்தொன்பது +20~இருபது +30~முப்பது +40~நாற்பது +50~ஐம்பது +60~அறுபது +70~எழுபது +80~எண்பது +90~தொண்ணூறு \ No newline at end of file From 7ebabdfaa68cf734bd959637f8a6b624625daf4c Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Fri, 5 Jun 2026 13:52:40 +0530 Subject: [PATCH 02/29] feat(ta): address review comments Signed-off-by: surendran-246 --- .../text_normalization/ta/__init__.py | 13 ++++ .../text_normalization/ta/data/__init__.py | 13 ++++ .../ta/data/numbers/teens_and_ties.tsv | 74 ++++++++++++++++++- .../text_normalization/ta/graph_utils.py | 3 +- .../text_normalization/ta/taggers/__init__.py | 13 ++++ .../text_normalization/ta/taggers/cardinal.py | 34 ++++++--- .../ta/verbalizers/__init__.py | 13 ++++ .../ta/verbalizers/cardinal.py | 30 ++++++-- test_cases_cardinal.txt | 74 ++++++++++++++++++- 9 files changed, 244 insertions(+), 23 deletions(-) create mode 100644 nemo_text_processing/text_normalization/ta/data/__init__.py diff --git a/nemo_text_processing/text_normalization/ta/__init__.py b/nemo_text_processing/text_normalization/ta/__init__.py index e69de29bb..2f2f217f3 100644 --- a/nemo_text_processing/text_normalization/ta/__init__.py +++ b/nemo_text_processing/text_normalization/ta/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/__init__.py b/nemo_text_processing/text_normalization/ta/data/__init__.py new file mode 100644 index 000000000..4fc25d0d3 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv index 51bfd3800..21f9f65ef 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv @@ -9,10 +9,82 @@ 18 பதினெட்டு 19 பத்தொன்பது 20 இருபது +21 இருபத்தொன்று +22 இருபத்திரண்டு +23 இருபத்துமூன்று +24 இருபத்துநான்கு +25 இருபத்தைந்து +26 இருபத்தாறு +27 இருபத்தேழு +28 இருபத்தெட்டு +29 இருபத்தொன்பது 30 முப்பது +31 முப்பத்தொன்று +32 முப்பத்திரண்டு +33 முப்பத்துமூன்று +34 முப்பத்துநான்கு +35 முப்பத்தைந்து +36 முப்பத்தாறு +37 முப்பத்தேழு +38 முப்பத்தெட்டு +39 முப்பத்தொன்பது 40 நாற்பது +41 நாற்பத்தொன்று +42 நாற்பத்திரண்டு +43 நாற்பத்துமூன்று +44 நாற்பத்துநான்கு +45 நாற்பத்தைந்து +46 நாற்பத்தாறு +47 நாற்பத்தேழு +48 நாற்பத்தெட்டு +49 நாற்பத்தொன்பது 50 ஐம்பது +51 ஐம்பத்தொன்று +52 ஐம்பத்திரண்டு +53 ஐம்பத்துமூன்று +54 ஐம்பத்துநான்கு +55 ஐம்பத்தைந்து +56 ஐம்பத்தாறு +57 ஐம்பத்தேழு +58 ஐம்பத்தெட்டு +59 ஐம்பத்தொன்பது 60 அறுபது +61 அறுபத்தொன்று +62 அறுபத்திரண்டு +63 அறுபத்துமூன்று +64 அறுபத்துநான்கு +65 அறுபத்தைந்து +66 அறுபத்தாறு +67 அறுபத்தேழு +68 அறுபத்தெட்டு +69 அறுபத்தொன்பது 70 எழுபது +71 எழுபத்தொன்று +72 எழுபத்திரண்டு +73 எழுபத்துமூன்று +74 எழுபத்துநான்கு +75 எழுபத்தைந்து +76 எழுபத்தாறு +77 எழுபத்தேழு +78 எழுபத்தெட்டு +79 எழுபத்தொன்பது 80 எண்பது -90 தொண்ணூறு \ No newline at end of file +81 எண்பத்தொன்று +82 எண்பத்திரண்டு +83 எண்பத்துமூன்று +84 எண்பத்துநான்கு +85 எண்பத்தைந்து +86 எண்பத்தாறு +87 எண்பத்தேழு +88 எண்பத்தெட்டு +89 எண்பத்தொன்பது +90 தொண்ணூறு +91 தொண்ணூற்றொன்று +92 தொண்ணூற்றிரண்டு +93 தொண்ணூற்றுமூன்று +94 தொண்ணூற்றுநான்கு +95 தொண்ணூற்றைந்து +96 தொண்ணூற்றாறு +97 தொண்ணூற்றேழு +98 தொண்ணூற்றெட்டு +99 தொண்ணூற்றொன்பது \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index e8543d9ad..854bcb8e5 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -1,5 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. -# Copyright 2015 and onwards Google, Inc. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/taggers/__init__.py b/nemo_text_processing/text_normalization/ta/taggers/__init__.py index e69de29bb..2f2f217f3 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/__init__.py +++ b/nemo_text_processing/text_normalization/ta/taggers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index f336995de..e7cf19655 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -1,3 +1,17 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import pynini from pynini.lib import pynutil @@ -5,9 +19,13 @@ from nemo_text_processing.text_normalization.ta.utils import get_abs_path -class CardinalFst(GraphFst): +class CardinalFst(GraphFst): """ - Classifies cardinal numbers, e.g. 5 -> cardinal { integer: "" } + Finite state transducer for classifying cardinals, e.g. + 5 -> cardinal { integer: "ஐந்து" } + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) """ def __init__(self, deterministic: bool = True): @@ -17,18 +35,12 @@ def __init__(self, deterministic: bool = True): digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) teens_and_ties = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - - # TODO 1: Combine the three transducers into one grammar so it accepts - # a single digit (1-9), zero (0), OR a two-digit number. - # Hint: the union operator in pynini is | - graph = digit | zero | teens_and_ties # <-- complete this + + graph = digit | zero | teens_and_ties graph = graph.optimize() - # TODO 2: Wrap the word in the token field the verbalizer expects: - # produce integer: "" - # Hint: pynutil.insert("text") writes literal text into the output. final_graph = pynutil.insert('integer: "') + graph + pynutil.insert('"') # add_tokens() turns it into: cardinal { integer: "" } final_graph = self.add_tokens(final_graph) - self.fst = final_graph.optimize() + self.fst = final_graph.optimize() \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py b/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py index e69de29bb..2f2f217f3 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py index 9dbde23e2..24e300c1b 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py @@ -1,3 +1,17 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import pynini from pynini.lib import pynutil @@ -8,23 +22,23 @@ ) -class CardinalFst(GraphFst): +class CardinalFst(GraphFst): """ - Verbalizes cardinals, e.g. cardinal { integer: "" } -> + Finite state transducer for verbalizing cardinal, e.g. + cardinal { integer: "5" } -> ஐந்து + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) """ def __init__(self, deterministic: bool = True): super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic) - - # TODO 3: Remove integer: " before the word and the closing " after it, - # keeping the word itself. - # Hint: pynutil.delete("text") deletes literal text; - # NEMO_NOT_QUOTE matches any character that is not a quote. + graph = ( pynutil.delete("integer:") + delete_space + pynutil.delete('"') - + pynini.closure(NEMO_NOT_QUOTE, 1) # <-- keep the word (1 or more non-quote chars) + + pynini.closure(NEMO_NOT_QUOTE, 1) + pynutil.delete('"') ) diff --git a/test_cases_cardinal.txt b/test_cases_cardinal.txt index c3da1bbbc..17716aafb 100644 --- a/test_cases_cardinal.txt +++ b/test_cases_cardinal.txt @@ -19,10 +19,82 @@ 18~பதினெட்டு 19~பத்தொன்பது 20~இருபது +21~இருபத்தொன்று +22~இருபத்திரண்டு +23~இருபத்துமூன்று +24~இருபத்துநான்கு +25~இருபத்தைந்து +26~இருபத்தாறு +27~இருபத்தேழு +28~இருபத்தெட்டு +29~இருபத்தொன்பது 30~முப்பது +31~முப்பத்தொன்று +32~முப்பத்திரண்டு +33~முப்பத்துமூன்று +34~முப்பத்துநான்கு +35~முப்பத்தைந்து +36~முப்பத்தாறு +37~முப்பத்தேழு +38~முப்பத்தெட்டு +39~முப்பத்தொன்பது 40~நாற்பது +41~நாற்பத்தொன்று +42~நாற்பத்திரண்டு +43~நாற்பத்துமூன்று +44~நாற்பத்துநான்கு +45~நாற்பத்தைந்து +46~நாற்பத்தாறு +47~நாற்பத்தேழு +48~நாற்பத்தெட்டு +49~நாற்பத்தொன்பது 50~ஐம்பது +51~ஐம்பத்தொன்று +52~ஐம்பத்திரண்டு +53~ஐம்பத்துமூன்று +54~ஐம்பத்துநான்கு +55~ஐம்பத்தைந்து +56~ஐம்பத்தாறு +57~ஐம்பத்தேழு +58~ஐம்பத்தெட்டு +59~ஐம்பத்தொன்பது 60~அறுபது +61~அறுபத்தொன்று +62~அறுபத்திரண்டு +63~அறுபத்துமூன்று +64~அறுபத்துநான்கு +65~அறுபத்தைந்து +66~அறுபத்தாறு +67~அறுபத்தேழு +68~அறுபத்தெட்டு +69~அறுபத்தொன்பது 70~எழுபது +71~எழுபத்தொன்று +72~எழுபத்திரண்டு +73~எழுபத்துமூன்று +74~எழுபத்துநான்கு +75~எழுபத்தைந்து +76~எழுபத்தாறு +77~எழுபத்தேழு +78~எழுபத்தெட்டு +79~எழுபத்தொன்பது 80~எண்பது -90~தொண்ணூறு \ No newline at end of file +81~எண்பத்தொன்று +82~எண்பத்திரண்டு +83~எண்பத்துமூன்று +84~எண்பத்துநான்கு +85~எண்பத்தைந்து +86~எண்பத்தாறு +87~எண்பத்தேழு +88~எண்பத்தெட்டு +89~எண்பத்தொன்பது +90~தொண்ணூறு +91~தொண்ணூற்றொன்று +92~தொண்ணூற்றிரண்டு +93~தொண்ணூற்றுமூன்று +94~தொண்ணூற்றுநான்கு +95~தொண்ணூற்றைந்து +96~தொண்ணூற்றாறு +97~தொண்ணூற்றேழு +98~தொண்ணூற்றெட்டு +99~தொண்ணூற்றொன்பது \ No newline at end of file From d68701b13067bcf858b897298129f7435007f385 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 16 Jun 2026 18:18:12 +0530 Subject: [PATCH 03/29] message Signed-off-by: surendran-246 --- "eval \"$(ssh-agent -s)\" " | 7 + "eval \"$(ssh-agent -s)\" .pub" | 1 + .../text_normalization/blind_testcases_ta | 1398 +++++++++++++++++ .../text_normalization/normalize.py | 16 +- .../text_normalization/run_evaluate.py | 6 +- .../ta/data/numbers/digit.tsv | 9 + .../ta/data/numbers/hundred_ta.tsv | 18 + .../ta/data/numbers/teens_and_ties.tsv | 180 +-- .../ta/data/numbers/teens_and_ties_en.tsv | 90 ++ .../ta/data/numbers/thousands.tsv | 8 + .../ta/data/numbers/zero.tsv | 1 + .../text_normalization/ta/graph_utils.py | 58 +- .../text_normalization/ta/taggers/cardinal.py | 478 +++++- .../ta/taggers/punctuation.py | 48 + .../ta/taggers/tokenize_and_classify.py | 168 ++ .../text_normalization/ta/taggers/word.py | 61 + .../ta/verbalizers/cardinal.py | 61 +- .../ta/verbalizers/post_processing.py | 96 ++ .../ta/verbalizers/verbalize.py | 53 + .../ta/verbalizers/verbalize_final.py | 76 + .../text_normalization/ta/verbalizers/word.py | 43 + run_cardinal_tests.py | 48 + tests/nemo_text_processing/ta/__init__.py | 13 + .../text_cases_cardinal.txt | 54 + .../test_cases_cardinal.txt | 148 ++ .../nemo_text_processing/ta/test_cardinal.py | 42 + 26 files changed, 2996 insertions(+), 185 deletions(-) create mode 100644 "eval \"$(ssh-agent -s)\" " create mode 100644 "eval \"$(ssh-agent -s)\" .pub" create mode 100644 nemo_text_processing/text_normalization/blind_testcases_ta create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv create mode 100644 nemo_text_processing/text_normalization/ta/taggers/punctuation.py create mode 100644 nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py create mode 100644 nemo_text_processing/text_normalization/ta/taggers/word.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py create mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/word.py create mode 100644 run_cardinal_tests.py create mode 100644 tests/nemo_text_processing/ta/__init__.py create mode 100644 tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt create mode 100644 tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt create mode 100644 tests/nemo_text_processing/ta/test_cardinal.py diff --git "a/eval \"$(ssh-agent -s)\" " "b/eval \"$(ssh-agent -s)\" " new file mode 100644 index 000000000..b14c82405 --- /dev/null +++ "b/eval \"$(ssh-agent -s)\" " @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCBMyvfUYcSi2sN3FiNKP92mA4jqEmXAt9Mz/oDhT/pJwAAAJieiaaMnomm +jAAAAAtzc2gtZWQyNTUxOQAAACCBMyvfUYcSi2sN3FiNKP92mA4jqEmXAt9Mz/oDhT/pJw +AAAED1t2yISojEhh/YjRHWLfYQOZzCun70VF+ZVvMWjWh3I4EzK99RhxKLaw3cWI0o/3aY +DiOoSZcC30zP+gOFP+knAAAAFXN1cmVuZHJhbnNAbnZpZGlhLmNvbQ== +-----END OPENSSH PRIVATE KEY----- diff --git "a/eval \"$(ssh-agent -s)\" .pub" "b/eval \"$(ssh-agent -s)\" .pub" new file mode 100644 index 000000000..90b5c176a --- /dev/null +++ "b/eval \"$(ssh-agent -s)\" .pub" @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIEzK99RhxKLaw3cWI0o/3aYDiOoSZcC30zP+gOFP+kn surendrans@nvidia.com diff --git a/nemo_text_processing/text_normalization/blind_testcases_ta b/nemo_text_processing/text_normalization/blind_testcases_ta new file mode 100644 index 000000000..4a2911adf --- /dev/null +++ b/nemo_text_processing/text_normalization/blind_testcases_ta @@ -0,0 +1,1398 @@ +CARDINAL ௪ சிக்ஸர்கள் ௧௪ பவுண்டரிகள் நான்கு சிக்ஸர்கள் பதினான்கு பவுண்டரிகள் + +CARDINAL ௬ ரன்கள் எடுத்தார் ஆறு ரன்கள் எடுத்தார் + +CARDINAL ௩ கோல்கள் அடித்தார் மூன்று கோல்கள் அடித்தார் + +CARDINAL ௯ சிக்ஸர்கள் ஒன்பது சிக்ஸர்கள் + +CARDINAL ௫ பவுண்டரிகள் ஐந்து பவுண்டரிகள் + +CARDINAL ௨ சிக்ஸர்கள் ௧௨ ரன்கள் இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் + +CARDINAL ௯ புள்ளிகள் ஒன்பது புள்ளிகள் + +CARDINAL ௪ பேர் உயிரிழப்பு ௧௮ பேர் காயம் நான்கு பேர் உயிரிழப்பு பதினெட்டு பேர் காயம் + +CARDINAL ௫ கோல்கள் அடித்தனர் ஐந்து கோல்கள் அடித்தனர் + +CARDINAL ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள் மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் + +CARDINAL ௧ ஓவர் ௧௩ ரன்கள் ஒன்று ஓவர் பதிமூன்று ரன்கள் + +CARDINAL ௩ ஓவர்கள் மூன்று ஓவர்கள் + +CARDINAL ௫ கோல்கள் ஐந்து கோல்கள் + +CARDINAL ௩ ஆப்பிள்கள் மூன்று ஆப்பிள்கள் + +CARDINAL ௭ வாழைப்பழங்கள் ஏழு வாழைப்பழங்கள் + +CARDINAL ௩ தோல்வி ௧௨ வெற்றி மூன்று தோல்வி பன்னிரண்டு வெற்றி + +CARDINAL ௫ தோல்விகள் ௧ டிரா ௧௭ வெற்றிகள் ஐந்து தோல்விகள் ஒன்று டிரா பதினேழு வெற்றிகள் + +CARDINAL ௮ போட்டிகள் டிரா எட்டு போட்டிகள் டிரா + +CARDINAL ௪ பவுண்டரிகள் நான்கு பவுண்டரிகள் + +CARDINAL ௮ சிக்ஸர்கள் ௨ அவுட் எட்டு சிக்ஸர்கள் இரண்டு அவுட் + +CARDINAL ௬ வீரர்கள் அவுட் ஆறு வீரர்கள் அவுட் + +CARDINAL ௪ ரன்கள் ௩ பவுண்டரிகள் நான்கு ரன்கள் மூன்று பவுண்டரிகள் + +CARDINAL ஒன்பிளஸ் ௮ ப்ரோ ஒன்பிளஸ் எட்டு ப்ரோ + +CARDINAL ௫ சார்ஜர்கள் ஐந்து சார்ஜர்கள் + +CARDINAL ௪ ஓவரில் ௧௭ ரன்கள் நான்கு ஓவரில் பதினேழு ரன்கள் + +CARDINAL ௫ சாக்லேட்டுகள் ௯ டாபிகள் ஐந்து சாக்லேட்டுகள் ஒன்பது டாபிகள் + +CARDINAL ௬ பேட்ஸ்மேன்கள் ௨ பவுலர்கள் ஆறு பேட்ஸ்மேன்கள் இரண்டு பவுலர்கள் + +CARDINAL ௧ விக்கெட் கீப்பர் ஒன்று விக்கெட் கீப்பர் + +CARDINAL ௮ கேட்ச் அவுட் எட்டு கேட்ச் அவுட் + +CARDINAL ௫ விக்கெட்டுக்கு ௧௦ ரன்கள் ஐந்து விக்கெட்டுக்கு பத்து ரன்கள் + +CARDINAL ௭ வெற்றி ௨ டிரா ஏழு வெற்றி இரண்டு டிரா + +CARDINAL ௨ பவுண்டரிகள் இரண்டு பவுண்டரிகள் + +CARDINAL ௬ ரன்கள் ௫ விக்கெட்டுகள் ஆறு ரன்கள் ஐந்து விக்கெட்டுகள் + +CARDINAL ௭ பந்துகள் ௧௧ ரன்கள் ஏழு பந்துகள் பதினொன்று ரன்கள் + +CARDINAL ௬ சாக்லேட்டுகள் ௪ டாபிகள் ஆறு சாக்லேட்டுகள் நான்கு டாபிகள் + +CARDINAL ௮ வெண்கலங்கள் ௨ தங்கங்கள் எட்டு வெண்கலங்கள் இரண்டு தங்கங்கள் + +CARDINAL ௧ தங்கப் பதக்கம் ஒன்று தங்கப் பதக்கம் + +CARDINAL ௩ ரன்கள் மூன்று ரன்கள் + +CARDINAL ௫ ஓவர்கள் ஐந்து ஓவர்கள் + +CARDINAL ௬ பந்து ஆறு பந்து + +CARDINAL ௩ இன்னிங்ஸ் மூன்று இன்னிங்ஸ் + +CARDINAL வசனம் ௭ பாடம் ௧௫ வசனம் ஏழு பாடம் பதினைந்து + +CARDINAL பாடம் எண் ௨ வசனம் ௪ பாடம் எண் இரண்டு வசனம் நான்கு + +CARDINAL பக்க எண் ௮ பத்தி ௬ பக்க எண் எட்டு பத்தி ஆறு + +CARDINAL ௨ பந்துகள் ௪ ரன்கள் இரண்டு பந்துகள் நான்கு ரன்கள் + +CARDINAL ௬ விக்கெட்டுகள் ஆறு விக்கெட்டுகள் + +CARDINAL ௨ புள்ளி ௫ கோல்கள் இரண்டு புள்ளி ஐந்து கோல்கள் + +CARDINAL பாடம் ௧௦ ஸ்லோகம் ௨ பாடம் பத்து ஸ்லோகம் இரண்டு + +CARDINAL அத்தியாயம் ௫ காட்சி ௬ அத்தியாயம் ஐந்து காட்சி ஆறு + +CARDINAL ௬ கேள்விகள் ௫ தவறு ஆறு கேள்விகள் ஐந்து தவறு + +CARDINAL ௩ ரோஜா ௪ மல்லிகை ௨ சாமந்தி மூன்று ரோஜா நான்கு மல்லிகை இரண்டு சாமந்தி + +CARDINAL ௨ ஃப்ரீ ஹிட் ௧ நோ பால் இரண்டு ஃப்ரீ ஹிட் ஒன்று நோ பால் + +CARDINAL ௩ போன் ௧ சார்ஜர் மூன்று போன் ஒன்று சார்ஜர் + +CARDINAL ௬ டிரா ௭ தோல்வி ௯ வெற்றி ஆறு டிரா ஏழு தோல்வி ஒன்பது வெற்றி + +CARDINAL ௪ கார் ௨ பைக் நான்கு கார் இரண்டு பைக் + +CARDINAL ௧ கூடை ௮ பழம் ஒன்று கூடை எட்டு பழம் + +CARDINAL ௩ வரிசை ௮ நபர் மூன்று வரிசை எட்டு நபர் + +CARDINAL ௧௦ பென்சில் ௨ பேனா பத்து பென்சில் இரண்டு பேனா + +CARDINAL ௫ கட்டிடம் ஐந்து கட்டிடம் + +CARDINAL ௬ குழந்தை ஆறு குழந்தை + +CARDINAL பத்தி ௧௩ வரிசை ௪ பத்தி பதிமூன்று வரிசை நான்கு + +CARDINAL ௩ தங்கம் ௪ வெள்ளி மூன்று தங்கம் நான்கு வெள்ளி + +CARDINAL ௫ குழிகள் ஐந்து குழிகள் + +CARDINAL ௮ குப்பம் எட்டு குப்பம் + +CARDINAL ௩ லேப்டாப் மூன்று லேப்டாப் + +CARDINAL ௧ சிக்ஸர் ௨ பவுண்டரிகள் ஒன்று சிக்ஸர் இரண்டு பவுண்டரிகள் + +CARDINAL ௫ பஸ் ஐந்து பஸ் + +CARDINAL ௨ லாரி இரண்டு லாரி + +CARDINAL ௩ வண்டி மூன்று வண்டி + +CARDINAL ௬ சுறா ௩௦ முதலீட்டாளர்கள் ஆறு சுறா முப்பது முதலீட்டாளர்கள் + +CARDINAL ௨ அமைச்சர் ௫௦ பிரச்சனைகள் இரண்டு அமைச்சர் ஐம்பது பிரச்சனைகள் + +CARDINAL ௬ பவுலர் ஆறு பவுலர் + +CARDINAL ஸ்லோகம் ௩ பாடம் ௧ ஸ்லோகம் மூன்று பாடம் ஒன்று + +CARDINAL வரிசை ௬ பத்தி ௯ வரிசை ஆறு பத்தி ஒன்பது + +CARDINAL புத்தகம் ௧ பாடம் ௮ புத்தகம் ஒன்று பாடம் எட்டு + +CARDINAL சிறுகதை எண் ௨ வரிசை ௬ சிறுகதை எண் இரண்டு வரிசை ஆறு + +CARDINAL கைதி எண் ௪ கைதி எண் நான்கு + +CARDINAL பக்க எண் ௧௦ வரிசை ௨ பக்க எண் பத்து வரிசை இரண்டு + +CARDINAL ௪ மருத்துவர் நான்கு மருத்துவர் + +CARDINAL ௨ பந்து ௩ ரன் இரண்டு பந்து மூன்று ரன் + +CARDINAL புள்ளிகள் ௨ கோல் ௪ புள்ளிகள் இரண்டு கோல் நான்கு + +CARDINAL பாடம் எண் ௪ பாடம் எண் நான்கு + +CARDINAL ௮ ஓவர் எட்டு ஓவர் + +CARDINAL ௭ ரன் ௨ ஓவர் ஏழு ரன் இரண்டு ஓவர் + +CARDINAL ௪ பந்து ௮ ரன் நான்கு பந்து எட்டு ரன் + +CARDINAL ௩ பாட்டில் ௫ கிளாஸ் மூன்று பாட்டில் ஐந்து கிளாஸ் + +CARDINAL ௬ ரன் ஆறு ரன் + +CARDINAL ௬ கோல் ஆறு கோல் + +CARDINAL ௧௦ புள்ளிகள் ௩ கோல் பத்து புள்ளிகள் மூன்று கோல் + +CARDINAL ௧௪ சிக்ஸர் ௩ பவுண்டரி பதினான்கு சிக்ஸர் மூன்று பவுண்டரி + +CARDINAL ௬ ஆப்பிள் ௩ வாழைப்பழம் ஆறு ஆப்பிள் மூன்று வாழைப்பழம் + +CARDINAL ௩ மேட்ச் டிரா மூன்று மேட்ச் டிரா + +CARDINAL ௬ மேட்ச் தோல்வி ஆறு மேட்ச் தோல்வி + +CARDINAL ௯ மேட்ச் வெற்றி ஒன்பது மேட்ச் வெற்றி + +CARDINAL ஸ்லோகம் ௬ பாடம் ௯ ஸ்லோகம் ஆறு பாடம் ஒன்பது + +CARDINAL பதம் ௪ வரிசை எண் ௩ பதம் நான்கு வரிசை எண் மூன்று + +CARDINAL பாடம் ௧௦ பக்கம் ௪ பாடம் பத்து பக்கம் நான்கு + +CARDINAL ௫ கார் ௨ மோட்டார் சைக்கிள் ஐந்து கார் இரண்டு மோட்டார் சைக்கிள் + +CARDINAL ௭ புள்ளிகள் ௨ கோல் ஏழு புள்ளிகள் இரண்டு கோல் + +CARDINAL ௪ இரவு ௩ பகல் நான்கு இரவு மூன்று பகல் + +CARDINAL ௧ ஆஸ் ௧ ராணி ௫ சீட்டுகள் ஒன்று ஆஸ் ஒன்று ராணி ஐந்து சீட்டுகள் + +CARDINAL வரிசை ௨ பத்தி ௧ வரிசை இரண்டு பத்தி ஒன்று + +CARDINAL ௫ ஜோடி காலணி ஐந்து ஜோடி காலணி + +CARDINAL ௧௦ ஓவரில் ௯ ரன் பத்து ஓவரில் ஒன்பது ரன் + +CARDINAL ௮ ரன் எட்டு ரன் + +CARDINAL ௪ சிக்ஸர்கள் ௧ ஃபோர் நான்கு சிக்ஸர்கள் ஒன்று ஃபோர் + +CARDINAL பக்க எண் ௯ இன் வரிசை ௪ பக்க எண் ஒன்பது இன் வரிசை நான்கு + +CARDINAL பாரா ௧௦ இன் பகுதி ௩ பாரா பத்து இன் பகுதி மூன்று + +CARDINAL ஆயத் ௪ ருகூ ௬ ஆயத் நான்கு ருகூ ஆறு + +CARDINAL பாரா ௯ ருகூ ௬ பாரா ஒன்பது ருகூ ஆறு + +CARDINAL ௮ கால்சட்டைகள் ௯ சட்டைகள் எட்டு கால்சட்டைகள் ஒன்பது சட்டைகள் + +CARDINAL ௪ ரொட்டி ௨ காய்கறி நான்கு ரொட்டி இரண்டு காய்கறி + +CARDINAL ௩ மேட்ச் ௪ வெற்றி மூன்று மேட்ச் நான்கு வெற்றி + +CARDINAL ௪ தோல்வி ௩ வெற்றி ௧ டிரா நான்கு தோல்வி மூன்று வெற்றி ஒன்று டிரா + +CARDINAL படம் ௧௯ பாடம் ௨ படம் பத்தொன்பது பாடம் இரண்டு + +CARDINAL பாடம் ௧ பக்கம் ௧௨௨ பாடம் ஒன்று பக்கம் நூற்று இருபத்து இரண்டு + +CARDINAL பாடம் ௩ வரிசை ௬ பாடம் மூன்று வரிசை ஆறு + +CARDINAL ஸ்லோகம் ௧௦ பக்கம் ௩ ஸ்லோகம் பத்து பக்கம் மூன்று + +CARDINAL ௬ புள்ளிகள் ௩ கோல் ஆறு புள்ளிகள் மூன்று கோல் + +CARDINAL ௨ டெஸ்ட் போட்டிகள் ௬ ஒன்றுநாள் போட்டிகள் இரண்டு டெஸ்ட் போட்டிகள் ஆறு ஒன்றுநாள் போட்டிகள் + +CARDINAL ௨ ஓவரில் ௭ ரன் இரண்டு ஓவரில் ஏழு ரன் + +CARDINAL ௮ ஓவரில் ௪௫ ரன் எட்டு ஓவரில் நாற்பத்து ஐந்து ரன் + +CARDINAL ௯ ஓவரில் ௬௦ ரன் ஒன்பது ஓவரில் அறுபது ரன் + +CARDINAL ௫ போட்டிகள் ௪ வெற்றிகள் ஐந்து போட்டிகள் நான்கு வெற்றிகள் + +CARDINAL ௨ வெற்றி ௪ தோல்வி ௫ டிரா இரண்டு வெற்றி நான்கு தோல்வி ஐந்து டிரா + +CARDINAL ஸ்லோகம் ௯ பக்கம் ௭ ஸ்லோகம் ஒன்பது பக்கம் ஏழு + +CARDINAL பாடம் ௨ பக்கம் ௬௬ பாடம் இரண்டு பக்கம் அறுபத்து ஆறு + +CARDINAL ௨ டயகிராம் ௧௩ பக்க எண் இரண்டு டயகிராம் பதிமூன்று பக்க எண் + +CARDINAL பட எண் ௮ பாடம் ௪ பட எண் எட்டு பாடம் நான்கு + +CARDINAL பக்க எண் ௧௦ பாடம் ௩ பக்க எண் பத்து பாடம் மூன்று + +CARDINAL ருகு ௩ ஆயத் ௮ ருகு மூன்று ஆயத் எட்டு + +CARDINAL ருகு ௪ ஆயத் ௬ வரி ௩௩ ருகு நான்கு ஆயத் ஆறு வரி முப்பத்து மூன்று + +CARDINAL பாரா ௨ ருகு ௭ வரி ௧௫ பாரா இரண்டு ருகு ஏழு வரி பதினைந்து + +CARDINAL ௩௦ பாரா வரி ௮ முப்பது பாரா வரி எட்டு + +CARDINAL ௪ சிக்ஸர்கள் ௧௨ ஃபோர்கள் நான்கு சிக்ஸர்கள் பன்னிரண்டு ஃபோர்கள் + +CARDINAL ௫ புள்ளிகள் ௭ கோல்கள் ஐந்து புள்ளிகள் ஏழு கோல்கள் + +CARDINAL பதிப்பு ௨ தலைமுறை ௪ பதிப்பு இரண்டு தலைமுறை நான்கு + +CARDINAL ௮ செங்கற்கள் ௩௨ கற்கள் எட்டு செங்கற்கள் முப்பத்து இரண்டு கற்கள் + +CARDINAL ௯ ஓவரில் ௧௫ ரன்கள் ஒன்பது ஓவரில் பதினைந்து ரன்கள் + +CARDINAL ௪ விக்கெட் ௧௧௩ ரன்கள் நான்கு விக்கெட் நூற்று பதிமூன்று ரன்கள் + +CARDINAL ௭ விக்கெட் ௨௧௧ ரன்கள் ஏழு விக்கெட் இருநூற்று பதினொன்று ரன்கள் + +CARDINAL ௪ சிக்ஸர்கள் ௫ ஃபோர்கள் ௪௪ ரன்கள் நான்கு சிக்ஸர்கள் ஐந்து ஃபோர்கள் நாற்பத்து நான்கு ரன்கள் + +CARDINAL ருகு ௮ வரி ௧௦ ருகு எட்டு வரி பத்து + +CARDINAL பாடம் ௯ வரி ௧௩ பாடம் ஒன்பது வரி பதிமூன்று + +CARDINAL பகுதி ௧௦ வரி ௬ சுலோகம் ௨ பகுதி பத்து வரி ஆறு சுலோகம் இரண்டு + +CARDINAL பகுதி ௧௨ சுலோகம் ௩ வரி ௧௭ பகுதி பன்னிரண்டு சுலோகம் மூன்று வரி பதினேழு + +CARDINAL ௭ ஓவர் ஏழு ஓவர் + +CARDINAL ௬ ஃபோர்கள் ஆறு ஃபோர்கள் + +CARDINAL ௩ ஒன்றுநாள் ௫ டெஸ்ட் போட்டிகள் மூன்று ஒன்றுநாள் ஐந்து டெஸ்ட் போட்டிகள் + +CARDINAL ௭ வீரர்கள் ௨ காயம் ஏழு வீரர்கள் இரண்டு காயம் + +CARDINAL பதிப்பு ௩ தலைமுறை ௧௦ பதிப்பு மூன்று தலைமுறை பத்து + +CARDINAL ருகு ௧௪ பாரா ௮ ருகு பதினான்கு பாரா எட்டு + +CARDINAL சுலோகம் ௮ பாடம் ௬ சுலோகம் எட்டு பாடம் ஆறு + +CARDINAL விரிவுரை ௩ வகுப்பு ௮ விரிவுரை மூன்று வகுப்பு எட்டு + +CARDINAL வகுப்பு ௧௦ பிரிவு ௨ வகுப்பு பத்து பிரிவு இரண்டு + +CARDINAL ௩ டிரா ௨ தோல்வி மூன்று டிரா இரண்டு தோல்வி + +CARDINAL சுலோகம் ௩ பாடம் ௧௧ சுலோகம் மூன்று பாடம் பதினொன்று + +CARDINAL வரி ௬ பாடம் ௧௦ வரி ஆறு பாடம் பத்து + +CARDINAL ருகு ௨ பாரா ௧௫ ருகு இரண்டு பாரா பதினைந்து + +CARDINAL ௪ சிக்ஸர்கள் ௫ பந்துகள் நான்கு சிக்ஸர்கள் ஐந்து பந்துகள் + +CARDINAL ௨ பந்துகள் ௧ ரன் இரண்டு பந்துகள் ஒன்று ரன் + +CARDINAL வரி ௮ அத்தியாயம் ௧௯ வரி எட்டு அத்தியாயம் பத்தொன்பது + +CARDINAL பக்கம் ௧௦ பத்தி ௨ பக்கம் பத்து பத்தி இரண்டு + +CARDINAL ௯ ஓவரில் ௧௭ ரன்கள் ஒன்பது ஓவரில் பதினேழு ரன்கள் + +CARDINAL ௪ பந்துகளில் ௬ நான்கு பந்துகளில் ஆறு + +CARDINAL ௧௭ பந்துகளில் ௧௦ ரன்கள் பதினேழு பந்துகளில் பத்து ரன்கள் + +CARDINAL ௫ ஓவர் ௬௬ ரன்கள் ஐந்து ஓவர் அறுபத்து ஆறு ரன்கள் + +CARDINAL ௮ புள்ளிகள் ௯ கோல்கள் எட்டு புள்ளிகள் ஒன்பது கோல்கள் + +CARDINAL ௫ கொய்யாப்பழங்கள் ஐந்து கொய்யாப்பழங்கள் + +CARDINAL ௬ ருகு ௭ பாரா ஆறு ருகு ஏழு பாரா + +CARDINAL சுலோகம் ௮ பதம் ௯ சுலோகம் எட்டு பதம் ஒன்பது + +CARDINAL ௭ ஓவரில் ௨௧ ரன்கள் ஏழு ஓவரில் இருபத்து ஒன்று ரன்கள் + +CARDINAL ௧ ஓவரில் ௩ ரன்கள் ஒன்று ஓவரில் மூன்று ரன்கள் + +CARDINAL ௭ சிக்ஸர்கள் ௫ ஃபோர்கள் ஏழு சிக்ஸர்கள் ஐந்து ஃபோர்கள் + +CARDINAL ௩ சுலோகங்கள் மூன்று சுலோகங்கள் + +CARDINAL ௬ பக்கங்கள் ஆறு பக்கங்கள் + +CARDINAL ௫ சிக்ஸர்கள் ஐந்து சிக்ஸர்கள் + +CARDINAL ௩ பாட்டில்கள் ௧௦ கண்ணாடிகள் மூன்று பாட்டில்கள் பத்து கண்ணாடிகள் + +CARDINAL ௩ போட்டிகள் மூன்று போட்டிகள் + +CARDINAL ௬ போட்டிகள் ௪ டிரா ஆறு போட்டிகள் நான்கு டிரா + +CARDINAL ௨ பந்துகளில் ௩ ரன்கள் இரண்டு பந்துகளில் மூன்று ரன்கள் + +CARDINAL ௩ புள்ளிகள் ௪ கோல்கள் மூன்று புள்ளிகள் நான்கு கோல்கள் + +CARDINAL ஆயத் ௪ வரி ௯ ஆயத் நான்கு வரி ஒன்பது + +CARDINAL பாரா ௪ ருகு ௧௦ வரி ௧௭ பாரா நான்கு ருகு பத்து வரி பதினேழு + +CARDINAL பாரா ௬ ருகு ௨௫ வரி ௨௦ பாரா ஆறு ருகு இருபத்து ஐந்து வரி இருபது + +CARDINAL பாடம் ௩ தோஹா ௪ வரி ௨ பாடம் மூன்று தோஹா நான்கு வரி இரண்டு + +CARDINAL வரி ௮ சொல் ௬ வரி எட்டு சொல் ஆறு + +CARDINAL கட்டுரை ௧௦ பத்தி ௨ கட்டுரை பத்து பத்தி இரண்டு + +CARDINAL ௭ ஸ்வரங்கள் ஏழு ஸ்வரங்கள் + +CARDINAL பாடல் ௪ முகடை ௨ பாடல் நான்கு முகடை இரண்டு + +CARDINAL டிக்கெட் எண் ௯ வரி ௮ டிக்கெட் எண் ஒன்பது வரி எட்டு + +CARDINAL ஆயத் ௧௦ வரி ௧௮ ஆயத் பத்து வரி பதினெட்டு + +CARDINAL ௬ ஓவர் ௨௦ ரன்கள் ஆறு ஓவர் இருபது ரன்கள் + +CARDINAL ௮௦ ரன்கள் ௩ விக்கெட்டுகள் எண்பது ரன்கள் மூன்று விக்கெட்டுகள் + +CARDINAL ௪ ஸ்பின்னர்கள் ௩ பேட்ஸ்மேன்கள் ௧ விக்கெட் கீப்பர் நான்கு ஸ்பின்னர்கள் மூன்று பேட்ஸ்மேன்கள் ஒன்று விக்கெட் கீப்பர் + +CARDINAL ௧ கோல் கீப்பர் ௬ வீரர்கள் ஒன்று கோல் கீப்பர் ஆறு வீரர்கள் + +CARDINAL பாடம் ௧௮ பதம் ௫ பாடம் பதினெட்டு பதம் ஐந்து + +CARDINAL தோஹா ௬ வரி ௯ தோஹா ஆறு வரி ஒன்பது + +CARDINAL படம் ௬ பக்கம் ௮௦ படம் ஆறு பக்கம் எண்பது + +CARDINAL ௨ டிரா ௩ வெற்றி இரண்டு டிரா மூன்று வெற்றி + +CARDINAL ௪ வைவா ௩ தேர்வுகள் நான்கு வைவா மூன்று தேர்வுகள் + +CARDINAL ௪ தேர்வுகள் ௬ செஷனல்கள் நான்கு தேர்வுகள் ஆறு செஷனல்கள் + +CARDINAL ௩ தட்டுகள் ௪ கிண்ணங்கள் ௨ கரண்டிகள் மூன்று தட்டுகள் நான்கு கிண்ணங்கள் இரண்டு கரண்டிகள் + +CARDINAL ௪ டிரா ௫ வெற்றி நான்கு டிரா ஐந்து வெற்றி + +CARDINAL ௮ சிக்ஸர்கள் ௧௪ ஃபோர்கள் எட்டு சிக்ஸர்கள் பதினான்கு ஃபோர்கள் + +CARDINAL ௫ ஓவர்கள் ௪ விக்கெட்டுகள் ஐந்து ஓவர்கள் நான்கு விக்கெட்டுகள் + +CARDINAL ௩ ரன்கள் ௨ விக்கெட்டுகள் மூன்று ரன்கள் இரண்டு விக்கெட்டுகள் + +CARDINAL ௬ ஓவர்கள் ௪ ரன்கள் ஆறு ஓவர்கள் நான்கு ரன்கள் + +CARDINAL ௪ டெஸ்ட் போட்டிகள் ௧ ஒன்றுநாள் போட்டி நான்கு டெஸ்ட் போட்டிகள் ஒன்று ஒன்றுநாள் போட்டி + +CARDINAL ௨ புள்ளிகள் ௧௨ கோல்கள் இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் + +CARDINAL ௭ கரண்டிகள் உடைந்தன ஏழு கரண்டிகள் உடைந்தன + +CARDINAL ௧௦ இல் ௬ மதிப்பெண்கள் பத்து இல் ஆறு மதிப்பெண்கள் + +CARDINAL பாடம் ௨ பக்க எண் ௧௨ பாடம் இரண்டு பக்க எண் பன்னிரண்டு + +CARDINAL ௧ ஓவரில் ௬ பந்துகள் ஒன்று ஓவரில் ஆறு பந்துகள் + +CARDINAL ௭ ஷாட்டுகள் சரியாக பட்டன ஏழு ஷாட்டுகள் சரியாக பட்டன + +CARDINAL இந்தியாவுக்கு ௪ புள்ளிகள் முன்னிலை இந்தியாவுக்கு நான்கு புள்ளிகள் முன்னிலை + +CARDINAL சதத்திற்கு ௩ ரன்கள் மீதம் சதத்திற்கு மூன்று ரன்கள் மீதம் + +CARDINAL ௧ தோல்வி ௨ டிரா ஒன்று தோல்வி இரண்டு டிரா + +CARDINAL அர்ஜென்டினா ௨ புள்ளிகள் பின்தங்கி அர்ஜென்டினா இரண்டு புள்ளிகள் பின்தங்கி + +CARDINAL ௨ கோல்கள் அடிக்கப்பட்டன இரண்டு கோல்கள் அடிக்கப்பட்டன + +CARDINAL ௮ கூடுதல் ரன்கள் எட்டு கூடுதல் ரன்கள் + +CARDINAL ௪ வைடு பந்துகள் நான்கு வைடு பந்துகள் + +CARDINAL வகுப்பு ௯ வகுப்பு ஒன்பது + +CARDINAL வகுப்பு ௫ வகுப்பு ஐந்து + +CARDINAL ௯ பகுதிகள் ஒன்பது பகுதிகள் + +CARDINAL வகுப்பு ௪ பாடம் ௩ வகுப்பு நான்கு பாடம் மூன்று + +CARDINAL பாடம் ௯ பாடம் ஒன்பது + +CARDINAL பக்க எண் ௮ பக்க எண் எட்டு + +CARDINAL ௪ பாட்டில்கள் நான்கு பாட்டில்கள் + +CARDINAL ௧௦௦ இல் ௪ மதிப்பெண்கள் நூறு இல் நான்கு மதிப்பெண்கள் + +CARDINAL ௮ மதிப்பெண்கள் எட்டு மதிப்பெண்கள் + +CARDINAL கண்ணாடி எண் ௨ கண்ணாடி எண் இரண்டு + +CARDINAL ௭ செருப்புகள் ஏழு செருப்புகள் + +CARDINAL ௫ காலணிகள் ஐந்து காலணிகள் + +CARDINAL ௨ சாண்டல்கள் இரண்டு சாண்டல்கள் + +CARDINAL ௭ விளையாட்டுகளில் வெற்றி ஏழு விளையாட்டுகளில் வெற்றி + +CARDINAL ௬ மூடிகள் ஆறு மூடிகள் + +CARDINAL ௧௦௦௦ ரூபாய் ௨ நோட்டுகள் ஆயிரம் ரூபாய் இரண்டு நோட்டுகள் + +CARDINAL ௧௯ இல் ௩ கண்ணாடிகள் பத்தொன்பது இல் மூன்று கண்ணாடிகள் + +CARDINAL பக்கம் ௧௯௯ பாடம் ௬ பக்கம் நூற்று தொண்ணூற்று ஒன்பது பாடம் ஆறு + +CARDINAL ௮ பாராக்கள் எட்டு பாராக்கள் + +CARDINAL பகுதி ௫ பாடம் ௧௯ பகுதி ஐந்து பாடம் பத்தொன்பது + +CARDINAL ௮௦ ரன்கள் ௬ விக்கெட்டுகள் எண்பது ரன்கள் ஆறு விக்கெட்டுகள் + +CARDINAL ௯ கூடுதல் ரன்கள் ஒன்பது கூடுதல் ரன்கள் + +CARDINAL ௧௧ பந்துகள் ௮ ரன்கள் பதினொன்று பந்துகள் எட்டு ரன்கள் + +CARDINAL ௨ மஞ்சள் ௮ சிவப்பு அட்டைகள் இரண்டு மஞ்சள் எட்டு சிவப்பு அட்டைகள் + +CARDINAL அத்தியாயம் ௧௨ சுலோகம் ௮ அத்தியாயம் பன்னிரண்டு சுலோகம் எட்டு + +CARDINAL பக்கம் ௮௮ அத்தியாயம் ௭ பக்கம் எண்பத்து எட்டு அத்தியாயம் ஏழு + +CARDINAL ௧௦௦ ரன்கள் ௫ விக்கெட்டுகள் நூறு ரன்கள் ஐந்து விக்கெட்டுகள் + +CARDINAL ௮ கோல்களால் வெற்றி எட்டு கோல்களால் வெற்றி + +CARDINAL ௩ சக்கர வாகனம் மூன்று சக்கர வாகனம் + +CARDINAL அத்தியாயம் ௧௯ பகுதி ௪ அத்தியாயம் பத்தொன்பது பகுதி நான்கு + +CARDINAL ௧௧ மாதங்கள் ௮ நாட்கள் பதினொன்று மாதங்கள் எட்டு நாட்கள் + +CARDINAL ௯ நாட்கள் ௧௨ மணி நேரம் ஒன்பது நாட்கள் பன்னிரண்டு மணி நேரம் + +CARDINAL ௪ கட்டுகள் ௧௩ அட்டைகள் நான்கு கட்டுகள் பதிமூன்று அட்டைகள் + +CARDINAL ௭ போட்டிகள் ௧௨ விக்கெட்டுகள் ஏழு போட்டிகள் பன்னிரண்டு விக்கெட்டுகள் + +CARDINAL ௧ மனிதன் ஒன்று மனிதன் + +CARDINAL ௨ பெண்கள் இரண்டு பெண்கள் + +CARDINAL ௩ குழந்தைகள் மூன்று குழந்தைகள் + +CARDINAL ௪ புத்தகங்கள் நான்கு புத்தகங்கள் + +CARDINAL ௫ அறைகள் ஐந்து அறைகள் + +CARDINAL ௬ வீடுகள் ஆறு வீடுகள் + +CARDINAL ௭ பக்கங்கள் ஏழு பக்கங்கள் + +CARDINAL ௮ நாணயங்கள் எட்டு நாணயங்கள் + +CARDINAL ௯ பெட்டிகள் ஒன்பது பெட்டிகள் + +CARDINAL ௧௦ வேலைகள் பத்து வேலைகள் + +CARDINAL ௧௧ பழங்கள் ௨ பூக்கள் பதினொன்று பழங்கள் இரண்டு பூக்கள் + +CARDINAL ௩ பூக்கள் மூன்று பூக்கள் + +CARDINAL ௧௩ பூந்தொட்டிகள் ௪ செடிகள் பதிமூன்று பூந்தொட்டிகள் நான்கு செடிகள் + +CARDINAL ௪ பப்பாளிப்பழங்கள் நான்கு பப்பாளிப்பழங்கள் + +CARDINAL ௫ மாம்பழங்கள் ஐந்து மாம்பழங்கள் + +CARDINAL ௬ வாழைப்பழங்கள் ஆறு வாழைப்பழங்கள் + +CARDINAL ௭ திராட்சைப்பழங்கள் ஏழு திராட்சைப்பழங்கள் + +CARDINAL ௮ ஆரஞ்சுப்பழங்கள் எட்டு ஆரஞ்சுப்பழங்கள் + +CARDINAL ௯ ஆப்பிள்கள் ஒன்பது ஆப்பிள்கள் + +CARDINAL ௧௦ சப்போட்டா பழங்கள் பத்து சப்போட்டா பழங்கள் + +CARDINAL ௧ தாமரை ஒன்று தாமரை + +CARDINAL ௨ கற்கள் இரண்டு கற்கள் + +CARDINAL ௩ நாற்காலிகள் மூன்று நாற்காலிகள் + +CARDINAL ௪ பைகள் நான்கு பைகள் + +CARDINAL ௫ தொலைபேசிகள் ஐந்து தொலைபேசிகள் + +CARDINAL ௬ அறைகள் ஆறு அறைகள் + +CARDINAL ௭ பெண்கள் ஏழு பெண்கள் + +CARDINAL ௮ புத்தகங்கள் எட்டு புத்தகங்கள் + +CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் + +CARDINAL ௧௦ நதிகள் பத்து நதிகள் + +CARDINAL ௩ எருமைகள் மூன்று எருமைகள் + +CARDINAL ௨ காலணிகள் இரண்டு காலணிகள் + +CARDINAL ௩ நாய்கள் மூன்று நாய்கள் + +CARDINAL ௪ குதிரைகள் நான்கு குதிரைகள் + +CARDINAL ௫ மகன்கள் ஐந்து மகன்கள் + +CARDINAL ௬ சேவல்கள் ஆறு சேவல்கள் + +CARDINAL ௭ கழுதைகள் ஏழு கழுதைகள் + +CARDINAL ௮ சிறுமிகள் எட்டு சிறுமிகள் + +CARDINAL ௯ சிறுவர்கள் ஒன்பது சிறுவர்கள் + +CARDINAL ௧௦ கேள்விகள் பத்து கேள்விகள் + +CARDINAL ௧ சட்டை ஒன்று சட்டை + +CARDINAL ௨ படகுகள் இரண்டு படகுகள் + +CARDINAL ௩ பெட்டிகள் மூன்று பெட்டிகள் + +CARDINAL ௪ மூடிகள் நான்கு மூடிகள் + +CARDINAL ௫ நோட்டுகள் ஐந்து நோட்டுகள் + +CARDINAL ௬ நாணயங்கள் ஆறு நாணயங்கள் + +CARDINAL ௭ காயங்கள் ஏழு காயங்கள் + +CARDINAL ௮ நிறங்கள் எட்டு நிறங்கள் + +CARDINAL ௯ மக்கள் ஒன்பது மக்கள் + +CARDINAL ௧௦ நாட்கள் பத்து நாட்கள் + +CARDINAL ௫ விஷயங்கள் ஐந்து விஷயங்கள் + +CARDINAL ௨ மருந்துகள் இரண்டு மருந்துகள் + +CARDINAL ௩ கூடுகள் மூன்று கூடுகள் + +CARDINAL ௪ தோழிகள் நான்கு தோழிகள் + +CARDINAL ௫ செடிகள் ஐந்து செடிகள் + +CARDINAL ௬ திரைகள் ஆறு திரைகள் + +CARDINAL ௭ பூனைகள் ஏழு பூனைகள் + +CARDINAL ௮ எலிகள் எட்டு எலிகள் + +CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் + +CARDINAL ௧௦ கண்கள் பத்து கண்கள் + +CARDINAL ௬ சுவர்கள் ஆறு சுவர்கள் + +CARDINAL ௨ கடிகாரங்கள் இரண்டு கடிகாரங்கள் + +CARDINAL ௩ பப்பாளிப்பழங்கள் மூன்று பப்பாளிப்பழங்கள் + +CARDINAL ௪ மிதிவண்டிகள் நான்கு மிதிவண்டிகள் + +CARDINAL ௫ ஜன்னல்கள் ஐந்து ஜன்னல்கள் + +CARDINAL ௬ கிளைகள் ஆறு கிளைகள் + +CARDINAL ௭ பொம்மைகள் ஏழு பொம்மைகள் + +CARDINAL ௮ கவிதைகள் எட்டு கவிதைகள் + +CARDINAL ௯ கதைகள் ஒன்பது கதைகள் + +CARDINAL ௧௦ கதைகள் பத்து கதைகள் + +CARDINAL ௭ மொட்டுகள் ஏழு மொட்டுகள் + +CARDINAL ௨ கோழிகள் இரண்டு கோழிகள் + +CARDINAL ௩ தெருக்கள் மூன்று தெருக்கள் + +CARDINAL ௪ தேதிகள் நான்கு தேதிகள் + +CARDINAL ௫ கருவிகள் ஐந்து கருவிகள் + +CARDINAL ௬ கன்னியர்கள் ஆறு கன்னியர்கள் + +CARDINAL ௭ தட்டுகள் ஏழு தட்டுகள் + +CARDINAL ௮ பெண்கள் எட்டு பெண்கள் + +CARDINAL ௯ இரவுகள் ஒன்பது இரவுகள் + +CARDINAL ௧௦ காய்கறிகள் பத்து காய்கறிகள் + +CARDINAL ௮ குழந்தைகள் எட்டு குழந்தைகள் + +CARDINAL ௨ தொப்பிகள் இரண்டு தொப்பிகள் + +CARDINAL ௩ சிறுமிகள் மூன்று சிறுமிகள் + +CARDINAL ௪ நதிகள் நான்கு நதிகள் + +CARDINAL ௫ பெண்கள் ஐந்து பெண்கள் + +CARDINAL ௬ பொட்டுகள் ஆறு பொட்டுகள் + +CARDINAL ௭ பெட்டிகள் ஏழு பெட்டிகள் + +CARDINAL ௯ பொம்மைகள் ஒன்பது பொம்மைகள் + +CARDINAL ௧௦ கதைகள் பத்து கதைகள் + +CARDINAL ௯ இதழ்கள் ஒன்பது இதழ்கள் + +CARDINAL ௨ கொடிகள் இரண்டு கொடிகள் + +CARDINAL ௩ கவிதைகள் மூன்று கவிதைகள் + +CARDINAL ௪ ஏரிகள் நான்கு ஏரிகள் + +CARDINAL ௫ செருப்புகள் ஐந்து செருப்புகள் + +CARDINAL ௬ பசுக்கள் ஆறு பசுக்கள் + +CARDINAL ௭ சாலைகள் ஏழு சாலைகள் + +CARDINAL ௮ கண்கள் எட்டு கண்கள் + +CARDINAL ௧௦ பேச்சுகள் பத்து பேச்சுகள் + +CARDINAL ௧௦௧ நூற்று ஒன்று + +CARDINAL ௧௦௨ நூற்று இரண்டு + +CARDINAL ௧௦௩ நூற்று மூன்று + +CARDINAL ௧௦௪ நூற்று நான்கு + +CARDINAL ௧௦௫ நூற்று ஐந்து + +CARDINAL ௧௦௬ நூற்று ஆறு + +CARDINAL ௧௦௭ நூற்று ஏழு + +CARDINAL ௧௦௮ நூற்று எட்டு + +CARDINAL ௧௦௯ நூற்று ஒன்பது + +CARDINAL ௧௧௦ நூற்று பத்து + +CARDINAL ௧௧௧ நூற்று பதினொன்று + +CARDINAL ௧௧௨ நூற்று பன்னிரண்டு + +CARDINAL ௧௧௩ நூற்று பதிமூன்று + +CARDINAL ௧௧௪ நூற்று பதினான்கு + +CARDINAL ௧௧௫ நூற்று பதினைந்து + +CARDINAL ௧௧௬ நூற்று பதினாறு + +CARDINAL ௮௧௭ எட்டுநூற்று பதினேழு + +CARDINAL ௮௧௮ எட்டுநூற்று பதினெட்டு + +CARDINAL ௮௧௯ எட்டுநூற்று பத்தொன்பது + +CARDINAL ௮௨௦ எட்டுநூற்று இருபது + +CARDINAL ௮௨௧ எட்டுநூற்று இருபத்து ஒன்று + +CARDINAL ௮௨௨ எட்டுநூற்று இருபத்து இரண்டு + +CARDINAL ௮௨௩ எட்டுநூற்று இருபத்து மூன்று + +CARDINAL ௮௨௪ எட்டுநூற்று இருபத்து நான்கு + +CARDINAL ௮௨௫ எட்டுநூற்று இருபத்து ஐந்து + +CARDINAL ௮௨௬ எட்டுநூற்று இருபத்து ஆறு + +CARDINAL ௮௨௭ எட்டுநூற்று இருபத்து ஏழு + +CARDINAL ௮௨௮ எட்டுநூற்று இருபத்து எட்டு + +CARDINAL ௮௨௯ எட்டுநூற்று இருபத்து ஒன்பது + +CARDINAL ௮௩௦ எட்டுநூற்று முப்பது + +CARDINAL ௮௩௧ எட்டுநூற்று முப்பத்து ஒன்று + +CARDINAL ௮௩௨ எட்டுநூற்று முப்பத்து இரண்டு + +CARDINAL ௮௩௩ எட்டுநூற்று முப்பத்து மூன்று + +CARDINAL ௮௩௪ எட்டுநூற்று முப்பத்து நான்கு + +CARDINAL ௮௩௫ எட்டுநூற்று முப்பத்து ஐந்து + +CARDINAL ௮௩௬ எட்டுநூற்று முப்பத்து ஆறு + +CARDINAL ௭௩௮ எழுநூற்று முப்பத்து எட்டு + +CARDINAL ௭௩௯ எழுநூற்று முப்பத்து ஒன்பது + +CARDINAL ௭௪௦ எழுநூற்று நாற்பது + +CARDINAL ௭௪௧ எழுநூற்று நாற்பத்து ஒன்று + +CARDINAL ௭௪௨ எழுநூற்று நாற்பத்து இரண்டு + +CARDINAL ௭௪௩ எழுநூற்று நாற்பத்து மூன்று + +CARDINAL ௭௪௪ எழுநூற்று நாற்பத்து நான்கு + +CARDINAL ௭௪௫ எழுநூற்று நாற்பத்து ஐந்து + +CARDINAL ௪௪௬ நானூற்று நாற்பத்து ஆறு + +CARDINAL ௪௪௭ நானூற்று நாற்பத்து ஏழு + +CARDINAL ௪௪௮ நானூற்று நாற்பத்து எட்டு + +CARDINAL ௪௪௯ நானூற்று நாற்பத்து ஒன்பது + +CARDINAL ௪௫௦ நானூற்று ஐம்பது + +CARDINAL ௪௬௧ நானூற்று அறுபத்து ஒன்று + +CARDINAL ௧௭௫ நூற்று எழுபத்து ஐந்து + +CARDINAL ௧௮௧ நூற்று எண்பத்து ஒன்று + +CARDINAL ௧௯௦ நூற்று தொண்ணூறு + +CARDINAL ௧௯௯ நூற்று தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௧ ஆயிரத்து ஒன்று + +CARDINAL ௧௦௦௨ ஆயிரத்து இரண்டு + +CARDINAL ௧௦௦௩ ஆயிரத்து மூன்று + +CARDINAL ௧௦௦௪ ஆயிரத்து நான்கு + +CARDINAL ௧௦௦௫ ஆயிரத்து ஐந்து + +CARDINAL ௧௦௦௬ ஆயிரத்து ஆறு + +CARDINAL ௧௦௦௭ ஆயிரத்து ஏழு + +CARDINAL ௧௦௦௮ ஆயிரத்து எட்டு + +CARDINAL ௧௦௦௯ ஆயிரத்து ஒன்பது + +CARDINAL ௧௦௧௦ ஆயிரத்து பத்து + +CARDINAL ௧௦௧௧ ஆயிரத்து பதினொன்று + +CARDINAL ௧௦௧௨ ஆயிரத்து பன்னிரண்டு + +CARDINAL ௧௦௧௩ ஆயிரத்து பதிமூன்று + +CARDINAL ௧௦௧௪ ஆயிரத்து பதினான்கு + +CARDINAL ௧௦௧௫ ஆயிரத்து பதினைந்து + +CARDINAL ௧௦௧௬ ஆயிரத்து பதினாறு + +CARDINAL ௧௦௧௭ ஆயிரத்து பதினேழு + +CARDINAL ௧௦௧௮ ஆயிரத்து பதினெட்டு + +CARDINAL ௧௦௧௯ ஆயிரத்து பத்தொன்பது + +CARDINAL ௧௦௨௦ ஆயிரத்து இருபது + +CARDINAL ௧௦௨௧ ஆயிரத்து இருபத்து ஒன்று + +CARDINAL ௧௦௨௨ ஆயிரத்து இருபத்து இரண்டு + +CARDINAL ௧௧௨௩ ஆயிரத்து நூற்று இருபத்து மூன்று + +CARDINAL ௧௪௨௪ ஆயிரத்து நானூற்று இருபத்து நான்கு + +CARDINAL ௧௫௨௫ ஆயிரத்து ஐந்நூற்று இருபத்து ஐந்து + +CARDINAL ௧௩௨௬ ஆயிரத்து முந்நூற்று இருபத்து ஆறு + +CARDINAL ௧௪௨௭ ஆயிரத்து நானூற்று இருபத்து ஏழு + +CARDINAL ௧௬௨௮ ஆயிரத்து அறுநூற்று இருபத்து எட்டு + +CARDINAL ௧௭௨௯ ஆயிரத்து எழுநூற்று இருபத்து ஒன்பது + +CARDINAL ௧௮௩௦ ஆயிரத்து எட்டுநூற்று முப்பது + +CARDINAL ௧௧௩௧ ஆயிரத்து நூற்று முப்பத்து ஒன்று + +CARDINAL ௧௨௩௨ ஆயிரத்து இருநூற்று முப்பத்து இரண்டு + +CARDINAL ௧௩௩௩ ஆயிரத்து முந்நூற்று முப்பத்து மூன்று + +CARDINAL ௧௪௩௪ ஆயிரத்து நானூற்று முப்பத்து நான்கு + +CARDINAL ௧௫௩௫ ஆயிரத்து ஐந்நூற்று முப்பத்து ஐந்து + +CARDINAL ௧௬௩௬ ஆயிரத்து அறுநூற்று முப்பத்து ஆறு + +CARDINAL ௧௭௩௭ ஆயிரத்து எழுநூற்று முப்பத்து ஏழு + +CARDINAL ௧௮௩௮ ஆயிரத்து எட்டுநூற்று முப்பத்து எட்டு + +CARDINAL ௧௯௩௯ ஆயிரத்து ஒன்பதுநூற்று முப்பத்து ஒன்பது + +CARDINAL ௧௦௪௦ ஆயிரத்து நாற்பது + +CARDINAL ௧௦௪௧ ஆயிரத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௪௨ ஆயிரத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௪௩ ஆயிரத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௪௪ ஆயிரத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௪௫ ஆயிரத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௪௬ ஆயிரத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௪௭ ஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௪௮ ஆயிரத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௪௯ ஆயிரத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௫௦ ஆயிரத்து ஐம்பது + +CARDINAL ௧௦௬௧ ஆயிரத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௭௫ ஆயிரத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௮௧ ஆயிரத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௯௦ ஆயிரத்து தொண்ணூறு + +CARDINAL ௧௦௯௯ ஆயிரத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௧ பத்துஆயிரத்து ஒன்று + +CARDINAL ௧௦௦௦௨ பத்துஆயிரத்து இரண்டு + +CARDINAL ௧௦௨௦௩ பத்துஆயிரத்து இருநூற்று மூன்று + +CARDINAL ௧௦௩௦௪ பத்துஆயிரத்து முந்நூற்று நான்கு + +CARDINAL ௧௧௩௦௫ பதினொன்றுஆயிரத்து முந்நூற்று ஐந்து + +CARDINAL ௧௨௪௫௬ பன்னிரண்டுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௧௩௦௪௭ பதிமூன்றுஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௮ பத்துஆயிரத்து எட்டு + +CARDINAL ௧௦௦௦௯ பத்துஆயிரத்து ஒன்பது + +CARDINAL ௧௦௦௧௦ பத்துஆயிரத்து பத்து + +CARDINAL ௧௦௦௧௧ பத்துஆயிரத்து பதினொன்று + +CARDINAL ௧௦௦௧௨ பத்துஆயிரத்து பன்னிரண்டு + +CARDINAL ௧௦௦௧௩ பத்துஆயிரத்து பதிமூன்று + +CARDINAL ௧௦௦௧௪ பத்துஆயிரத்து பதினான்கு + +CARDINAL ௧௦௦௧௫ பத்துஆயிரத்து பதினைந்து + +CARDINAL ௧௦௦௧௬ பத்துஆயிரத்து பதினாறு + +CARDINAL ௧௦௦௧௭ பத்துஆயிரத்து பதினேழு + +CARDINAL ௧௦௦௧௮ பத்துஆயிரத்து பதினெட்டு + +CARDINAL ௧௦௦௧௯ பத்துஆயிரத்து பத்தொன்பது + +CARDINAL ௧௦௦௨௦ பத்துஆயிரத்து இருபது + +CARDINAL ௧௦௦௨௧ பத்துஆயிரத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௨௨ பத்துஆயிரத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௨௩ பத்துஆயிரத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௨௪ பத்துஆயிரத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௨௫ பத்துஆயிரத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௨௬ பத்துஆயிரத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௨௭ பத்துஆயிரத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௨௮ பத்துஆயிரத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௨௯ பத்துஆயிரத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௩௦ பத்துஆயிரத்து முப்பது + +CARDINAL ௧௦௦௩௧ பத்துஆயிரத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௩௨ பத்துஆயிரத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௩௩ பத்துஆயிரத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௩௪ பத்துஆயிரத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௩௫ பத்துஆயிரத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௩௬ பத்துஆயிரத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௩௭ பத்துஆயிரத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௩௮ பத்துஆயிரத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௩௯ பத்துஆயிரத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௪௦ பத்துஆயிரத்து நாற்பது + +CARDINAL ௧௦௦௪௧ பத்துஆயிரத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௪௨ பத்துஆயிரத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௪௩ பத்துஆயிரத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௪௪ பத்துஆயிரத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௪௫ பத்துஆயிரத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௪௬ பத்துஆயிரத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௪௭ பத்துஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௪௮ பத்துஆயிரத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௪௯ பத்துஆயிரத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௫௦ பத்துஆயிரத்து ஐம்பது + +CARDINAL ௧௦௦௬௧ பத்துஆயிரத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௭௫ பத்துஆயிரத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௮௧ பத்துஆயிரத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௯௦ பத்துஆயிரத்து தொண்ணூறு + +CARDINAL ௧௦௦௯௯ பத்துஆயிரத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௧ ஒன்று இலட்சத்து ஒன்று + +CARDINAL ௧௧௦௦௦௨ ஒன்று இலட்சத்து பத்துஆயிரத்து இரண்டு + +CARDINAL ௧௨௦௪௦௩ ஒன்று இலட்சத்து இருபதுஆயிரத்து நானூற்று மூன்று + +CARDINAL ௧௪௧௫௦௪ ஒன்று இலட்சத்து நாற்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று நான்கு + +CARDINAL ௧௫௧௫௧௫ ஒன்று இலட்சத்து ஐம்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று பதினைந்து + +CARDINAL ௧௦௦௦௦௬ ஒன்று இலட்சத்து ஆறு + +CARDINAL ௧௦௦௦௦௭ ஒன்று இலட்சத்து ஏழு + +CARDINAL ௧௦௦௦௦௮ ஒன்று இலட்சத்து எட்டு + +CARDINAL ௧௦௦௦௦௯ ஒன்று இலட்சத்து ஒன்பது + +CARDINAL ௧௦௦௦௧௦ ஒன்று இலட்சத்து பத்து + +CARDINAL ௧௦௦௦௧௧ ஒன்று இலட்சத்து பதினொன்று + +CARDINAL ௧௦௦௦௧௨ ஒன்று இலட்சத்து பன்னிரண்டு + +CARDINAL ௧௦௦௦௧௩ ஒன்று இலட்சத்து பதிமூன்று + +CARDINAL ௧௦௦௦௧௪ ஒன்று இலட்சத்து பதினான்கு + +CARDINAL ௧௦௦௦௧௫ ஒன்று இலட்சத்து பதினைந்து + +CARDINAL ௧௦௦௦௧௬ ஒன்று இலட்சத்து பதினாறு + +CARDINAL ௧௦௦௦௧௭ ஒன்று இலட்சத்து பதினேழு + +CARDINAL ௧௦௦௦௧௮ ஒன்று இலட்சத்து பதினெட்டு + +CARDINAL ௧௦௦௦௧௯ ஒன்று இலட்சத்து பத்தொன்பது + +CARDINAL ௧௦௦௦௨௦ ஒன்று இலட்சத்து இருபது + +CARDINAL ௧௦௦௦௨௧ ஒன்று இலட்சத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௨௨ ஒன்று இலட்சத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௨௩ ஒன்று இலட்சத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௦௨௪ ஒன்று இலட்சத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௦௨௫ ஒன்று இலட்சத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௨௬ ஒன்று இலட்சத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௦௨௭ ஒன்று இலட்சத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௦௨௮ ஒன்று இலட்சத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௦௨௯ ஒன்று இலட்சத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௩௦ ஒன்று இலட்சத்து முப்பது + +CARDINAL ௧௦௦௦௩௧ ஒன்று இலட்சத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௩௨ ஒன்று இலட்சத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௩௩ ஒன்று இலட்சத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௩௪ ஒன்று இலட்சத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௩௫ ஒன்று இலட்சத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௩௬ ஒன்று இலட்சத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௩௭ ஒன்று இலட்சத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௩௮ ஒன்று இலட்சத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௩௯ ஒன்று இலட்சத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௪௦ ஒன்று இலட்சத்து நாற்பது + +CARDINAL ௧௦௦௦௪௧ ஒன்று இலட்சத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௪௨ ஒன்று இலட்சத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௪௩ ஒன்று இலட்சத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௪௪ ஒன்று இலட்சத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௪௫ ஒன்று இலட்சத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௪௬ ஒன்று இலட்சத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௪௭ ஒன்று இலட்சத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௪௮ ஒன்று இலட்சத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௪௯ ஒன்று இலட்சத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௫௦ ஒன்று இலட்சத்து ஐம்பது + +CARDINAL ௧௦௦௦௬௧ ஒன்று இலட்சத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௭௫ ஒன்று இலட்சத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௮௧ ஒன்று இலட்சத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௯௦ ஒன்று இலட்சத்து தொண்ணூறு + +CARDINAL ௧௦௦௦௯௯ ஒன்று இலட்சத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௦௧ பத்து இலட்சத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௨ பத்து இலட்சத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௩ பத்து இலட்சத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௪ பத்து இலட்சத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௫ பத்து இலட்சத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௬ பத்து இலட்சத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௭ பத்து இலட்சத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௮ பத்து இலட்சத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௯ பத்து இலட்சத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௧௦ பத்து இலட்சத்து பத்து + +CARDINAL ௧௦௦௦௦௧௧ பத்து இலட்சத்து பதினொன்று + +CARDINAL ௧௦௦௦௦௧௨ பத்து இலட்சத்து பன்னிரண்டு + +CARDINAL ௧௦௦௦௦௧௩ பத்து இலட்சத்து பதிமூன்று + +CARDINAL ௧௦௦௦௦௧௪ பத்து இலட்சத்து பதினான்கு + +CARDINAL ௧௦௦௦௦௧௫ பத்து இலட்சத்து பதினைந்து + +CARDINAL ௧௦௦௦௦௧௬ பத்து இலட்சத்து பதினாறு + +CARDINAL ௧௦௦௦௦௧௭ பத்து இலட்சத்து பதினேழு + +CARDINAL ௧௦௦௦௦௧௮ பத்து இலட்சத்து பதினெட்டு + +CARDINAL ௧௦௦௦௦௧௯ பத்து இலட்சத்து பத்தொன்பது + +CARDINAL ௧௦௦௦௦௨௦ பத்து இலட்சத்து இருபது + +CARDINAL ௧௦௦௦௦௨௧ பத்து இலட்சத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௨௨ பத்து இலட்சத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௦௨௩ பத்து இலட்சத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௦௦௨௪ பத்து இலட்சத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௦௦௨௫ பத்து இலட்சத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௨௬ பத்து இலட்சத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௦௦௨௭ பத்து இலட்சத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௦௦௨௮ பத்து இலட்சத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௦௦௨௯ பத்து இலட்சத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௩௦ பத்து இலட்சத்து முப்பது + +CARDINAL ௧௦௦௦௦௩௧ பத்து இலட்சத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௩௨ பத்து இலட்சத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௩௩ பத்து இலட்சத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௩௪ பத்து இலட்சத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௩௫ பத்து இலட்சத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௩௬ பத்து இலட்சத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௩௭ பத்து இலட்சத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௩௮ பத்து இலட்சத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௩௯ பத்து இலட்சத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௪௦ பத்து இலட்சத்து நாற்பது + +CARDINAL ௧௦௦௦௦௪௧ பத்து இலட்சத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௪௨ பத்து இலட்சத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௪௩ பத்து இலட்சத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௪௪ பத்து இலட்சத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௪௫ பத்து இலட்சத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௪௬ பத்து இலட்சத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௪௭ பத்து இலட்சத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௪௮ பத்து இலட்சத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௪௯ பத்து இலட்சத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௫௦ பத்து இலட்சத்து ஐம்பது + +CARDINAL ௧௦௦௦௦௬௧ பத்து இலட்சத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௭௫ பத்து இலட்சத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௮௧ பத்து இலட்சத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௯௦ பத்து இலட்சத்து தொண்ணூறு + +CARDINAL ௧௦௦௦௦௯௯ பத்து இலட்சத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௦௦௧ ஒன்று கோடியே ஒன்று + +CARDINAL ௧௦௦௦௦௦௦௨ ஒன்று கோடியே இரண்டு + +CARDINAL ௧௦௦௦௦௦௦௩ ஒன்று கோடியே மூன்று + +CARDINAL ௧௦௦௦௦௦௦௪ ஒன்று கோடியே நான்கு + +CARDINAL ௧௦௦௦௦௦௦௫ ஒன்று கோடியே ஐந்து + +CARDINAL ௧௦௦௦௦௦௦௬ ஒன்று கோடியே ஆறு + +CARDINAL ௧௦௦௦௦௦௦௭ ஒன்று கோடியே ஏழு + +CARDINAL ௧௦௦௦௦௦௦௮ ஒன்று கோடியே எட்டு + +CARDINAL ௧௦௦௦௦௦௦௯ ஒன்று கோடியே ஒன்பது + +CARDINAL ௧௦௦௦௦௦௧௦ ஒன்று கோடியே பத்து + +CARDINAL ௧௦௦௦௦௦௧௧ ஒன்று கோடியே பதினொன்று + +CARDINAL ௧௦௦௦௦௦௧௨ ஒன்று கோடியே பன்னிரண்டு + +CARDINAL ௧௦௦௦௦௦௧௩ ஒன்று கோடியே பதிமூன்று + +CARDINAL ௧௦௦௦௦௦௧௪ ஒன்று கோடியே பதினான்கு + +CARDINAL ௧௦௦௦௦௦௧௫ ஒன்று கோடியே பதினைந்து + +CARDINAL ௧௦௦௦௦௦௧௬ ஒன்று கோடியே பதினாறு + +CARDINAL ௧௦௦௦௦௦௧௭ ஒன்று கோடியே பதினேழு + +CARDINAL ௧௦௦௦௦௦௧௮ ஒன்று கோடியே பதினெட்டு + +CARDINAL ௧௦௦௦௦௦௧௯ ஒன்று கோடியே பத்தொன்பது + +CARDINAL ௧௦௦௦௦௦௨௦ ஒன்று கோடியே இருபது + +CARDINAL ௧௦௦௦௦௦௨௧ ஒன்று கோடியே இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௨௨ ஒன்று கோடியே இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௨௩ ஒன்று கோடியே இருபத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௨௪ ஒன்று கோடியே இருபத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௨௫ ஒன்று கோடியே இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௨௬ ஒன்று கோடியே இருபத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௨௭ ஒன்று கோடியே இருபத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௨௮ ஒன்று கோடியே இருபத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௨௯ ஒன்று கோடியே இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௩௦ ஒன்று கோடியே முப்பது + +CARDINAL ௧௦௦௦௦௦௩௧ ஒன்று கோடியே முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௩௨ ஒன்று கோடியே முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௩௩ ஒன்று கோடியே முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௩௪ ஒன்று கோடியே முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௩௫ ஒன்று கோடியே முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௩௬ ஒன்று கோடியே முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௩௭ ஒன்று கோடியே முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௩௮ ஒன்று கோடியே முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௩௯ ஒன்று கோடியே முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௪௦ ஒன்று கோடியே நாற்பது + +CARDINAL ௧௦௦௦௦௦௪௧ ஒன்று கோடியே நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௪௨ ஒன்று கோடியே நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௪௩ ஒன்று கோடியே நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௪௪ ஒன்று கோடியே நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௪௫ ஒன்று கோடியே நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௪௬ ஒன்று கோடியே நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௪௭ ஒன்று கோடியே நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௪௮ ஒன்று கோடியே நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௪௯ ஒன்று கோடியே நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௫௦ ஒன்று கோடியே ஐம்பது + +CARDINAL ௧௦௦௦௦௦௬௧ ஒன்று கோடியே அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௭௫ ஒன்று கோடியே எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௮௧ ஒன்று கோடியே எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௯௦ ஒன்று கோடியே தொண்ணூறு + +CARDINAL ௧௦௦௦௦௦௯௯ ஒன்று கோடியே தொண்ணூற்று ஒன்பது + +CARDINAL ௧௩௨௩ ஆயிரத்து முந்நூற்று இருபத்து மூன்று + +CARDINAL ௧௩௪௫ ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து + +CARDINAL ௧௩௪௫௬ பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௧௨௩௪௬ பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு + +CARDINAL ௧௨௩௪௫௬ ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௮௭௨௯௮௭ எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு + +CARDINAL ௯௮௭௬௦௯ ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது + +CARDINAL ௯௮௭௬௭௮௯ தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது + +CARDINAL ௨௩௪௫௫௬௭ இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௨௩௪௫௫௬௭ ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௨௧௨௧௨௧௨௨ பன்னிரண்டு கோடியே பன்னிரண்டு இலட்சத்து பன்னிரண்டுஆயிரத்து நூற்று இருபத்து இரண்டு + +CARDINAL ௧௦௦௨௩௪௫௫௬௭ ஒன்று அரபு இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௧௨௨௩௪௫௫௬௭ ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௦௨௨௩௪௫௫௬௭ ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௧௦௨௨௩௪௫௫௬௭ பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௫௧௦௨௨௩௪௫௫௬௭ ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + diff --git a/nemo_text_processing/text_normalization/normalize.py b/nemo_text_processing/text_normalization/normalize.py index d8ebf2f4d..01d8f3354 100644 --- a/nemo_text_processing/text_normalization/normalize.py +++ b/nemo_text_processing/text_normalization/normalize.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -163,9 +163,10 @@ def __init__( from nemo_text_processing.text_normalization.hi.taggers.tokenize_and_classify import ClassifyFst from nemo_text_processing.text_normalization.hi.verbalizers.post_processing import PostProcessingFst from nemo_text_processing.text_normalization.hi.verbalizers.verbalize_final import VerbalizeFinalFst - + if post_process: self.post_processor = PostProcessingFst(cache_dir=cache_dir, overwrite_cache=overwrite_cache) + elif lang == 'it': from nemo_text_processing.text_normalization.it.taggers.tokenize_and_classify import ClassifyFst from nemo_text_processing.text_normalization.it.verbalizers.verbalize_final import VerbalizeFinalFst @@ -191,6 +192,13 @@ def __init__( elif lang == 'ko': from nemo_text_processing.text_normalization.ko.taggers.tokenize_and_classify import ClassifyFst from nemo_text_processing.text_normalization.ko.verbalizers.verbalize_final import VerbalizeFinalFst + elif lang == 'ta': + from nemo_text_processing.text_normalization.ta.taggers.tokenize_and_classify import ClassifyFst + from nemo_text_processing.text_normalization.ta.verbalizers.post_processing import PostProcessingFst + from nemo_text_processing.text_normalization.ta.verbalizers.verbalize_final import VerbalizeFinalFst + + if post_process: + self.post_processor = PostProcessingFst(cache_dir=cache_dir, overwrite_cache=overwrite_cache) else: raise NotImplementedError(f"Language {lang} has not been supported yet.") @@ -391,7 +399,7 @@ def normalize( return text output = SPACE_DUP.sub(' ', output[1:]) - if self.lang in ["en", "hi", "vi"] and hasattr(self, 'post_processor') and self.post_processor is not None: + if self.lang in ["en", "hi", "ta", "vi"] and hasattr(self, 'post_processor') and self.post_processor is not None: output = self.post_process(output) if punct_post_process: @@ -737,7 +745,7 @@ def parse_args(): parser.add_argument( "--language", help="language", - choices=["en", "de", "es", "fr", "hu", "sv", "zh", "ar", "it", "hy", "ja", "hi", "ko", "vi", "pt"], + choices=["en", "de", "es", "fr", "hu", "sv", "zh", "ar", "it", "hy", "ja", "hi", "ta", "ko", "vi", "pt"], default="en", type=str, ) diff --git a/nemo_text_processing/text_normalization/run_evaluate.py b/nemo_text_processing/text_normalization/run_evaluate.py index 3a1964bbd..fd0fac207 100644 --- a/nemo_text_processing/text_normalization/run_evaluate.py +++ b/nemo_text_processing/text_normalization/run_evaluate.py @@ -35,7 +35,7 @@ def parse_args(): parser.add_argument( "--lang", help="language", - choices=['ar', 'de', 'en', 'es', 'fr', 'hu', 'it', 'ru', 'sv', 'zh', 'hy', 'hi', 'ko', 'vi', 'pt'], + choices=['ar', 'de', 'en', 'es', 'fr', 'hu', 'it', 'ru', 'sv', 'zh', 'hy', 'hi', 'ta', 'ko', 'vi', 'pt'], default="en", type=str, ) @@ -67,6 +67,10 @@ def parse_args(): to_lower = args.input_case == "lower_cased" training_data = load_files([file_path], to_lower=to_lower) + # print("Loading training data: " + file_path) + # to_lower = True if args.input_case == "lower_cased" else False + # training_data = load_files([file_path], to_lower=to_lower) + if args.filter: training_data = filter_loaded_data(training_data) diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv index d61749cbd..92111ede3 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/digit.tsv @@ -1,3 +1,12 @@ +௧ ஒன்று +௨ இரண்டு +௩ மூன்று +௪ நான்கு +௫ ஐந்து +௬ ஆறு +௭ ஏழு +௮ எட்டு +௯ ஒன்பது 1 ஒன்று 2 இரண்டு 3 மூன்று diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv new file mode 100644 index 000000000..29621c1a9 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv @@ -0,0 +1,18 @@ +100 நூறு +200 இருநூற்று +300 முந்நூற்று +400 நானூற்று +500 ஐந்நூற்று +600 அறுநூற்று +700 எழுநூற்று +800 எட்டுநூற்று +900 ஒன்பதுநூற்று +௧௦௦ நூறு +௨௦௦ இருநூற்று +௩௦௦ முந்நூற்று +௪௦௦ நானூற்று +௫௦௦ ஐந்நூற்று +௬௦௦ அறுநூற்று +௭௦௦ எழுநூற்று +௮௦௦ எட்டுநூற்று +௯௦௦ ஒன்பதுநூற்று \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv index 21f9f65ef..4b1c3686c 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv @@ -1,90 +1,90 @@ -10 பத்து -11 பதினொன்று -12 பன்னிரண்டு -13 பதின்மூன்று -14 பதினான்கு -15 பதினைந்து -16 பதினாறு -17 பதினேழு -18 பதினெட்டு -19 பத்தொன்பது -20 இருபது -21 இருபத்தொன்று -22 இருபத்திரண்டு -23 இருபத்துமூன்று -24 இருபத்துநான்கு -25 இருபத்தைந்து -26 இருபத்தாறு -27 இருபத்தேழு -28 இருபத்தெட்டு -29 இருபத்தொன்பது -30 முப்பது -31 முப்பத்தொன்று -32 முப்பத்திரண்டு -33 முப்பத்துமூன்று -34 முப்பத்துநான்கு -35 முப்பத்தைந்து -36 முப்பத்தாறு -37 முப்பத்தேழு -38 முப்பத்தெட்டு -39 முப்பத்தொன்பது -40 நாற்பது -41 நாற்பத்தொன்று -42 நாற்பத்திரண்டு -43 நாற்பத்துமூன்று -44 நாற்பத்துநான்கு -45 நாற்பத்தைந்து -46 நாற்பத்தாறு -47 நாற்பத்தேழு -48 நாற்பத்தெட்டு -49 நாற்பத்தொன்பது -50 ஐம்பது -51 ஐம்பத்தொன்று -52 ஐம்பத்திரண்டு -53 ஐம்பத்துமூன்று -54 ஐம்பத்துநான்கு -55 ஐம்பத்தைந்து -56 ஐம்பத்தாறு -57 ஐம்பத்தேழு -58 ஐம்பத்தெட்டு -59 ஐம்பத்தொன்பது -60 அறுபது -61 அறுபத்தொன்று -62 அறுபத்திரண்டு -63 அறுபத்துமூன்று -64 அறுபத்துநான்கு -65 அறுபத்தைந்து -66 அறுபத்தாறு -67 அறுபத்தேழு -68 அறுபத்தெட்டு -69 அறுபத்தொன்பது -70 எழுபது -71 எழுபத்தொன்று -72 எழுபத்திரண்டு -73 எழுபத்துமூன்று -74 எழுபத்துநான்கு -75 எழுபத்தைந்து -76 எழுபத்தாறு -77 எழுபத்தேழு -78 எழுபத்தெட்டு -79 எழுபத்தொன்பது -80 எண்பது -81 எண்பத்தொன்று -82 எண்பத்திரண்டு -83 எண்பத்துமூன்று -84 எண்பத்துநான்கு -85 எண்பத்தைந்து -86 எண்பத்தாறு -87 எண்பத்தேழு -88 எண்பத்தெட்டு -89 எண்பத்தொன்பது -90 தொண்ணூறு -91 தொண்ணூற்றொன்று -92 தொண்ணூற்றிரண்டு -93 தொண்ணூற்றுமூன்று -94 தொண்ணூற்றுநான்கு -95 தொண்ணூற்றைந்து -96 தொண்ணூற்றாறு -97 தொண்ணூற்றேழு -98 தொண்ணூற்றெட்டு -99 தொண்ணூற்றொன்பது \ No newline at end of file +௧௦ பத்து +௧௧ பதினொன்று +௧௨ பன்னிரண்டு +௧௩ பதிமூன்று +௧௪ பதினான்கு +௧௫ பதினைந்து +௧௬ பதினாறு +௧௭ பதினேழு +௧௮ பதினெட்டு +௧௯ பத்தொன்பது +௨௦ இருபது +௨௧ இருபத்து ஒன்று +௨௨ இருபத்து இரண்டு +௨௩ இருபத்து மூன்று +௨௪ இருபத்து நான்கு +௨௫ இருபத்து ஐந்து +௨௬ இருபத்து ஆறு +௨௭ இருபத்து ஏழு +௨௮ இருபத்து எட்டு +௨௯ இருபத்து ஒன்பது +௩௦ முப்பது +௩௧ முப்பத்து ஒன்று +௩௨ முப்பத்து இரண்டு +௩௩ முப்பத்து மூன்று +௩௪ முப்பத்து நான்கு +௩௫ முப்பத்து ஐந்து +௩௬ முப்பத்து ஆறு +௩௭ முப்பத்து ஏழு +௩௮ முப்பத்து எட்டு +௩௯ முப்பத்து ஒன்பது +௪௦ நாற்பது +௪௧ நாற்பத்து ஒன்று +௪௨ நாற்பத்து இரண்டு +௪௩ நாற்பத்து மூன்று +௪௪ நாற்பத்து நான்கு +௪௫ நாற்பத்து ஐந்து +௪௬ நாற்பத்து ஆறு +௪௭ நாற்பத்து ஏழு +௪௮ நாற்பத்து எட்டு +௪௯ நாற்பத்து ஒன்பது +௫௦ ஐம்பது +௫௧ ஐம்பத்து ஒன்று +௫௨ ஐம்பத்து இரண்டு +௫௩ ஐம்பத்து மூன்று +௫௪ ஐம்பத்து நான்கு +௫௫ ஐம்பத்து ஐந்து +௫௬ ஐம்பத்து ஆறு +௫௭ ஐம்பத்து ஏழு +௫௮ ஐம்பத்து எட்டு +௫௯ ஐம்பத்து ஒன்பது +௬௦ அறுபது +௬௧ அறுபத்து ஒன்று +௬௨ அறுபத்து இரண்டு +௬௩ அறுபத்து மூன்று +௬௪ அறுபத்து நான்கு +௬௫ அறுபத்து ஐந்து +௬௬ அறுபத்து ஆறு +௬௭ அறுபத்து ஏழு +௬௮ அறுபத்து எட்டு +௬௯ அறுபத்து ஒன்பது +௭௦ எழுபது +௭௧ எழுபத்து ஒன்று +௭௨ எழுபத்து இரண்டு +௭௩ எழுபத்து மூன்று +௭௪ எழுபத்து நான்கு +௭௫ எழுபத்து ஐந்து +௭௬ எழுபத்து ஆறு +௭௭ எழுபத்து ஏழு +௭௮ எழுபத்து எட்டு +௭௯ எழுபத்து ஒன்பது +௮௦ எண்பது +௮௧ எண்பத்து ஒன்று +௮௨ எண்பத்து இரண்டு +௮௩ எண்பத்து மூன்று +௮௪ எண்பத்து நான்கு +௮௫ எண்பத்து ஐந்து +௮௬ எண்பத்து ஆறு +௮௭ எண்பத்து ஏழு +௮௮ எண்பத்து எட்டு +௮௯ எண்பத்து ஒன்பது +௯௦ தொண்ணூறு +௯௧ தொண்ணூற்று ஒன்று +௯௨ தொண்ணூற்று இரண்டு +௯௩ தொண்ணூற்று மூன்று +௯௪ தொண்ணூற்று நான்கு +௯௫ தொண்ணூற்று ஐந்து +௯௬ தொண்ணூற்று ஆறு +௯௭ தொண்ணூற்று ஏழு +௯௮ தொண்ணூற்று எட்டு +௯௯ தொண்ணூற்று ஒன்பது \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv new file mode 100644 index 000000000..5e4e47be4 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv @@ -0,0 +1,90 @@ +10 பத்து +11 பதினொன்று +12 பன்னிரண்டு +13 பதிமூன்று +14 பதினான்கு +15 பதினைந்து +16 பதினாறு +17 பதினேழு +18 பதினெட்டு +19 பத்தொன்பது +20 இருபது +21 இருபத்து ஒன்று +22 இருபத்து இரண்டு +23 இருபத்து மூன்று +24 இருபத்து நான்கு +25 இருபத்து ஐந்து +26 இருபத்து ஆறு +27 இருபத்து ஏழு +28 இருபத்து எட்டு +29 இருபத்து ஒன்பது +30 முப்பது +31 முப்பத்து ஒன்று +32 முப்பத்து இரண்டு +33 முப்பத்து மூன்று +34 முப்பத்து நான்கு +35 முப்பத்து ஐந்து +36 முப்பத்து ஆறு +37 முப்பத்து ஏழு +38 முப்பத்து எட்டு +39 முப்பத்து ஒன்பது +40 நாற்பது +41 நாற்பத்து ஒன்று +42 நாற்பத்து இரண்டு +43 நாற்பத்து மூன்று +44 நாற்பத்து நான்கு +45 நாற்பத்து ஐந்து +46 நாற்பத்து ஆறு +47 நாற்பத்து ஏழு +48 நாற்பத்து எட்டு +49 நாற்பத்து ஒன்பது +50 ஐம்பது +51 ஐம்பத்து ஒன்று +52 ஐம்பத்து இரண்டு +53 ஐம்பத்து மூன்று +54 ஐம்பத்து நான்கு +55 ஐம்பத்து ஐந்து +56 ஐம்பத்து ஆறு +57 ஐம்பத்து ஏழு +58 ஐம்பத்து எட்டு +59 ஐம்பத்து ஒன்பது +60 அறுபது +61 அறுபத்து ஒன்று +62 அறுபத்து இரண்டு +63 அறுபத்து மூன்று +64 அறுபத்து நான்கு +65 அறுபத்து ஐந்து +66 அறுபத்து ஆறு +67 அறுபத்து ஏழு +68 அறுபத்து எட்டு +69 அறுபத்து ஒன்பது +70 எழுபது +71 எழுபத்து ஒன்று +72 எழுபத்து இரண்டு +73 எழுபத்து மூன்று +74 எழுபத்து நான்கு +75 எழுபத்து ஐந்து +76 எழுபத்து ஆறு +77 எழுபத்து ஏழு +78 எழுபத்து எட்டு +79 எழுபத்து ஒன்பது +80 எண்பது +81 எண்பத்து ஒன்று +82 எண்பத்து இரண்டு +83 எண்பத்து மூன்று +84 எண்பத்து நான்கு +85 எண்பத்து ஐந்து +86 எண்பத்து ஆறு +87 எண்பத்து ஏழு +88 எண்பத்து எட்டு +89 எண்பத்து ஒன்பது +90 தொண்ணூறு +91 தொண்ணூற்று ஒன்று +92 தொண்ணூற்று இரண்டு +93 தொண்ணூற்று மூன்று +94 தொண்ணூற்று நான்கு +95 தொண்ணூற்று ஐந்து +96 தொண்ணூற்று ஆறு +97 தொண்ணூற்று ஏழு +98 தொண்ணூற்று எட்டு +99 தொண்ணூற்று ஒன்பது \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv new file mode 100644 index 000000000..31515f0f6 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv @@ -0,0 +1,8 @@ +௧௦௦௦ ஆயிரம் +௧௦௦௦௦௦ லட்சம் +௧௦௦௦௦௦௦௦ கோடி +௧௦௦௦௦௦௦௦௦௦ அரபு +௧௦௦௦௦௦௦௦௦௦௦௦ கரபு +௧௦௦௦௦௦௦௦௦௦௦௦௦௦ நீல் +௧௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦ பத்மம் +௧௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦ சங்கம் diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv index 13de36a14..c5011b29f 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/zero.tsv @@ -1 +1,2 @@ +௦ சுழியம் 0 சுழியம் \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 854bcb8e5..20082e127 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -26,26 +26,26 @@ NEMO_CHAR = utf8.VALID_UTF8_CHAR NEMO_DIGIT = byte.DIGIT -NEMO_HI_DIGIT = pynini.union("०", "१", "२", "३", "४", "५", "६", "७", "८", "९").optimize() -NEMO_HI_NON_ZERO = pynini.union("१", "२", "३", "४", "५", "६", "७", "८", "९").optimize() -NEMO_HI_ZERO = "०" -# Combined Hindi and Arabic digits for graphs that need to accept both -NEMO_ALL_DIGIT = pynini.union(NEMO_HI_DIGIT, NEMO_DIGIT).optimize() -NEMO_ALL_ZERO = pynini.union("०", "0").optimize() -NEMO_ALL_NON_ZERO = pynini.union(NEMO_HI_NON_ZERO, "1", "2", "3", "4", "5", "6", "7", "8", "9").optimize() - -HI_DEDH = "डेढ़" # 1.5 -HI_DHAI = "ढाई" # 2.5 -HI_SAVVA = "सवा" # quarter more (1.25) -HI_SADHE = "साढ़े" # half more (X.5) -HI_PAUNE = "पौने" # quarter less (0.75) - -# Hindi decimal representations -HI_POINT_FIVE = ".५" # .5 -HI_ONE_POINT_FIVE = "१.५" # 1.5 -HI_TWO_POINT_FIVE = "२.५" # 2.5 -HI_DECIMAL_25 = ".२५" # .25 -HI_DECIMAL_75 = ".७५" # .75 +NEMO_TA_DIGIT = pynini.union("௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯").optimize() +NEMO_TA_NON_ZERO = pynini.union("௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯").optimize() +NEMO_TA_ZERO = "௦" +# Combined TAMIL and Arabic digits for graphs that need to accept both +NEMO_ALL_DIGIT = pynini.union(NEMO_TA_DIGIT, NEMO_DIGIT).optimize() +NEMO_ALL_ZERO = pynini.union("௦", "0").optimize() +NEMO_ALL_NON_ZERO = pynini.union(NEMO_TA_NON_ZERO, "1", "2", "3", "4", "5", "6", "7", "8", "9").optimize() + +TA_ONRARAI = "ஒன்றரை" # 1.5 +TA_IRANDARAI = "இரண்டரை" # 2.5 +TA_ONRUKAAL = "ஒன்றுகால்" # quarter more (1.25) +TA_ARAI = "அரை" # half more (X.5) +TA_MUKKAAL = "முக்கால்" # quarter less (0.75) + +# Tamil decimal representations +TA_POINT_FIVE = ".௫" # .5 +TA_ONE_POINT_FIVE = "௧.௫" # 1.5 +TA_TWO_POINT_FIVE = "௨.௫" # 2.5 +TA_DECIMAL_25 = ".௨௫" # .25 +TA_DECIMAL_75 = ".௭௫" # .75 # Arabic/English decimal representations EN_POINT_FIVE = ".5" @@ -54,15 +54,15 @@ EN_DECIMAL_25 = ".25" EN_DECIMAL_75 = ".75" -# Combined Hindi and English decimal patterns -POINT_FIVE = pynini.union(HI_POINT_FIVE, EN_POINT_FIVE).optimize() -ONE_POINT_FIVE = pynini.union(HI_ONE_POINT_FIVE, EN_ONE_POINT_FIVE).optimize() -TWO_POINT_FIVE = pynini.union(HI_TWO_POINT_FIVE, EN_TWO_POINT_FIVE).optimize() -DECIMAL_25 = pynini.union(HI_DECIMAL_25, EN_DECIMAL_25).optimize() -DECIMAL_75 = pynini.union(HI_DECIMAL_75, EN_DECIMAL_75).optimize() +# Combined Tamil and English decimal patterns +POINT_FIVE = pynini.union(TA_POINT_FIVE, EN_POINT_FIVE).optimize() +ONE_POINT_FIVE = pynini.union(TA_ONE_POINT_FIVE, EN_ONE_POINT_FIVE).optimize() +TWO_POINT_FIVE = pynini.union(TA_TWO_POINT_FIVE, EN_TWO_POINT_FIVE).optimize() +DECIMAL_25 = pynini.union(TA_DECIMAL_25, EN_DECIMAL_25).optimize() +DECIMAL_75 = pynini.union(TA_DECIMAL_75, EN_DECIMAL_75).optimize() # Symbol constants -HI_BY = "बाई" +TA_BY = "வகுத்தல்" LOWERCASE_X = "x" UPPERCASE_X = "X" ASTERISK = "*" @@ -70,7 +70,7 @@ SLASH = "/" COMMA = "," PERIOD = "." -HI_PERIOD = "।" +TA_PERIOD = "।" NEMO_LOWER = pynini.union(*string.ascii_lowercase).optimize() NEMO_UPPER = pynini.union(*string.ascii_uppercase).optimize() @@ -100,7 +100,7 @@ MIN_POS_WEIGHT = 0.0001 INPUT_CASED = "cased" INPUT_LOWER_CASED = "lower_cased" -MINUS = pynini.union(" ऋणात्मक ", " ऋणात्मक ").optimize() +MINUS = pynini.union(" எதிர்மறை ", " எதிர்மறை ").optimize() def capitalized_input_graph( diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index e7cf19655..2c6e83596 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -11,36 +11,452 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import pynini +from pynini.lib import pynutil +from nemo_text_processing.text_normalization.ta.graph_utils import ( + NEMO_ALL_DIGIT, + NEMO_ALL_ZERO, + GraphFst, + insert_space, +) +from nemo_text_processing.text_normalization.ta.utils import get_abs_path -import pynini -from pynini.lib import pynutil - -from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst -from nemo_text_processing.text_normalization.ta.utils import get_abs_path - - class CardinalFst(GraphFst): - """ - Finite state transducer for classifying cardinals, e.g. - 5 -> cardinal { integer: "ஐந்து" } - Args: - deterministic: if True will provide a single transduction option, - for False multiple transduction are generated (used for audio-based normalization) - """ - - def __init__(self, deterministic: bool = True): - super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - - # Load the three data files as transducers (number -> word) - digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) - zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) - teens_and_ties = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - - graph = digit | zero | teens_and_ties - graph = graph.optimize() - - final_graph = pynutil.insert('integer: "') + graph + pynutil.insert('"') - - # add_tokens() turns it into: cardinal { integer: "" } - final_graph = self.add_tokens(final_graph) - self.fst = final_graph.optimize() \ No newline at end of file + """ + Finite state transducer for classifying cardinals, e.g. + -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + def __init__(self, deterministic: bool = True, lm: bool = False): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) + teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) + teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) + teens_ties = pynini.union(teens_ties_hi, teens_ties_en) + teens_and_ties = pynutil.add_weight(teens_ties, -0.1) + self.digit = digit + self.zero = zero + self.hundred_ta = hundred_ta + self.teens_and_ties = teens_and_ties + # single_digit early — covers ASCII + Tamil digits + zero + single_digit = digit | zero + # Single digit graph for digit-by-digit reading + single_digit_graph = digit | zero + self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) + zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + def create_graph_suffix(digit_graph, suffix, zeros_counts): + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + return digit_graph + (z ** zeros_counts) + suffix + def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): + ins = pynutil.insert(" ") + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + ins + sub_graph + return digit_graph + suffix + (z ** zeros_counts) + ins + sub_graph + + # HUNDREDS GRAPH + # Use hundred_ta.tsv for fused exact hundreds (நூற்று, இருநூற்று, ... + # எட்டுநூற்று, எழுநூற்று, நானூற்று etc.) + # For 101-199: நூற்று + space + remainder + # For 201-999: fused prefix (no space) + space + remainder + # Fused hundred prefix for composites (201-999 non-exact) + fused_hundred_prefix = pynini.union( + pynini.cross("2", "இருநூற்று"), + pynini.cross("3", "முந்நூற்று"), + pynini.cross("4", "நானூற்று"), + pynini.cross("5", "ஐந்நூற்று"), + pynini.cross("6", "அறுநூற்று"), + pynini.cross("7", "எழுநூற்று"), + pynini.cross("8", "எட்டுநூற்று"), + pynini.cross("9", "ஒன்பதுநூற்று"), + pynini.cross("௨", "இருநூற்று"), + pynini.cross("௩", "முந்நூற்று"), + pynini.cross("௪", "நானூற்று"), + pynini.cross("௫", "ஐந்நூற்று"), + pynini.cross("௬", "அறுநூற்று"), + pynini.cross("௭", "எழுநூற்று"), + pynini.cross("௮", "எட்டுநூற்று"), + pynini.cross("௯", "ஒன்பதுநூற்று"), + ).optimize() + # Start with fused exact forms from hundred_ta.tsv + exact_hundred = pynutil.add_weight(pynini.union( + pynini.cross("100", "நூறு"), + pynini.cross("௧௦௦", "நூறு"), + ).optimize(), -1.0) + graph_hundreds = hundred_ta + # 101-109 (ASCII and Tamil digits) + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + zero_delete + + pynutil.insert(" ") + + single_digit + ) + # 110-119 + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + pynutil.insert(" ") + + teens_ties + ) + # 201-209, 301-309 ... 901-909 + graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit + # 210-219 ... 910-919 + graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties + # 220-299 ... 920-999 (two-digit tie/tens tail already in teens_ties) + # teens_ties handles 20,21,...99 so this covers the remaining composites + graph_hundreds = graph_hundreds.optimize() + self.graph_hundreds = graph_hundreds + # THOUSANDS GRAPH + # 1000 → ஆயிரம் (exact, no leading ஒன்று) + # 1001-1099 → ஆயிரத்து + space + remainder + # 1100-1999 → ஆயிரத்து + space + graph_hundreds + # 2000-9000 → fused exact (இரண்டாயிரம், மூன்றாயிரம் ...) + # 2001-9999 → fused prefix (ஐந்தாயிரத்து ...) + space + remainder + one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") + one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") + fused_thousands_exact = pynini.union( + pynini.cross("2", "இரண்டாயிரம்"), + pynini.cross("3", "மூன்றாயிரம்"), + pynini.cross("4", "நான்காயிரம்"), + pynini.cross("5", "ஐந்தாயிரம்"), + pynini.cross("6", "ஆறாயிரம்"), + pynini.cross("7", "ஏழாயிரம்"), + pynini.cross("8", "எட்டாயிரம்"), + pynini.cross("9", "ஒன்பதாயிரம்"), + pynini.cross("௨", "இரண்டாயிரம்"), + pynini.cross("௩", "மூன்றாயிரம்"), + pynini.cross("௪", "நான்காயிரம்"), + pynini.cross("௫", "ஐந்தாயிரம்"), + pynini.cross("௬", "ஆறாயிரம்"), + pynini.cross("௭", "ஏழாயிரம்"), + pynini.cross("௮", "எட்டாயிரம்"), + pynini.cross("௯", "ஒன்பதாயிரம்"), + ).optimize() + fused_thousands_prefix = pynini.union( + pynini.cross("2", "இரண்டாயிரத்து"), + pynini.cross("3", "மூன்றாயிரத்து"), + pynini.cross("4", "நான்காயிரத்து"), + pynini.cross("5", "ஐந்தாயிரத்து"), + pynini.cross("6", "ஆறாயிரத்து"), + pynini.cross("7", "ஏழாயிரத்து"), + pynini.cross("8", "எட்டாயிரத்து"), + pynini.cross("9", "ஒன்பதாயிரத்து"), + pynini.cross("௨", "இரண்டாயிரத்து"), + pynini.cross("௩", "மூன்றாயிரத்து"), + pynini.cross("௪", "நான்காயிரத்து"), + pynini.cross("௫", "ஐந்தாயிரத்து"), + pynini.cross("௬", "ஆறாயிரத்து"), + pynini.cross("௭", "ஏழாயிரத்து"), + pynini.cross("௮", "எட்டாயிரத்து"), + pynini.cross("௯", "ஒன்பதாயிரத்து"), + ).optimize() + # 1000 exact + graph_thousands = one_k_exact + (zero_delete ** 3) + # 1001-1009 + graph_thousands |= one_k_tail + (zero_delete ** 2) + pynutil.insert(" ") + single_digit + # 1010-1099 + graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties + # 1100-1999 + graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds + # 2000-9000 exact + graph_thousands |= fused_thousands_exact + (zero_delete ** 3) + # 2001-9009 + graph_thousands |= fused_thousands_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit + # 2010-9099 + graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties + # 2100-9999 + graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds + graph_thousands = graph_thousands.optimize() + self.graph_thousands = graph_thousands + # TEN-THOUSANDS GRAPH + # e.g. 55000 → ஐம்பத்தைந்தாயிரம், 55199 → ஐம்பத்தைந்தாயிரத்து ... + # teens_and_ties already covers 10-99; we fuse them with ஆயிரம்/ஆயிரத்து + suffix_ten_k_exact = pynutil.insert("ஆயிரம்") + suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") + # exact ten-thousands (X0000 where X is a two-digit teens/ties) + graph_ten_thousands = create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) + # +single digit tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) + # +teens tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) + # +hundreds tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) + graph_ten_thousands = graph_ten_thousands.optimize() + self.graph_ten_thousands = graph_ten_thousands + + # LAKHS — இலட்சம் / இலட்சத்து + suffix_lakhs = pynutil.insert(" இலட்சம்") + suffix_lakhs_tail = pynutil.insert(" இலட்சத்து") + digit_one_as_oru = pynini.union( + pynini.cross("1", "ஒன்று"), + pynini.cross("௧", "ஒன்று"), + pynini.cross("2", "இரண்டு"), + pynini.cross("3", "மூன்று"), + pynini.cross("4", "நான்கு"), + pynini.cross("5", "ஐந்து"), + pynini.cross("6", "ஆறு"), + pynini.cross("7", "ஏழு"), + pynini.cross("8", "எட்டு"), + pynini.cross("9", "ஒன்பது"), + pynini.cross("௨", "இரண்டு"), + pynini.cross("௩", "மூன்று"), + pynini.cross("௪", "நான்கு"), + pynini.cross("௫", "ஐந்து"), + pynini.cross("௬", "ஆறு"), + pynini.cross("௭", "ஏழு"), + pynini.cross("௮", "எட்டு"), + pynini.cross("௯", "ஒன்பது"), + ).optimize() + graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_lakhs = graph_lakhs.optimize() + self.graph_lakhs = graph_lakhs + graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_ten_lakhs.optimize() + self.graph_ten_lakhs = graph_ten_lakhs + + # CRORES — கோடி / கோடியே + suffix_crores = pynutil.insert(" கோடி") + suffix_crores_tail = pynutil.insert(" கோடியே") + graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores = graph_crores.optimize() + graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_crores.optimize() + + # ARABS + suffix_arabs = pynutil.insert(" அரபு") + graph_arabs = create_graph_suffix(digit_one_as_oru, suffix_arabs, 9) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 8, single_digit) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 7, teens_ties) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 6, graph_hundreds) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 5, graph_thousands) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 4, graph_ten_thousands) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 3, graph_lakhs) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 2, graph_ten_lakhs) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 1, graph_crores) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 0, graph_ten_crores) + graph_arabs.optimize() + graph_ten_arabs = create_graph_suffix(teens_and_ties, suffix_arabs, 9) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 8, single_digit) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 7, teens_ties) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 6, graph_hundreds) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 5, graph_thousands) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 4, graph_ten_thousands) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 3, graph_lakhs) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 2, graph_ten_lakhs) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 1, graph_crores) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 0, graph_ten_crores) + graph_ten_arabs.optimize() + + # KHARABS + suffix_kharabs = pynutil.insert(" கரபு") + graph_kharabs = create_graph_suffix(digit_one_as_oru, suffix_kharabs, 11) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 10, single_digit) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 9, teens_ties) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 8, graph_hundreds) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 7, graph_thousands) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 6, graph_ten_thousands) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 5, graph_lakhs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 4, graph_ten_lakhs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 3, graph_crores) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 2, graph_ten_crores) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 1, graph_arabs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 0, graph_ten_arabs) + graph_kharabs.optimize() + graph_ten_kharabs = create_graph_suffix(teens_and_ties, suffix_kharabs, 11) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 10, single_digit) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 9, teens_ties) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 8, graph_hundreds) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 7, graph_thousands) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 6, graph_ten_thousands) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 5, graph_lakhs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 4, graph_ten_lakhs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 3, graph_crores) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 2, graph_ten_crores) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 1, graph_arabs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 0, graph_ten_arabs) + graph_ten_kharabs.optimize() + + # NILS + suffix_nils = pynutil.insert(" நீல்") + graph_nils = create_graph_suffix(digit_one_as_oru, suffix_nils, 13) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 12, single_digit) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 11, teens_ties) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 10, graph_hundreds) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 9, graph_thousands) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 8, graph_ten_thousands) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 7, graph_lakhs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 6, graph_ten_lakhs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 5, graph_crores) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 4, graph_ten_crores) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 3, graph_arabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 2, graph_ten_arabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 1, graph_kharabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 0, graph_ten_kharabs) + graph_nils.optimize() + graph_ten_nils = create_graph_suffix(teens_and_ties, suffix_nils, 13) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 12, single_digit) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 11, teens_ties) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 10, graph_hundreds) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 9, graph_thousands) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 8, graph_ten_thousands) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 7, graph_lakhs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 6, graph_ten_lakhs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 5, graph_crores) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 4, graph_ten_crores) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 3, graph_arabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 2, graph_ten_arabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 1, graph_kharabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 0, graph_ten_kharabs) + graph_ten_nils.optimize() + + # PADMAS + suffix_padmas = pynutil.insert(" பத்மம்") + graph_padmas = create_graph_suffix(digit_one_as_oru, suffix_padmas, 15) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 14, single_digit) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 13, teens_ties) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 12, graph_hundreds) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 11, graph_thousands) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 10, graph_ten_thousands) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 9, graph_lakhs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 8, graph_ten_lakhs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 7, graph_crores) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 6, graph_ten_crores) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 5, graph_arabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 4, graph_ten_arabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 3, graph_kharabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 2, graph_ten_kharabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 1, graph_nils) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 0, graph_ten_nils) + graph_padmas.optimize() + graph_ten_padmas = create_graph_suffix(teens_and_ties, suffix_padmas, 15) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 14, single_digit) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 13, teens_ties) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 12, graph_hundreds) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 11, graph_thousands) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 10, graph_ten_thousands) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 9, graph_lakhs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 8, graph_ten_lakhs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 7, graph_crores) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 6, graph_ten_crores) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 5, graph_arabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 4, graph_ten_arabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 3, graph_kharabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 2, graph_ten_kharabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 1, graph_nils) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 0, graph_ten_nils) + graph_ten_padmas.optimize() + + # SHANKHS + suffix_shankhs = pynutil.insert(" சங்கம்") + graph_shankhs = create_graph_suffix(digit_one_as_oru, suffix_shankhs, 17) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 16, single_digit) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 15, teens_ties) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 14, graph_hundreds) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 13, graph_thousands) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 12, graph_ten_thousands) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 11, graph_lakhs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 10, graph_ten_lakhs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 9, graph_crores) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 8, graph_ten_crores) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 7, graph_arabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 6, graph_ten_arabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 5, graph_kharabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 4, graph_ten_kharabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 3, graph_nils) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 2, graph_ten_nils) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 1, graph_padmas) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 0, graph_ten_padmas) + graph_shankhs.optimize() + graph_ten_shankhs = create_graph_suffix(teens_and_ties, suffix_shankhs, 17) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 16, single_digit) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 15, teens_ties) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 14, graph_hundreds) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 13, graph_thousands) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 12, graph_ten_thousands) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 11, graph_lakhs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 10, graph_ten_lakhs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 9, graph_crores) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 8, graph_ten_crores) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 7, graph_arabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 6, graph_ten_arabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 5, graph_kharabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 4, graph_ten_kharabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 3, graph_nils) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 2, graph_ten_nils) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 1, graph_padmas) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 0, graph_ten_padmas) + graph_ten_shankhs.optimize() + + # LEADING ZERO and FINAL GRAPH + graph_leading_zero = zero + insert_space + single_digit + graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) + graph_without_leading_zeros = ( + digit + | zero + | teens_and_ties + | exact_hundred + | graph_hundreds + | graph_thousands + | graph_ten_thousands + | graph_lakhs + | graph_ten_lakhs + | graph_crores + | graph_ten_crores + | graph_arabs + | graph_ten_arabs + | graph_kharabs + | graph_ten_kharabs + | graph_nils + | graph_ten_nils + | graph_padmas + | graph_ten_padmas + | graph_shankhs + | graph_ten_shankhs + ) + self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() + cardinal_with_leading_zeros = pynini.compose( + NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph + ) + cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) + final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros + optional_minus_graph = pynini.closure( + pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1 + ) + self.final_graph = final_graph.optimize() + final_graph = ( + optional_minus_graph + + pynutil.insert("integer: \"") + + self.final_graph + + pynutil.insert("\"") + ) + final_graph = self.add_tokens(final_graph) + self.fst = final_graph \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/punctuation.py b/nemo_text_processing/text_normalization/ta/taggers/punctuation.py new file mode 100644 index 000000000..32bc395e9 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/taggers/punctuation.py @@ -0,0 +1,48 @@ +import sys +from unicodedata import category + +import pynini +from pynini.examples import plurals +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_NOT_SPACE, NEMO_SIGMA, GraphFst + + +class PunctuationFst(GraphFst): + """ + Finite state transducer for classifying punctuation + e.g. a, -> tokens { name: "a" } tokens { name: "," } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transductions are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="punctuation", kind="classify", deterministic=deterministic) + s = "!#%&\'()*+,-./:;<=>?@^_`{|}~\"" + + punct_symbols_to_exclude = ["[", "]"] + punct_unicode = [ + chr(i) + for i in range(sys.maxunicode) + if category(chr(i)).startswith("P") and chr(i) not in punct_symbols_to_exclude + ] + + self.punct_marks = [p for p in punct_unicode + list(s)] + + punct = pynini.union(*self.punct_marks) + punct = pynini.closure(punct, 1) + + emphasis = ( + pynini.accep("<") + + pynini.union( + (pynini.closure(NEMO_NOT_SPACE - pynini.union("<", ">"), 1) + pynini.closure(pynini.accep("/"), 0, 1)), + (pynini.accep("/") + pynini.closure(NEMO_NOT_SPACE - pynini.union("<", ">"), 1)), + ) + + pynini.accep(">") + ) + punct = plurals._priority_union(emphasis, punct, NEMO_SIGMA) + + self.graph = punct + self.fst = (pynutil.insert("name: \"") + self.graph + pynutil.insert("\"")).optimize() diff --git a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py new file mode 100644 index 000000000..86fdc3421 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py @@ -0,0 +1,168 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import ( + NEMO_SPACE, + NEMO_WHITE_SPACE, + GraphFst, + delete_extra_space, + delete_space, + generator_main, +) +from nemo_text_processing.text_normalization.ta.taggers.cardinal import CardinalFst +# from nemo_text_processing.text_normalization.hi.taggers.date import DateFst +# from nemo_text_processing.text_normalization.hi.taggers.decimal import DecimalFst +# from nemo_text_processing.text_normalization.hi.taggers.electronic import ElectronicFst +# from nemo_text_processing.text_normalization.hi.taggers.fraction import FractionFst +# from nemo_text_processing.text_normalization.hi.taggers.measure import MeasureFst +# from nemo_text_processing.text_normalization.hi.taggers.money import MoneyFst +# from nemo_text_processing.text_normalization.hi.taggers.ordinal import OrdinalFst +from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst +# from nemo_text_processing.text_normalization.hi.taggers.telephone import TelephoneFst +# from nemo_text_processing.text_normalization.hi.taggers.time import TimeFst +# from nemo_text_processing.text_normalization.hi.taggers.whitelist import WhiteListFst +from nemo_text_processing.text_normalization.ta.taggers.word import WordFst + + +class ClassifyFst(GraphFst): + """ + Final class that composes all other classification grammars. This class can process an entire sentence including punctuation. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + input_case: accepting either "lower_cased" or "cased" input. + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. + overwrite_cache: set to True to overwrite .far files + whitelist: path to a file with whitelist replacements + """ + + def __init__( + self, + input_case: str, + deterministic: bool = True, + cache_dir: str = None, + overwrite_cache: bool = False, + whitelist: str = None, + ): + super().__init__(name="tokenize_and_classify", kind="classify", deterministic=deterministic) + + far_file = None + if cache_dir is not None and cache_dir != "None": + os.makedirs(cache_dir, exist_ok=True) + whitelist_file = os.path.basename(whitelist) if whitelist else "" + far_file = os.path.join( + cache_dir, + f"hi_tn_{deterministic}_deterministic_{input_case}_{whitelist_file}_tokenize.far", + ) + if not overwrite_cache and far_file and os.path.exists(far_file): + self.fst = pynini.Far(far_file, mode="r")["tokenize_and_classify"] + logging.info(f"ClassifyFst.fst was restored from {far_file}.") + else: + logging.info(f"Creating ClassifyFst grammars.") + + cardinal = CardinalFst(deterministic=deterministic) + cardinal_graph = cardinal.fst + + # decimal = DecimalFst(cardinal=cardinal, deterministic=deterministic) + # decimal_graph = decimal.fst + + # fraction = FractionFst(cardinal=cardinal, deterministic=deterministic) + # fraction_graph = fraction.fst + + # date = DateFst(cardinal=cardinal) + # date_graph = date.fst + + # timefst = TimeFst(cardinal=cardinal) + # time_graph = timefst.fst + + # ordinal = OrdinalFst(cardinal=cardinal, deterministic=deterministic) + # ordinal_graph = ordinal.fst + + # measure = MeasureFst(cardinal=cardinal, decimal=decimal, ordinal=ordinal, input_case=input_case) + # measure_graph = measure.fst + + # money = MoneyFst(cardinal=cardinal) + # money_graph = money.fst + + # whitelist_graph = WhiteListFst( + # input_case=input_case, deterministic=deterministic, input_file=whitelist + # ).fst + + punctuation = PunctuationFst(deterministic=deterministic) + punct_graph = punctuation.fst + + # telephone = TelephoneFst() + # telephone_graph = telephone.fst + + # electronic = ElectronicFst(deterministic=deterministic) + # electronic_graph = electronic.fst + + classify = ( + # pynutil.add_weight(whitelist_graph, 1.01)| + pynutil.add_weight(cardinal_graph, 1.1) + # | pynutil.add_weight(decimal_graph, 1.1) + # | pynutil.add_weight(fraction_graph, 1.1) + # | pynutil.add_weight(date_graph, 1.1) + # | pynutil.add_weight(time_graph, 1.1) + # | pynutil.add_weight(measure_graph, 1.1) + # | pynutil.add_weight(money_graph, 1.1) + # | pynutil.add_weight(telephone_graph, 1.1) + # | pynutil.add_weight(ordinal_graph, 1.1) + # | pynutil.add_weight(electronic_graph, 1.1) + ) + + word_graph = WordFst(punctuation=punctuation, deterministic=deterministic).fst + + punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=2.1) + pynutil.insert(" }") + punct = pynini.closure( + pynini.union( + pynini.compose(pynini.closure(NEMO_WHITE_SPACE, 1), delete_extra_space), + (pynutil.insert(NEMO_SPACE) + punct), + ), + 1, + ) + + classify = pynini.union(classify, pynutil.add_weight(word_graph, 100)) + token = pynutil.insert("tokens { ") + classify + pynutil.insert(" }") + token_plus_punct = ( + pynini.closure(punct + pynutil.insert(NEMO_SPACE)) + + token + + pynini.closure(pynutil.insert(NEMO_SPACE) + punct) + ) + + graph = token_plus_punct + pynini.closure( + pynini.union( + pynini.compose(pynini.closure(NEMO_WHITE_SPACE, 1), delete_extra_space), + (pynutil.insert(NEMO_SPACE) + punct + pynutil.insert(NEMO_SPACE)), + ) + + token_plus_punct + ) + + graph = delete_space + graph + delete_space + graph = pynini.union(graph, punct) + + self.fst = graph.optimize() + + if far_file: + generator_main(far_file, {"tokenize_and_classify": self.fst}) + logging.info(f"ClassifyFst grammars are saved to {far_file}.") diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py new file mode 100644 index 000000000..6398a78fd --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -0,0 +1,61 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import ( + MIN_NEG_WEIGHT, + NEMO_NOT_SPACE, + GraphFst, + convert_space, +) +from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst + + +class WordFst(GraphFst): + """ + Finite state transducer for classifying Tamil words. + e.g. சோனா -> tokens { name: " சோனா" } + + Args: + punctuation: PunctuationFst + deterministic: if True will provide a single transduction option, + for False multiple transductions are generated (used for audio-based normalization) + """ + + def __init__(self, punctuation: PunctuationFst, deterministic: bool = True): + super().__init__(name="word", kind="classify", deterministic=deterministic) + + # Define Tamil characters and symbols using pynini.union + TAMIL_CHAR = pynini.union( + *[chr(i) for i in range(0x0B80, 0x0B83 + 1)], # Tamil vowels and consonants + *[chr(i) for i in range(0x0B85, 0x0BB9 + 1)], # More Tamil characters + *[chr(i) for i in range(0x0BBE, 0x0BCD + 1)], # Tamil diacritics + ).optimize() + + # Include punctuation in the graph + punct = punctuation.graph + default_graph = pynini.closure(pynini.difference(NEMO_NOT_SPACE, punct.project("input")), 1) + symbols_to_exclude = (pynini.union("$", "€", "₩", "£", "¥", "#", "%") | punct).optimize() + + # Use TAMIL_CHAR in the graph + graph = pynini.closure(pynini.difference(TAMIL_CHAR, symbols_to_exclude), 1) + graph = pynutil.add_weight(graph, MIN_NEG_WEIGHT) | default_graph + + # Ensure no spaces around punctuation + graph = pynini.closure(graph + pynini.closure(punct + graph, 0, 1)) + + self.graph = convert_space(graph) + self.fst = (pynutil.insert("name: \"") + self.graph + pynutil.insert("\"")).optimize() diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py index 24e300c1b..59676b890 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py @@ -12,37 +12,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pynini -from pynini.lib import pynutil - -from nemo_text_processing.text_normalization.ta.graph_utils import ( - NEMO_NOT_QUOTE, - GraphFst, - delete_space, -) - - +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.hi.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space + + class CardinalFst(GraphFst): - """ + """ Finite state transducer for verbalizing cardinal, e.g. - cardinal { integer: "5" } -> ஐந்து + cardinal { negative: "true" integer: "23" } -> minus twenty three + Args: deterministic: if True will provide a single transduction option, - for False multiple options (used for audio-based normalization) - """ - - def __init__(self, deterministic: bool = True): - super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic) - - graph = ( - pynutil.delete("integer:") - + delete_space - + pynutil.delete('"') - + pynini.closure(NEMO_NOT_QUOTE, 1) - + pynutil.delete('"') - ) - - # delete_tokens() removes the surrounding cardinal { ... } - delete_tokens = self.delete_tokens(graph) - self.fst = delete_tokens.optimize() - \ No newline at end of file + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="cardinal", kind="verbalize", deterministic=deterministic) + + self.optional_sign = pynini.cross("negative: \"true\"", "minus ") + if not deterministic: + self.optional_sign |= pynini.cross("negative: \"true\"", "negative ") + self.optional_sign |= pynini.cross("negative: \"true\"", "dash ") + + self.optional_sign = pynini.closure(self.optional_sign + delete_space, 0, 1) + + integer = pynini.closure(NEMO_NOT_QUOTE) + + self.integer = delete_space + pynutil.delete("\"") + integer + pynutil.delete("\"") + integer = pynutil.delete("integer:") + self.integer + + self.numbers = self.optional_sign + integer + delete_tokens = self.delete_tokens(self.numbers) + + self.fst = delete_tokens.optimize() diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py new file mode 100644 index 000000000..9afad60e3 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py @@ -0,0 +1,96 @@ +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import ( + MIN_NEG_WEIGHT, + NEMO_CHAR, + NEMO_SIGMA, + generator_main, +) +from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst +from nemo_text_processing.utils.logging import logger + + +class PostProcessingFst: + """ + Finite state transducer that post-processing an entire sentence after verbalization is complete, e.g. + removes extra spaces around punctuation marks " ( one hundred and twenty three ) " -> "(one hundred and twenty three)" + + Args: + cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. + overwrite_cache: set to True to overwrite .far files + """ + + def __init__(self, cache_dir: str = None, overwrite_cache: bool = False): + + far_file = None + if cache_dir is not None and cache_dir != "None": + os.makedirs(cache_dir, exist_ok=True) + far_file = os.path.join(cache_dir, "ta_tn_post_processing.far") + if not overwrite_cache and far_file and os.path.exists(far_file): + self.fst = pynini.Far(far_file, mode="r")["post_process_graph"] + logger.info(f'Post processing graph was restored from {far_file}.') + else: + self.fst = self.get_punct_postprocess_graph() + + if far_file: + generator_main(far_file, {"post_process_graph": self.fst}) + + def get_punct_postprocess_graph(self): + """ + Returns graph to post process punctuation marks. + + By default, spaces are removed before punctuation marks like comma, period, etc. + """ + punct_marks_all = PunctuationFst().punct_marks + + # Punctuation marks that should NOT have space before them + # (most punctuation except quotes, dashes, and opening brackets) + quotes = ["'", "\"", "«"] + dashes = ["-", "—"] + brackets = ["<", "{", "(", r"\["] + allow_space_before_punct = quotes + dashes + brackets + + no_space_before_punct = [m for m in punct_marks_all if m not in allow_space_before_punct] + # Add Hindi-specific punctuation + no_space_before_punct.extend(["।", ",", ".", ";", ":", "!", "?"]) + # Remove duplicates + no_space_before_punct = list(set(no_space_before_punct)) + no_space_before_punct = pynini.union(*no_space_before_punct) + + delete_space = pynutil.delete(" ") + + # Delete space before no_space_before_punct marks + non_punct = pynini.difference(NEMO_CHAR, no_space_before_punct).optimize() + graph = ( + pynini.closure(non_punct) + + pynini.closure( + no_space_before_punct | pynutil.add_weight(delete_space + no_space_before_punct, MIN_NEG_WEIGHT) + ) + + pynini.closure(non_punct) + ) + graph = pynini.closure(graph).optimize() + + # Remove space after opening brackets + no_space_after_punct = pynini.union(*brackets) + no_space_after_punct = pynini.cdrewrite(delete_space, no_space_after_punct, NEMO_SIGMA, NEMO_SIGMA).optimize() + graph = pynini.compose(graph, no_space_after_punct).optimize() + + return graph diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py new file mode 100644 index 000000000..2c27b0e56 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py @@ -0,0 +1,53 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst +from nemo_text_processing.text_normalization.ta.verbalizers.cardinal import CardinalFst +#from nemo_text_processing.text_normalization.ta.verbalizers.date import DateFst +#from nemo_text_processing.text_normalization.hi.verbalizers.decimal import DecimalFst +#from nemo_text_processing.text_normalization.hi.verbalizers.electronic import ElectronicFst +#from nemo_text_processing.text_normalization.hi.verbalizers.fraction import FractionFst +#from nemo_text_processing.text_normalization.hi.verbalizers.measure import MeasureFst +#from nemo_text_processing.text_normalization.hi.verbalizers.money import MoneyFst +#from nemo_text_processing.text_normalization.hi.verbalizers.ordinal import OrdinalFst +#from nemo_text_processing.text_normalization.hi.verbalizers.telephone import TelephoneFst +#from nemo_text_processing.text_normalization.hi.verbalizers.time import TimeFst +#from nemo_text_processing.text_normalization.ta.verbalizers.whitelist import WhiteListFst + + +class VerbalizeFst(GraphFst): + """ + Composes other verbalizer grammars. + For deployment, this grammar will be compiled and exported to OpenFst Finite State Archive (FAR) File. + More details to deployment at NeMo/tools/text_processing_deployment. + + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="verbalize", kind="verbalize", deterministic=deterministic) + + cardinal = CardinalFst(deterministic=deterministic) + cardinal_graph = cardinal.fst + + + + graph = ( + cardinal_graph + + ) + + self.fst = graph diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py new file mode 100644 index 000000000..f9c300aae --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py @@ -0,0 +1,76 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os + +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import ( + GraphFst, + delete_extra_space, + delete_space, + generator_main, +) +from nemo_text_processing.text_normalization.ta.verbalizers.verbalize import VerbalizeFst +from nemo_text_processing.text_normalization.ta.verbalizers.word import WordFst + + +class VerbalizeFinalFst(GraphFst): + """ + Finite state transducer that verbalizes an entire sentence, e.g. + tokens { name: "its" } tokens { time { hours: "twelve" minutes: "thirty" } } tokens { name: "now" } tokens { name: "." } -> its twelve thirty now . + + Args: + deterministic: if True will provide a single transduction option, + for False multiple options (used for audio-based normalization) + cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. + overwrite_cache: set to True to overwrite .far files + """ + + def __init__(self, deterministic: bool = True, cache_dir: str = None, overwrite_cache: bool = False): + super().__init__(name="verbalize_final", kind="verbalize", deterministic=deterministic) + + far_file = None + if cache_dir is not None and cache_dir != "None": + os.makedirs(cache_dir, exist_ok=True) + far_file = os.path.join(cache_dir, f"en_tn_{deterministic}_deterministic_verbalizer.far") + if not overwrite_cache and far_file and os.path.exists(far_file): + self.fst = pynini.Far(far_file, mode="r")["verbalize"] + logging.info(f'VerbalizeFinalFst graph was restored from {far_file}.') + else: + verbalize = VerbalizeFst(deterministic=deterministic).fst + word = WordFst(deterministic=deterministic).fst + types = verbalize | word + + if deterministic: + graph = ( + pynutil.delete("tokens") + + delete_space + + pynutil.delete("{") + + delete_space + + types + + delete_space + + pynutil.delete("}") + ) + else: + graph = delete_space + types + delete_space + + graph = delete_space + pynini.closure(graph + delete_extra_space) + graph + delete_space + + self.fst = graph.optimize() + if far_file: + generator_main(far_file, {"verbalize": self.fst}) + logging.info(f"VerbalizeFinalFst grammars are saved to {far_file}.") diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py new file mode 100644 index 000000000..9734d3d25 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -0,0 +1,43 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pynini +from pynini.lib import pynutil + +from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + + +class WordFst(GraphFst): + """ + Finite state transducer for verbalizing Tamil words. + e.g. tokens { name: " சோனா" } -> சோனா + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True): + super().__init__(name="word", kind="verbalize", deterministic=deterministic) + chars = pynini.closure(NEMO_CHAR - " ", 1) + punct = pynini.union("!", "?", ".", ",", "-", ":", ";", "।") # Add other punctuation marks as needed + char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") + + # Ensure no spaces around punctuation + graph = char + pynini.closure(delete_space + punct, 0, 1) + + # Explicitly remove spaces before punctuation + remove_space_before_punct = pynini.cdrewrite(pynini.cross(" ", ""), "", punct, NEMO_SIGMA) + graph = graph @ remove_space_before_punct + + self.fst = graph.optimize() diff --git a/run_cardinal_tests.py b/run_cardinal_tests.py new file mode 100644 index 000000000..d7224ff74 --- /dev/null +++ b/run_cardinal_tests.py @@ -0,0 +1,48 @@ +# run_cardinal_tests.py -- simple checker for the Cardinal exercise. +# Usage (from the repo root, inside your conda env): +# python run_cardinal_tests.py +# Example: +# python run_cardinal_tests.py LANGCODE DIRECTION test_cases_cardinal.txt +import sys +import importlib +import pynini + + +def apply_fst(fst, text): + lattice = text @ fst + if lattice.num_states() == 0: + return None # input was rejected by the grammar + out = pynini.shortestpath(lattice) + return out.string() if out.num_states() else None + + +def main(): + lang, direction, path = sys.argv[1], sys.argv[2], sys.argv[3] + base = "text_normalization" if direction == "tn" else "inverse_text_normalization" + tagger = importlib.import_module( + f"nemo_text_processing.{base}.{lang}.taggers.cardinal").CardinalFst().fst + verbalizer = importlib.import_module( + f"nemo_text_processing.{base}.{lang}.verbalizers.cardinal").CardinalFst().fst + + passed = failed = 0 + with open(path, encoding="utf-8") as f: + for line in f: + line = line.rstrip("\n") + if not line.strip() or "~" not in line: + continue + inp, expected = [s.strip() for s in line.split("~", 1)] + tagged = apply_fst(tagger, inp) + result = apply_fst(verbalizer, tagged) if tagged is not None else None + if result == expected: + passed += 1 + else: + failed += 1 + print(f"FAIL: {inp!r} -> got {result!r}, expected {expected!r}") + + print(f"\n{passed} passed, {failed} failed.") + sys.exit(1 if failed else 0) + + +if __name__ == "__main__": + main() + \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/__init__.py b/tests/nemo_text_processing/ta/__init__.py new file mode 100644 index 000000000..d9155f923 --- /dev/null +++ b/tests/nemo_text_processing/ta/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt new file mode 100644 index 000000000..5f2f741a5 --- /dev/null +++ b/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt @@ -0,0 +1,54 @@ +நான்கு ஃபோர்கள்~௪ ஃபோர்கள் +ஆறு வீரர்கள் அவுட்~௬ வீரர்கள் அவுட் +ஒன்பிளஸ் எட்டு ப்ரோ~ஒன்பிளஸ் ௮ ப்ரோ +ஐந்து சார்ஜர்கள்~௫ சார்ஜர்கள் +நான்கு ஓவரில் பதினேழு ரன்கள்~௪ ஓவரில் ௧௭ ரன்கள் +ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள்~௫ சாக்லெட்டுகள் ௯ டாஃபிகள் +பத்தாயிரத்து தொண்ணூற்று ஒன்பது~௧௦௦௯௯ +ஒரு இலட்சத்து ஒன்று~௧௦௦௦௦௧ +நூறு~௧௦௦ +முன்னூற்று ஒன்பது~௩௦௯ +எழுநூற்று தொண்ணூற்று எட்டு~௭௯௮ +ஐந்தாயிரம்~௫௦௦௦ +எட்டாயிரத்து நான்கு~௮௦௦௪ +ஒன்பதாயிரத்து பதினாறு~௯௦௧௬ +ஆயிரத்து தொள்ளாயிரத்து பன்னிரண்டு~௧௯௧௨ +இரண்டாயிரத்து இருநூற்று இருபத்து இரண்டு~௨௨௨௨ +பதினான்காயிரம்~௧௪௦௦௦ +பதினெட்டாயிரத்து ஆறு~௧௮௦௦௬ +இருபத்தாறாயிரத்து இருபத்து ஒன்று~௨௬௦௨௧ +தொண்ணூற்றாறாயிரத்து எண்ணூற்று பதினொன்று~௯௬௮௧௧ +நான்கு இலட்சம்~௪௦௦௦௦௦ +இரண்டு இலட்சத்து இரண்டு~௨௦௦௦௦௨ +ஏழு இலட்சத்து இருபது~௭௦௦௦௨௦ +ஒன்பது இலட்சத்து முன்னூற்று இருபத்து ஒன்று~௯௦௦௩௨௧ +எட்டு இலட்சத்து ஐந்தாயிரத்து முன்னூற்று இருபத்து ஒன்று~௮௦௫௩௨௧ +இருபத்து மூன்று இலட்சம்~௨௩௦௦௦௦௦ +பதினைந்து இலட்சத்து ஒன்று~௧௫௦௦௦௦௧ +இருபத்து ஏழு இலட்சத்து எண்ணூற்று இருபது~௨௭௦௦௮௨௦ +தொண்ணூற்று ஒரு இலட்சத்து முப்பத்தொன்றாயிரத்து எண்ணூற்று இருபத்து ஒன்பது~௯௧௩௧௮௨௯ +மூன்று கோடி~௩௦௦௦௦௦௦௦ +ஒரு கோடியே ஒன்று~௧௦௦௦௦௦௦௧ +ஏழு கோடியே பதின்மூன்று~௭௦௦௦௦௦௧௩ +நான்கு கோடியே தொள்ளாயிரத்து பதினொன்று~௪௦௦௦௦௯௧௧ +ஆறு கோடியே ஐந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௬௦௦௦௫௯௧௧ +ஆறு கோடியே இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௬௦௦௨௫௯௧௧ +மூன்று கோடியே ஒரு இலட்சத்து இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௩௦௧௨௫௯௧௧ +இரண்டு கோடியே பதினேழு இலட்சத்து இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௨௧௭௨௫௯௧௧ +முப்பது கோடி~௩௦௦௦௦௦௦௦௦ +தொண்ணூற்று எட்டு இலட்சத்து எழுபத்தாறாயிரத்து எழுநூற்று எண்பத்து ஒன்பது~௯௮௭௬௭௮௯ +இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௨௩௪௫௫௬௭ +ஒரு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௨௩௪௫௫௬௭ +ஒரு கோடியே இருபத்து ஒன்று இலட்சத்து இருபத்து ஒன்றாயிரத்து இருநூற்று பன்னிரண்டு~௧௨௧௨௧௨௧௨ +ஒரு அரபே பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௧௨௨௩௪௫௫௬௭ +ஒரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௦௨௨௩௪௫௫௬௭ +பதினொரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௧௦௨௨௩௪௫௫௬௭ +ஐம்பத்து ஒரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௫௧௦௨௨௩௪௫௫௬௭ +ஏழே கால் நூறு~௭௨௫ +ஏழரை நூறு~௭௫௦ +ஏழரை ஆயிரம்~௭௫௦௦ +ஏழே கால் ஆயிரம்~௭௨௫௦ +நூற்று ஐம்பது~௧௫௦ +இருநூற்று ஐம்பது~௨௫௦ +பதினாறு நூற்று ஐம்பது~௧௬௫௦ +பதினாறு நூற்று இருபத்தைந்து~௧௬௨௫ \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt new file mode 100644 index 000000000..0ab12369a --- /dev/null +++ b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt @@ -0,0 +1,148 @@ +௪ ஃபோர்கள்~நான்கு ஃபோர்கள் +௬ வீரர்கள் அவுட்~ஆறு வீரர்கள் அவுட் +ஒன்பிளஸ் ௮ ப்ரோ~ஒன்பிளஸ் எட்டு ப்ரோ +௫ சார்ஜர்கள்~ஐந்து சார்ஜர்கள் +௪ ஓவரில் ௧௭ ரன்கள்~நான்கு ஓவரில் பதினேழு ரன்கள் +௫ சாக்லெட்டுகள் ௯ டாஃபிகள்~ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள் +௧௦௦௯௯~பத்துஆயிரத்து தொண்ணூற்று ஒன்பது +௧௦௦௦௦௧~ஒன்று இலட்சத்து ஒன்று +௪ சிக்ஸர்கள் ௧௪ நான்குகள்~நான்கு சிக்ஸர்கள் பதினான்கு நான்குகள் +௬ ரன்கள் எடுத்தார்~ஆறு ரன்கள் எடுத்தார் +௩ கோல்கள் அடித்தார்~மூன்று கோல்கள் அடித்தார் +௫ நான்குகள்~ஐந்து நான்குகள் +௨ சிக்ஸர்கள் ௧௨ ரன்கள்~இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் +௯ புள்ளிகள்~ஒன்பது புள்ளிகள் +௪ உயிரிழப்பு ௧௮ காயம்~நான்கு உயிரிழப்பு பதினெட்டு காயம் +௫ கோல்கள் அடி~ஐந்து கோல்கள் அடி +௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள்~மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் +௫ தோல்வி ௧ டிரா ௧௭ வெற்றி~ஐந்து தோல்வி ஒன்று டிரா பதினேழு வெற்றி +௫௧௦௨௨௩௪௫௫௬௭~ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +பாடம் ௧௦ ஸ்லோகம் ௨~பாடம் பத்து ஸ்லோகம் இரண்டு +௧௦௧~நூற்று ஒன்று +௧௦௨~நூற்று இரண்டு +௧௦௩~நூற்று மூன்று +௧௦௪~நூற்று நான்கு +௧௦௫~நூற்று ஐந்து +௧௦௬~நூற்று ஆறு +௧௦௭~நூற்று ஏழு +௧௦௮~நூற்று எட்டு +௧௦௯~நூற்று ஒன்பது +௧௧௦~நூற்று பத்து +௧௧௧~நூற்று பதினொன்று +௧௧௨~நூற்று பன்னிரண்டு +௧௧௩~நூற்று பதிமூன்று +௧௧௪~நூற்று பதினான்கு +௧௧௫~நூற்று பதினைந்து +௧௧௬~நூற்று பதினாறு +௮௧௭~எட்டுநூற்று பதினேழு +௮௧௮~எட்டுநூற்று பதினெட்டு +௮௧௯~எட்டுநூற்று பத்தொன்பது +௮௨௦~எட்டுநூற்று இருபது +௮௨௧~எட்டுநூற்று இருபத்து ஒன்று +௮௨௨~எட்டுநூற்று இருபத்து இரண்டு +௮௨௩~எட்டுநூற்று இருபத்து மூன்று +௮௨௪~எட்டுநூற்று இருபத்து நான்கு +௮௨௫~எட்டுநூற்று இருபத்து ஐந்து +௮௨௬~எட்டுநூற்று இருபத்து ஆறு +௮௨௭~எட்டுநூற்று இருபத்து ஏழு +௮௨௮~எட்டுநூற்று இருபத்து எட்டு +௮௨௯~எட்டுநூற்று இருபத்து ஒன்பது +௮௩௦~எட்டுநூற்று முப்பது +௮௩௧~எட்டுநூற்று முப்பத்து ஒன்று +௮௩௨~எட்டுநூற்று முப்பத்து இரண்டு +௮௩௩~எட்டுநூற்று முப்பத்து மூன்று +௮௩௪~எட்டுநூற்று முப்பத்து நான்கு +௮௩௫~எட்டுநூற்று முப்பத்து ஐந்து +௮௩௬~எட்டுநூற்று முப்பத்து ஆறு +௭௩௭~எழுநூற்று முப்பத்து ஏழு +௭௩௮~எழுநூற்று முப்பத்து எட்டு +௭௩௯~எழுநூற்று முப்பத்து ஒன்பது +௭௪௦~எழுநூற்று நாற்பது +௭௪௧~எழுநூற்று நாற்பத்து ஒன்று +௭௪௨~எழுநூற்று நாற்பத்து இரண்டு +௭௪௩~எழுநூற்று நாற்பத்து மூன்று +௭௪௪~எழுநூற்று நாற்பத்து நான்கு +௭௪௫~எழுநூற்று நாற்பத்து ஐந்து +௪௪௬~நானூற்று நாற்பத்து ஆறு +௪௪௭~நானூற்று நாற்பத்து ஏழு +௪௪௮~நானூற்று நாற்பத்து எட்டு +௪௪௯~நானூற்று நாற்பத்து ஒன்பது +௪௫௦~நானூற்று ஐம்பது +௪௬௧~நானூற்று அறுபத்து ஒன்று +௧௭௫~நூற்று எழுபத்து ஐந்து +௧௮௧~நூற்று எண்பத்து ஒன்று +௧௯௦~நூற்று தொண்ணூறு +௧௯௧~நூற்று தொண்ணூற்று ஒன்று +௧௯௯~நூற்று தொண்ணூற்று ஒன்பது +௧௦௦௧~ஆயிரத்து ஒன்று +௧௦௯௯~ஆயிரத்து தொண்ணூற்று ஒன்பது +௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐந்நூற்று ஐம்பத்து ஒன்று வாழைப்பழங்கள் +௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்து ஐந்துஆயிரத்து ஐந்நூற்று ஐம்பத்து இரண்டு ஆப்பிள்கள் +௫௩~ஐம்பத்து மூன்று +௫௪~ஐம்பத்து நான்கு +௫௫~ஐம்பத்து ஐந்து +௫௬~ஐம்பத்து ஆறு +௫௭~ஐம்பத்து ஏழு +௫௮~ஐம்பத்து எட்டு +௫௯~ஐம்பத்து ஒன்பது +௬௦~அறுபது +௬௧~அறுபத்து ஒன்று +௬௨~அறுபத்து இரண்டு +௬௩~அறுபத்து மூன்று +௬௪~அறுபத்து நான்கு +௬௫~அறுபத்து ஐந்து +௬௬~அறுபத்து ஆறு +௬௭~அறுபத்து ஏழு +௬௮~அறுபத்து எட்டு +௬௯~அறுபத்து ஒன்பது +௭௦~எழுபது +௭௧~எழுபத்து ஒன்று +௭௨~எழுபத்து இரண்டு +௭௩~எழுபத்து மூன்று +௭௪~எழுபத்து நான்கு +௭௫~எழுபத்து ஐந்து +௭௬~எழுபத்து ஆறு +௭௭~எழுபத்து ஏழு +௭௮~எழுபத்து எட்டு +௭௯~எழுபத்து ஒன்பது +௮௦~எண்பது +௮௧~எண்பத்து ஒன்று +௮௨~எண்பத்து இரண்டு +௮௩~எண்பத்து மூன்று +௮௪~எண்பத்து நான்கு +௮௫~எண்பத்து ஐந்து +௮௬~எண்பத்து ஆறு +௮௭~எண்பத்து ஏழு +௮௮~எண்பத்து எட்டு +௮௯~எண்பத்து ஒன்பது +௯௦~தொண்ணூறு +௯௧~தொண்ணூற்று ஒன்று +௯௨~தொண்ணூற்று இரண்டு +௯௩~தொண்ணூற்று மூன்று +௯௪~தொண்ணூற்று நான்கு +௯௫~தொண்ணூற்று ஐந்து +௯௬~தொண்ணூற்று ஆறு +௯௭~தொண்ணூற்று ஏழு +௯௮~தொண்ணூற்று எட்டு +௯௯~தொண்ணூற்று ஒன்பது +௧௩௨௩~ஆயிரத்து முந்நூற்று இருபத்து மூன்று +௧௩௪௫~ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து +௧௩௪௫௬~பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு +௧௨௩௪௬~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு +௧௨௩௪௫௬~ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு +௮௭௨௯௮௭~எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு +௯௮௭௬௦௯~ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது +௯௮௭௬௭௮௯~தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது +௨௩௪௫௫௬௭~இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௧௨௩௪௫௫௬௭~ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௧௨௧௨௧௨௧௨~ஒன்று கோடியே இருபத்து ஒன்று இலட்சத்து இருபத்து ஒன்றுஆயிரத்து இருநூற்று பன்னிரண்டு +௧௧௨௨௩௪௫௫௬௭~ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௧௦௨௨௩௪௫௫௬௭~ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௧௧௦௨௨௩௪௫௫௬௭~பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௫௧௦௨௨௩௪௫௫௬௭~ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௨ புள்ளிகள் ௧௨ கோல்கள்~இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் +௦௫~சுழியம் ஐந்து +௦௧~சுழியம் ஒன்று +௦௭௩~சுழியம் ஏழு மூன்று +௦௦௦௧~சுழியம் சுழியம் சுழியம் ஒன்று +௦௦௦~சுழியம் சுழியம் சுழியம் diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py new file mode 100644 index 000000000..3be785d55 --- /dev/null +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -0,0 +1,42 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from parameterized import parameterized + +from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer +from nemo_text_processing.text_normalization.normalize import Normalizer + +from ..utils import CACHE_DIR, parse_test_case_file + + +class TestCardinal: + normalizer = Normalizer( + input_case='cased', lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False + ) + #inverse_normalizer = InverseNormalizer(lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False) + + @parameterized.expand(parse_test_case_file('ta/data_text_normalization/test_cases_cardinal.txt')) + @pytest.mark.run_only_on('CPU') + @pytest.mark.unit + def test_norm(self, test_input, expected): + pred = self.normalizer.normalize(test_input, verbose=False) + assert pred.strip() == expected.strip() + + #@parameterized.expand(parse_test_case_file('ta/data_inverse_text_normalization/test_cases_cardinal.txt')) + #@pytest.mark.run_only_on('CPU') + #@pytest.mark.unit + #def test_denorm(self, test_input, expected): + #pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + #assert pred == expected From c2fc1005c8552a8b0f85f901fcb68faade2cf576 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 17 Jun 2026 14:16:05 +0530 Subject: [PATCH 04/29] Updated Ta Cardinal Signed-off-by: surendran-246 --- .../text_normalization/run_evaluate.py | 2 +- .../text_normalization/ta/taggers/punctuation.py | 13 +++++++++++++ .../text_normalization/ta/taggers/word.py | 2 +- nemo_text_processing/text_normalization/ta/utils.py | 2 +- .../text_normalization/ta/verbalizers/verbalize.py | 2 -- .../ta/verbalizers/verbalize_final.py | 2 +- .../text_normalization/ta/verbalizers/word.py | 2 +- tests/nemo_text_processing/ta/__init__.py | 2 +- tests/nemo_text_processing/ta/test_cardinal.py | 2 +- 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/nemo_text_processing/text_normalization/run_evaluate.py b/nemo_text_processing/text_normalization/run_evaluate.py index fd0fac207..d0d5bada3 100644 --- a/nemo_text_processing/text_normalization/run_evaluate.py +++ b/nemo_text_processing/text_normalization/run_evaluate.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/taggers/punctuation.py b/nemo_text_processing/text_normalization/ta/taggers/punctuation.py index 32bc395e9..82aa82c93 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/punctuation.py +++ b/nemo_text_processing/text_normalization/ta/taggers/punctuation.py @@ -1,3 +1,16 @@ +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. import sys from unicodedata import category diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index 6398a78fd..ed2566ade 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/utils.py b/nemo_text_processing/text_normalization/ta/utils.py index 5d314506e..fa0471fb6 100644 --- a/nemo_text_processing/text_normalization/ta/utils.py +++ b/nemo_text_processing/text_normalization/ta/utils.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py index 2c27b0e56..dca601f77 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py @@ -42,9 +42,7 @@ def __init__(self, deterministic: bool = True): cardinal = CardinalFst(deterministic=deterministic) cardinal_graph = cardinal.fst - - graph = ( cardinal_graph diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py index f9c300aae..5eb01cd97 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index 9734d3d25..f9683a102 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/nemo_text_processing/ta/__init__.py b/tests/nemo_text_processing/ta/__init__.py index d9155f923..4fc25d0d3 100644 --- a/tests/nemo_text_processing/ta/__init__.py +++ b/tests/nemo_text_processing/ta/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index 3be785d55..58b20abd7 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From f9d575d7bf83fb6652f47c826bdabebab29000b2 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 12:34:20 +0530 Subject: [PATCH 05/29] cardinal implementation Signed-off-by: surendran-246 --- .../text_cases_cardinal.txt | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt diff --git a/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt deleted file mode 100644 index 5f2f741a5..000000000 --- a/tests/nemo_text_processing/ta/data_inverse_text_normalization/text_cases_cardinal.txt +++ /dev/null @@ -1,54 +0,0 @@ -நான்கு ஃபோர்கள்~௪ ஃபோர்கள் -ஆறு வீரர்கள் அவுட்~௬ வீரர்கள் அவுட் -ஒன்பிளஸ் எட்டு ப்ரோ~ஒன்பிளஸ் ௮ ப்ரோ -ஐந்து சார்ஜர்கள்~௫ சார்ஜர்கள் -நான்கு ஓவரில் பதினேழு ரன்கள்~௪ ஓவரில் ௧௭ ரன்கள் -ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள்~௫ சாக்லெட்டுகள் ௯ டாஃபிகள் -பத்தாயிரத்து தொண்ணூற்று ஒன்பது~௧௦௦௯௯ -ஒரு இலட்சத்து ஒன்று~௧௦௦௦௦௧ -நூறு~௧௦௦ -முன்னூற்று ஒன்பது~௩௦௯ -எழுநூற்று தொண்ணூற்று எட்டு~௭௯௮ -ஐந்தாயிரம்~௫௦௦௦ -எட்டாயிரத்து நான்கு~௮௦௦௪ -ஒன்பதாயிரத்து பதினாறு~௯௦௧௬ -ஆயிரத்து தொள்ளாயிரத்து பன்னிரண்டு~௧௯௧௨ -இரண்டாயிரத்து இருநூற்று இருபத்து இரண்டு~௨௨௨௨ -பதினான்காயிரம்~௧௪௦௦௦ -பதினெட்டாயிரத்து ஆறு~௧௮௦௦௬ -இருபத்தாறாயிரத்து இருபத்து ஒன்று~௨௬௦௨௧ -தொண்ணூற்றாறாயிரத்து எண்ணூற்று பதினொன்று~௯௬௮௧௧ -நான்கு இலட்சம்~௪௦௦௦௦௦ -இரண்டு இலட்சத்து இரண்டு~௨௦௦௦௦௨ -ஏழு இலட்சத்து இருபது~௭௦௦௦௨௦ -ஒன்பது இலட்சத்து முன்னூற்று இருபத்து ஒன்று~௯௦௦௩௨௧ -எட்டு இலட்சத்து ஐந்தாயிரத்து முன்னூற்று இருபத்து ஒன்று~௮௦௫௩௨௧ -இருபத்து மூன்று இலட்சம்~௨௩௦௦௦௦௦ -பதினைந்து இலட்சத்து ஒன்று~௧௫௦௦௦௦௧ -இருபத்து ஏழு இலட்சத்து எண்ணூற்று இருபது~௨௭௦௦௮௨௦ -தொண்ணூற்று ஒரு இலட்சத்து முப்பத்தொன்றாயிரத்து எண்ணூற்று இருபத்து ஒன்பது~௯௧௩௧௮௨௯ -மூன்று கோடி~௩௦௦௦௦௦௦௦ -ஒரு கோடியே ஒன்று~௧௦௦௦௦௦௦௧ -ஏழு கோடியே பதின்மூன்று~௭௦௦௦௦௦௧௩ -நான்கு கோடியே தொள்ளாயிரத்து பதினொன்று~௪௦௦௦௦௯௧௧ -ஆறு கோடியே ஐந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௬௦௦௦௫௯௧௧ -ஆறு கோடியே இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௬௦௦௨௫௯௧௧ -மூன்று கோடியே ஒரு இலட்சத்து இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௩௦௧௨௫௯௧௧ -இரண்டு கோடியே பதினேழு இலட்சத்து இருபத்தைந்தாயிரத்து தொள்ளாயிரத்து பதினொன்று~௨௧௭௨௫௯௧௧ -முப்பது கோடி~௩௦௦௦௦௦௦௦௦ -தொண்ணூற்று எட்டு இலட்சத்து எழுபத்தாறாயிரத்து எழுநூற்று எண்பத்து ஒன்பது~௯௮௭௬௭௮௯ -இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௨௩௪௫௫௬௭ -ஒரு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௨௩௪௫௫௬௭ -ஒரு கோடியே இருபத்து ஒன்று இலட்சத்து இருபத்து ஒன்றாயிரத்து இருநூற்று பன்னிரண்டு~௧௨௧௨௧௨௧௨ -ஒரு அரபே பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௧௨௨௩௪௫௫௬௭ -ஒரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௦௨௨௩௪௫௫௬௭ -பதினொரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௧௧௦௨௨௩௪௫௫௬௭ -ஐம்பத்து ஒரு அரபே இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்தைந்தாயிரத்து ஐந்நூற்று அறுபத்து ஏழு~௫௧௦௨௨௩௪௫௫௬௭ -ஏழே கால் நூறு~௭௨௫ -ஏழரை நூறு~௭௫௦ -ஏழரை ஆயிரம்~௭௫௦௦ -ஏழே கால் ஆயிரம்~௭௨௫௦ -நூற்று ஐம்பது~௧௫௦ -இருநூற்று ஐம்பது~௨௫௦ -பதினாறு நூற்று ஐம்பது~௧௬௫௦ -பதினாறு நூற்று இருபத்தைந்து~௧௬௨௫ \ No newline at end of file From fcfcb3ed1fbfce7a9e2cf352e4067ed405cbd3c9 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 12:36:33 +0530 Subject: [PATCH 06/29] cardinal file Signed-off-by: surendran-246 --- test_cases_cardinal.txt | 100 ---------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 test_cases_cardinal.txt diff --git a/test_cases_cardinal.txt b/test_cases_cardinal.txt deleted file mode 100644 index 17716aafb..000000000 --- a/test_cases_cardinal.txt +++ /dev/null @@ -1,100 +0,0 @@ -0~சுழியம் -1~ஒன்று -2~இரண்டு -3~மூன்று -4~நான்கு -5~ஐந்து -6~ஆறு -7~ஏழு -8~எட்டு -9~ஒன்பது -10~பத்து -11~பதினொன்று -12~பன்னிரண்டு -13~பதின்மூன்று -14~பதினான்கு -15~பதினைந்து -16~பதினாறு -17~பதினேழு -18~பதினெட்டு -19~பத்தொன்பது -20~இருபது -21~இருபத்தொன்று -22~இருபத்திரண்டு -23~இருபத்துமூன்று -24~இருபத்துநான்கு -25~இருபத்தைந்து -26~இருபத்தாறு -27~இருபத்தேழு -28~இருபத்தெட்டு -29~இருபத்தொன்பது -30~முப்பது -31~முப்பத்தொன்று -32~முப்பத்திரண்டு -33~முப்பத்துமூன்று -34~முப்பத்துநான்கு -35~முப்பத்தைந்து -36~முப்பத்தாறு -37~முப்பத்தேழு -38~முப்பத்தெட்டு -39~முப்பத்தொன்பது -40~நாற்பது -41~நாற்பத்தொன்று -42~நாற்பத்திரண்டு -43~நாற்பத்துமூன்று -44~நாற்பத்துநான்கு -45~நாற்பத்தைந்து -46~நாற்பத்தாறு -47~நாற்பத்தேழு -48~நாற்பத்தெட்டு -49~நாற்பத்தொன்பது -50~ஐம்பது -51~ஐம்பத்தொன்று -52~ஐம்பத்திரண்டு -53~ஐம்பத்துமூன்று -54~ஐம்பத்துநான்கு -55~ஐம்பத்தைந்து -56~ஐம்பத்தாறு -57~ஐம்பத்தேழு -58~ஐம்பத்தெட்டு -59~ஐம்பத்தொன்பது -60~அறுபது -61~அறுபத்தொன்று -62~அறுபத்திரண்டு -63~அறுபத்துமூன்று -64~அறுபத்துநான்கு -65~அறுபத்தைந்து -66~அறுபத்தாறு -67~அறுபத்தேழு -68~அறுபத்தெட்டு -69~அறுபத்தொன்பது -70~எழுபது -71~எழுபத்தொன்று -72~எழுபத்திரண்டு -73~எழுபத்துமூன்று -74~எழுபத்துநான்கு -75~எழுபத்தைந்து -76~எழுபத்தாறு -77~எழுபத்தேழு -78~எழுபத்தெட்டு -79~எழுபத்தொன்பது -80~எண்பது -81~எண்பத்தொன்று -82~எண்பத்திரண்டு -83~எண்பத்துமூன்று -84~எண்பத்துநான்கு -85~எண்பத்தைந்து -86~எண்பத்தாறு -87~எண்பத்தேழு -88~எண்பத்தெட்டு -89~எண்பத்தொன்பது -90~தொண்ணூறு -91~தொண்ணூற்றொன்று -92~தொண்ணூற்றிரண்டு -93~தொண்ணூற்றுமூன்று -94~தொண்ணூற்றுநான்கு -95~தொண்ணூற்றைந்து -96~தொண்ணூற்றாறு -97~தொண்ணூற்றேழு -98~தொண்ணூற்றெட்டு -99~தொண்ணூற்றொன்பது \ No newline at end of file From 423f239d534130595c2068fd12e693f8b9837204 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 12:41:13 +0530 Subject: [PATCH 07/29] Updated cardinal file Signed-off-by: surendran-246 --- .../text_normalization/blind_testcases_ta | 1398 ----------------- 1 file changed, 1398 deletions(-) delete mode 100644 nemo_text_processing/text_normalization/blind_testcases_ta diff --git a/nemo_text_processing/text_normalization/blind_testcases_ta b/nemo_text_processing/text_normalization/blind_testcases_ta deleted file mode 100644 index 4a2911adf..000000000 --- a/nemo_text_processing/text_normalization/blind_testcases_ta +++ /dev/null @@ -1,1398 +0,0 @@ -CARDINAL ௪ சிக்ஸர்கள் ௧௪ பவுண்டரிகள் நான்கு சிக்ஸர்கள் பதினான்கு பவுண்டரிகள் - -CARDINAL ௬ ரன்கள் எடுத்தார் ஆறு ரன்கள் எடுத்தார் - -CARDINAL ௩ கோல்கள் அடித்தார் மூன்று கோல்கள் அடித்தார் - -CARDINAL ௯ சிக்ஸர்கள் ஒன்பது சிக்ஸர்கள் - -CARDINAL ௫ பவுண்டரிகள் ஐந்து பவுண்டரிகள் - -CARDINAL ௨ சிக்ஸர்கள் ௧௨ ரன்கள் இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் - -CARDINAL ௯ புள்ளிகள் ஒன்பது புள்ளிகள் - -CARDINAL ௪ பேர் உயிரிழப்பு ௧௮ பேர் காயம் நான்கு பேர் உயிரிழப்பு பதினெட்டு பேர் காயம் - -CARDINAL ௫ கோல்கள் அடித்தனர் ஐந்து கோல்கள் அடித்தனர் - -CARDINAL ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள் மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் - -CARDINAL ௧ ஓவர் ௧௩ ரன்கள் ஒன்று ஓவர் பதிமூன்று ரன்கள் - -CARDINAL ௩ ஓவர்கள் மூன்று ஓவர்கள் - -CARDINAL ௫ கோல்கள் ஐந்து கோல்கள் - -CARDINAL ௩ ஆப்பிள்கள் மூன்று ஆப்பிள்கள் - -CARDINAL ௭ வாழைப்பழங்கள் ஏழு வாழைப்பழங்கள் - -CARDINAL ௩ தோல்வி ௧௨ வெற்றி மூன்று தோல்வி பன்னிரண்டு வெற்றி - -CARDINAL ௫ தோல்விகள் ௧ டிரா ௧௭ வெற்றிகள் ஐந்து தோல்விகள் ஒன்று டிரா பதினேழு வெற்றிகள் - -CARDINAL ௮ போட்டிகள் டிரா எட்டு போட்டிகள் டிரா - -CARDINAL ௪ பவுண்டரிகள் நான்கு பவுண்டரிகள் - -CARDINAL ௮ சிக்ஸர்கள் ௨ அவுட் எட்டு சிக்ஸர்கள் இரண்டு அவுட் - -CARDINAL ௬ வீரர்கள் அவுட் ஆறு வீரர்கள் அவுட் - -CARDINAL ௪ ரன்கள் ௩ பவுண்டரிகள் நான்கு ரன்கள் மூன்று பவுண்டரிகள் - -CARDINAL ஒன்பிளஸ் ௮ ப்ரோ ஒன்பிளஸ் எட்டு ப்ரோ - -CARDINAL ௫ சார்ஜர்கள் ஐந்து சார்ஜர்கள் - -CARDINAL ௪ ஓவரில் ௧௭ ரன்கள் நான்கு ஓவரில் பதினேழு ரன்கள் - -CARDINAL ௫ சாக்லேட்டுகள் ௯ டாபிகள் ஐந்து சாக்லேட்டுகள் ஒன்பது டாபிகள் - -CARDINAL ௬ பேட்ஸ்மேன்கள் ௨ பவுலர்கள் ஆறு பேட்ஸ்மேன்கள் இரண்டு பவுலர்கள் - -CARDINAL ௧ விக்கெட் கீப்பர் ஒன்று விக்கெட் கீப்பர் - -CARDINAL ௮ கேட்ச் அவுட் எட்டு கேட்ச் அவுட் - -CARDINAL ௫ விக்கெட்டுக்கு ௧௦ ரன்கள் ஐந்து விக்கெட்டுக்கு பத்து ரன்கள் - -CARDINAL ௭ வெற்றி ௨ டிரா ஏழு வெற்றி இரண்டு டிரா - -CARDINAL ௨ பவுண்டரிகள் இரண்டு பவுண்டரிகள் - -CARDINAL ௬ ரன்கள் ௫ விக்கெட்டுகள் ஆறு ரன்கள் ஐந்து விக்கெட்டுகள் - -CARDINAL ௭ பந்துகள் ௧௧ ரன்கள் ஏழு பந்துகள் பதினொன்று ரன்கள் - -CARDINAL ௬ சாக்லேட்டுகள் ௪ டாபிகள் ஆறு சாக்லேட்டுகள் நான்கு டாபிகள் - -CARDINAL ௮ வெண்கலங்கள் ௨ தங்கங்கள் எட்டு வெண்கலங்கள் இரண்டு தங்கங்கள் - -CARDINAL ௧ தங்கப் பதக்கம் ஒன்று தங்கப் பதக்கம் - -CARDINAL ௩ ரன்கள் மூன்று ரன்கள் - -CARDINAL ௫ ஓவர்கள் ஐந்து ஓவர்கள் - -CARDINAL ௬ பந்து ஆறு பந்து - -CARDINAL ௩ இன்னிங்ஸ் மூன்று இன்னிங்ஸ் - -CARDINAL வசனம் ௭ பாடம் ௧௫ வசனம் ஏழு பாடம் பதினைந்து - -CARDINAL பாடம் எண் ௨ வசனம் ௪ பாடம் எண் இரண்டு வசனம் நான்கு - -CARDINAL பக்க எண் ௮ பத்தி ௬ பக்க எண் எட்டு பத்தி ஆறு - -CARDINAL ௨ பந்துகள் ௪ ரன்கள் இரண்டு பந்துகள் நான்கு ரன்கள் - -CARDINAL ௬ விக்கெட்டுகள் ஆறு விக்கெட்டுகள் - -CARDINAL ௨ புள்ளி ௫ கோல்கள் இரண்டு புள்ளி ஐந்து கோல்கள் - -CARDINAL பாடம் ௧௦ ஸ்லோகம் ௨ பாடம் பத்து ஸ்லோகம் இரண்டு - -CARDINAL அத்தியாயம் ௫ காட்சி ௬ அத்தியாயம் ஐந்து காட்சி ஆறு - -CARDINAL ௬ கேள்விகள் ௫ தவறு ஆறு கேள்விகள் ஐந்து தவறு - -CARDINAL ௩ ரோஜா ௪ மல்லிகை ௨ சாமந்தி மூன்று ரோஜா நான்கு மல்லிகை இரண்டு சாமந்தி - -CARDINAL ௨ ஃப்ரீ ஹிட் ௧ நோ பால் இரண்டு ஃப்ரீ ஹிட் ஒன்று நோ பால் - -CARDINAL ௩ போன் ௧ சார்ஜர் மூன்று போன் ஒன்று சார்ஜர் - -CARDINAL ௬ டிரா ௭ தோல்வி ௯ வெற்றி ஆறு டிரா ஏழு தோல்வி ஒன்பது வெற்றி - -CARDINAL ௪ கார் ௨ பைக் நான்கு கார் இரண்டு பைக் - -CARDINAL ௧ கூடை ௮ பழம் ஒன்று கூடை எட்டு பழம் - -CARDINAL ௩ வரிசை ௮ நபர் மூன்று வரிசை எட்டு நபர் - -CARDINAL ௧௦ பென்சில் ௨ பேனா பத்து பென்சில் இரண்டு பேனா - -CARDINAL ௫ கட்டிடம் ஐந்து கட்டிடம் - -CARDINAL ௬ குழந்தை ஆறு குழந்தை - -CARDINAL பத்தி ௧௩ வரிசை ௪ பத்தி பதிமூன்று வரிசை நான்கு - -CARDINAL ௩ தங்கம் ௪ வெள்ளி மூன்று தங்கம் நான்கு வெள்ளி - -CARDINAL ௫ குழிகள் ஐந்து குழிகள் - -CARDINAL ௮ குப்பம் எட்டு குப்பம் - -CARDINAL ௩ லேப்டாப் மூன்று லேப்டாப் - -CARDINAL ௧ சிக்ஸர் ௨ பவுண்டரிகள் ஒன்று சிக்ஸர் இரண்டு பவுண்டரிகள் - -CARDINAL ௫ பஸ் ஐந்து பஸ் - -CARDINAL ௨ லாரி இரண்டு லாரி - -CARDINAL ௩ வண்டி மூன்று வண்டி - -CARDINAL ௬ சுறா ௩௦ முதலீட்டாளர்கள் ஆறு சுறா முப்பது முதலீட்டாளர்கள் - -CARDINAL ௨ அமைச்சர் ௫௦ பிரச்சனைகள் இரண்டு அமைச்சர் ஐம்பது பிரச்சனைகள் - -CARDINAL ௬ பவுலர் ஆறு பவுலர் - -CARDINAL ஸ்லோகம் ௩ பாடம் ௧ ஸ்லோகம் மூன்று பாடம் ஒன்று - -CARDINAL வரிசை ௬ பத்தி ௯ வரிசை ஆறு பத்தி ஒன்பது - -CARDINAL புத்தகம் ௧ பாடம் ௮ புத்தகம் ஒன்று பாடம் எட்டு - -CARDINAL சிறுகதை எண் ௨ வரிசை ௬ சிறுகதை எண் இரண்டு வரிசை ஆறு - -CARDINAL கைதி எண் ௪ கைதி எண் நான்கு - -CARDINAL பக்க எண் ௧௦ வரிசை ௨ பக்க எண் பத்து வரிசை இரண்டு - -CARDINAL ௪ மருத்துவர் நான்கு மருத்துவர் - -CARDINAL ௨ பந்து ௩ ரன் இரண்டு பந்து மூன்று ரன் - -CARDINAL புள்ளிகள் ௨ கோல் ௪ புள்ளிகள் இரண்டு கோல் நான்கு - -CARDINAL பாடம் எண் ௪ பாடம் எண் நான்கு - -CARDINAL ௮ ஓவர் எட்டு ஓவர் - -CARDINAL ௭ ரன் ௨ ஓவர் ஏழு ரன் இரண்டு ஓவர் - -CARDINAL ௪ பந்து ௮ ரன் நான்கு பந்து எட்டு ரன் - -CARDINAL ௩ பாட்டில் ௫ கிளாஸ் மூன்று பாட்டில் ஐந்து கிளாஸ் - -CARDINAL ௬ ரன் ஆறு ரன் - -CARDINAL ௬ கோல் ஆறு கோல் - -CARDINAL ௧௦ புள்ளிகள் ௩ கோல் பத்து புள்ளிகள் மூன்று கோல் - -CARDINAL ௧௪ சிக்ஸர் ௩ பவுண்டரி பதினான்கு சிக்ஸர் மூன்று பவுண்டரி - -CARDINAL ௬ ஆப்பிள் ௩ வாழைப்பழம் ஆறு ஆப்பிள் மூன்று வாழைப்பழம் - -CARDINAL ௩ மேட்ச் டிரா மூன்று மேட்ச் டிரா - -CARDINAL ௬ மேட்ச் தோல்வி ஆறு மேட்ச் தோல்வி - -CARDINAL ௯ மேட்ச் வெற்றி ஒன்பது மேட்ச் வெற்றி - -CARDINAL ஸ்லோகம் ௬ பாடம் ௯ ஸ்லோகம் ஆறு பாடம் ஒன்பது - -CARDINAL பதம் ௪ வரிசை எண் ௩ பதம் நான்கு வரிசை எண் மூன்று - -CARDINAL பாடம் ௧௦ பக்கம் ௪ பாடம் பத்து பக்கம் நான்கு - -CARDINAL ௫ கார் ௨ மோட்டார் சைக்கிள் ஐந்து கார் இரண்டு மோட்டார் சைக்கிள் - -CARDINAL ௭ புள்ளிகள் ௨ கோல் ஏழு புள்ளிகள் இரண்டு கோல் - -CARDINAL ௪ இரவு ௩ பகல் நான்கு இரவு மூன்று பகல் - -CARDINAL ௧ ஆஸ் ௧ ராணி ௫ சீட்டுகள் ஒன்று ஆஸ் ஒன்று ராணி ஐந்து சீட்டுகள் - -CARDINAL வரிசை ௨ பத்தி ௧ வரிசை இரண்டு பத்தி ஒன்று - -CARDINAL ௫ ஜோடி காலணி ஐந்து ஜோடி காலணி - -CARDINAL ௧௦ ஓவரில் ௯ ரன் பத்து ஓவரில் ஒன்பது ரன் - -CARDINAL ௮ ரன் எட்டு ரன் - -CARDINAL ௪ சிக்ஸர்கள் ௧ ஃபோர் நான்கு சிக்ஸர்கள் ஒன்று ஃபோர் - -CARDINAL பக்க எண் ௯ இன் வரிசை ௪ பக்க எண் ஒன்பது இன் வரிசை நான்கு - -CARDINAL பாரா ௧௦ இன் பகுதி ௩ பாரா பத்து இன் பகுதி மூன்று - -CARDINAL ஆயத் ௪ ருகூ ௬ ஆயத் நான்கு ருகூ ஆறு - -CARDINAL பாரா ௯ ருகூ ௬ பாரா ஒன்பது ருகூ ஆறு - -CARDINAL ௮ கால்சட்டைகள் ௯ சட்டைகள் எட்டு கால்சட்டைகள் ஒன்பது சட்டைகள் - -CARDINAL ௪ ரொட்டி ௨ காய்கறி நான்கு ரொட்டி இரண்டு காய்கறி - -CARDINAL ௩ மேட்ச் ௪ வெற்றி மூன்று மேட்ச் நான்கு வெற்றி - -CARDINAL ௪ தோல்வி ௩ வெற்றி ௧ டிரா நான்கு தோல்வி மூன்று வெற்றி ஒன்று டிரா - -CARDINAL படம் ௧௯ பாடம் ௨ படம் பத்தொன்பது பாடம் இரண்டு - -CARDINAL பாடம் ௧ பக்கம் ௧௨௨ பாடம் ஒன்று பக்கம் நூற்று இருபத்து இரண்டு - -CARDINAL பாடம் ௩ வரிசை ௬ பாடம் மூன்று வரிசை ஆறு - -CARDINAL ஸ்லோகம் ௧௦ பக்கம் ௩ ஸ்லோகம் பத்து பக்கம் மூன்று - -CARDINAL ௬ புள்ளிகள் ௩ கோல் ஆறு புள்ளிகள் மூன்று கோல் - -CARDINAL ௨ டெஸ்ட் போட்டிகள் ௬ ஒன்றுநாள் போட்டிகள் இரண்டு டெஸ்ட் போட்டிகள் ஆறு ஒன்றுநாள் போட்டிகள் - -CARDINAL ௨ ஓவரில் ௭ ரன் இரண்டு ஓவரில் ஏழு ரன் - -CARDINAL ௮ ஓவரில் ௪௫ ரன் எட்டு ஓவரில் நாற்பத்து ஐந்து ரன் - -CARDINAL ௯ ஓவரில் ௬௦ ரன் ஒன்பது ஓவரில் அறுபது ரன் - -CARDINAL ௫ போட்டிகள் ௪ வெற்றிகள் ஐந்து போட்டிகள் நான்கு வெற்றிகள் - -CARDINAL ௨ வெற்றி ௪ தோல்வி ௫ டிரா இரண்டு வெற்றி நான்கு தோல்வி ஐந்து டிரா - -CARDINAL ஸ்லோகம் ௯ பக்கம் ௭ ஸ்லோகம் ஒன்பது பக்கம் ஏழு - -CARDINAL பாடம் ௨ பக்கம் ௬௬ பாடம் இரண்டு பக்கம் அறுபத்து ஆறு - -CARDINAL ௨ டயகிராம் ௧௩ பக்க எண் இரண்டு டயகிராம் பதிமூன்று பக்க எண் - -CARDINAL பட எண் ௮ பாடம் ௪ பட எண் எட்டு பாடம் நான்கு - -CARDINAL பக்க எண் ௧௦ பாடம் ௩ பக்க எண் பத்து பாடம் மூன்று - -CARDINAL ருகு ௩ ஆயத் ௮ ருகு மூன்று ஆயத் எட்டு - -CARDINAL ருகு ௪ ஆயத் ௬ வரி ௩௩ ருகு நான்கு ஆயத் ஆறு வரி முப்பத்து மூன்று - -CARDINAL பாரா ௨ ருகு ௭ வரி ௧௫ பாரா இரண்டு ருகு ஏழு வரி பதினைந்து - -CARDINAL ௩௦ பாரா வரி ௮ முப்பது பாரா வரி எட்டு - -CARDINAL ௪ சிக்ஸர்கள் ௧௨ ஃபோர்கள் நான்கு சிக்ஸர்கள் பன்னிரண்டு ஃபோர்கள் - -CARDINAL ௫ புள்ளிகள் ௭ கோல்கள் ஐந்து புள்ளிகள் ஏழு கோல்கள் - -CARDINAL பதிப்பு ௨ தலைமுறை ௪ பதிப்பு இரண்டு தலைமுறை நான்கு - -CARDINAL ௮ செங்கற்கள் ௩௨ கற்கள் எட்டு செங்கற்கள் முப்பத்து இரண்டு கற்கள் - -CARDINAL ௯ ஓவரில் ௧௫ ரன்கள் ஒன்பது ஓவரில் பதினைந்து ரன்கள் - -CARDINAL ௪ விக்கெட் ௧௧௩ ரன்கள் நான்கு விக்கெட் நூற்று பதிமூன்று ரன்கள் - -CARDINAL ௭ விக்கெட் ௨௧௧ ரன்கள் ஏழு விக்கெட் இருநூற்று பதினொன்று ரன்கள் - -CARDINAL ௪ சிக்ஸர்கள் ௫ ஃபோர்கள் ௪௪ ரன்கள் நான்கு சிக்ஸர்கள் ஐந்து ஃபோர்கள் நாற்பத்து நான்கு ரன்கள் - -CARDINAL ருகு ௮ வரி ௧௦ ருகு எட்டு வரி பத்து - -CARDINAL பாடம் ௯ வரி ௧௩ பாடம் ஒன்பது வரி பதிமூன்று - -CARDINAL பகுதி ௧௦ வரி ௬ சுலோகம் ௨ பகுதி பத்து வரி ஆறு சுலோகம் இரண்டு - -CARDINAL பகுதி ௧௨ சுலோகம் ௩ வரி ௧௭ பகுதி பன்னிரண்டு சுலோகம் மூன்று வரி பதினேழு - -CARDINAL ௭ ஓவர் ஏழு ஓவர் - -CARDINAL ௬ ஃபோர்கள் ஆறு ஃபோர்கள் - -CARDINAL ௩ ஒன்றுநாள் ௫ டெஸ்ட் போட்டிகள் மூன்று ஒன்றுநாள் ஐந்து டெஸ்ட் போட்டிகள் - -CARDINAL ௭ வீரர்கள் ௨ காயம் ஏழு வீரர்கள் இரண்டு காயம் - -CARDINAL பதிப்பு ௩ தலைமுறை ௧௦ பதிப்பு மூன்று தலைமுறை பத்து - -CARDINAL ருகு ௧௪ பாரா ௮ ருகு பதினான்கு பாரா எட்டு - -CARDINAL சுலோகம் ௮ பாடம் ௬ சுலோகம் எட்டு பாடம் ஆறு - -CARDINAL விரிவுரை ௩ வகுப்பு ௮ விரிவுரை மூன்று வகுப்பு எட்டு - -CARDINAL வகுப்பு ௧௦ பிரிவு ௨ வகுப்பு பத்து பிரிவு இரண்டு - -CARDINAL ௩ டிரா ௨ தோல்வி மூன்று டிரா இரண்டு தோல்வி - -CARDINAL சுலோகம் ௩ பாடம் ௧௧ சுலோகம் மூன்று பாடம் பதினொன்று - -CARDINAL வரி ௬ பாடம் ௧௦ வரி ஆறு பாடம் பத்து - -CARDINAL ருகு ௨ பாரா ௧௫ ருகு இரண்டு பாரா பதினைந்து - -CARDINAL ௪ சிக்ஸர்கள் ௫ பந்துகள் நான்கு சிக்ஸர்கள் ஐந்து பந்துகள் - -CARDINAL ௨ பந்துகள் ௧ ரன் இரண்டு பந்துகள் ஒன்று ரன் - -CARDINAL வரி ௮ அத்தியாயம் ௧௯ வரி எட்டு அத்தியாயம் பத்தொன்பது - -CARDINAL பக்கம் ௧௦ பத்தி ௨ பக்கம் பத்து பத்தி இரண்டு - -CARDINAL ௯ ஓவரில் ௧௭ ரன்கள் ஒன்பது ஓவரில் பதினேழு ரன்கள் - -CARDINAL ௪ பந்துகளில் ௬ நான்கு பந்துகளில் ஆறு - -CARDINAL ௧௭ பந்துகளில் ௧௦ ரன்கள் பதினேழு பந்துகளில் பத்து ரன்கள் - -CARDINAL ௫ ஓவர் ௬௬ ரன்கள் ஐந்து ஓவர் அறுபத்து ஆறு ரன்கள் - -CARDINAL ௮ புள்ளிகள் ௯ கோல்கள் எட்டு புள்ளிகள் ஒன்பது கோல்கள் - -CARDINAL ௫ கொய்யாப்பழங்கள் ஐந்து கொய்யாப்பழங்கள் - -CARDINAL ௬ ருகு ௭ பாரா ஆறு ருகு ஏழு பாரா - -CARDINAL சுலோகம் ௮ பதம் ௯ சுலோகம் எட்டு பதம் ஒன்பது - -CARDINAL ௭ ஓவரில் ௨௧ ரன்கள் ஏழு ஓவரில் இருபத்து ஒன்று ரன்கள் - -CARDINAL ௧ ஓவரில் ௩ ரன்கள் ஒன்று ஓவரில் மூன்று ரன்கள் - -CARDINAL ௭ சிக்ஸர்கள் ௫ ஃபோர்கள் ஏழு சிக்ஸர்கள் ஐந்து ஃபோர்கள் - -CARDINAL ௩ சுலோகங்கள் மூன்று சுலோகங்கள் - -CARDINAL ௬ பக்கங்கள் ஆறு பக்கங்கள் - -CARDINAL ௫ சிக்ஸர்கள் ஐந்து சிக்ஸர்கள் - -CARDINAL ௩ பாட்டில்கள் ௧௦ கண்ணாடிகள் மூன்று பாட்டில்கள் பத்து கண்ணாடிகள் - -CARDINAL ௩ போட்டிகள் மூன்று போட்டிகள் - -CARDINAL ௬ போட்டிகள் ௪ டிரா ஆறு போட்டிகள் நான்கு டிரா - -CARDINAL ௨ பந்துகளில் ௩ ரன்கள் இரண்டு பந்துகளில் மூன்று ரன்கள் - -CARDINAL ௩ புள்ளிகள் ௪ கோல்கள் மூன்று புள்ளிகள் நான்கு கோல்கள் - -CARDINAL ஆயத் ௪ வரி ௯ ஆயத் நான்கு வரி ஒன்பது - -CARDINAL பாரா ௪ ருகு ௧௦ வரி ௧௭ பாரா நான்கு ருகு பத்து வரி பதினேழு - -CARDINAL பாரா ௬ ருகு ௨௫ வரி ௨௦ பாரா ஆறு ருகு இருபத்து ஐந்து வரி இருபது - -CARDINAL பாடம் ௩ தோஹா ௪ வரி ௨ பாடம் மூன்று தோஹா நான்கு வரி இரண்டு - -CARDINAL வரி ௮ சொல் ௬ வரி எட்டு சொல் ஆறு - -CARDINAL கட்டுரை ௧௦ பத்தி ௨ கட்டுரை பத்து பத்தி இரண்டு - -CARDINAL ௭ ஸ்வரங்கள் ஏழு ஸ்வரங்கள் - -CARDINAL பாடல் ௪ முகடை ௨ பாடல் நான்கு முகடை இரண்டு - -CARDINAL டிக்கெட் எண் ௯ வரி ௮ டிக்கெட் எண் ஒன்பது வரி எட்டு - -CARDINAL ஆயத் ௧௦ வரி ௧௮ ஆயத் பத்து வரி பதினெட்டு - -CARDINAL ௬ ஓவர் ௨௦ ரன்கள் ஆறு ஓவர் இருபது ரன்கள் - -CARDINAL ௮௦ ரன்கள் ௩ விக்கெட்டுகள் எண்பது ரன்கள் மூன்று விக்கெட்டுகள் - -CARDINAL ௪ ஸ்பின்னர்கள் ௩ பேட்ஸ்மேன்கள் ௧ விக்கெட் கீப்பர் நான்கு ஸ்பின்னர்கள் மூன்று பேட்ஸ்மேன்கள் ஒன்று விக்கெட் கீப்பர் - -CARDINAL ௧ கோல் கீப்பர் ௬ வீரர்கள் ஒன்று கோல் கீப்பர் ஆறு வீரர்கள் - -CARDINAL பாடம் ௧௮ பதம் ௫ பாடம் பதினெட்டு பதம் ஐந்து - -CARDINAL தோஹா ௬ வரி ௯ தோஹா ஆறு வரி ஒன்பது - -CARDINAL படம் ௬ பக்கம் ௮௦ படம் ஆறு பக்கம் எண்பது - -CARDINAL ௨ டிரா ௩ வெற்றி இரண்டு டிரா மூன்று வெற்றி - -CARDINAL ௪ வைவா ௩ தேர்வுகள் நான்கு வைவா மூன்று தேர்வுகள் - -CARDINAL ௪ தேர்வுகள் ௬ செஷனல்கள் நான்கு தேர்வுகள் ஆறு செஷனல்கள் - -CARDINAL ௩ தட்டுகள் ௪ கிண்ணங்கள் ௨ கரண்டிகள் மூன்று தட்டுகள் நான்கு கிண்ணங்கள் இரண்டு கரண்டிகள் - -CARDINAL ௪ டிரா ௫ வெற்றி நான்கு டிரா ஐந்து வெற்றி - -CARDINAL ௮ சிக்ஸர்கள் ௧௪ ஃபோர்கள் எட்டு சிக்ஸர்கள் பதினான்கு ஃபோர்கள் - -CARDINAL ௫ ஓவர்கள் ௪ விக்கெட்டுகள் ஐந்து ஓவர்கள் நான்கு விக்கெட்டுகள் - -CARDINAL ௩ ரன்கள் ௨ விக்கெட்டுகள் மூன்று ரன்கள் இரண்டு விக்கெட்டுகள் - -CARDINAL ௬ ஓவர்கள் ௪ ரன்கள் ஆறு ஓவர்கள் நான்கு ரன்கள் - -CARDINAL ௪ டெஸ்ட் போட்டிகள் ௧ ஒன்றுநாள் போட்டி நான்கு டெஸ்ட் போட்டிகள் ஒன்று ஒன்றுநாள் போட்டி - -CARDINAL ௨ புள்ளிகள் ௧௨ கோல்கள் இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் - -CARDINAL ௭ கரண்டிகள் உடைந்தன ஏழு கரண்டிகள் உடைந்தன - -CARDINAL ௧௦ இல் ௬ மதிப்பெண்கள் பத்து இல் ஆறு மதிப்பெண்கள் - -CARDINAL பாடம் ௨ பக்க எண் ௧௨ பாடம் இரண்டு பக்க எண் பன்னிரண்டு - -CARDINAL ௧ ஓவரில் ௬ பந்துகள் ஒன்று ஓவரில் ஆறு பந்துகள் - -CARDINAL ௭ ஷாட்டுகள் சரியாக பட்டன ஏழு ஷாட்டுகள் சரியாக பட்டன - -CARDINAL இந்தியாவுக்கு ௪ புள்ளிகள் முன்னிலை இந்தியாவுக்கு நான்கு புள்ளிகள் முன்னிலை - -CARDINAL சதத்திற்கு ௩ ரன்கள் மீதம் சதத்திற்கு மூன்று ரன்கள் மீதம் - -CARDINAL ௧ தோல்வி ௨ டிரா ஒன்று தோல்வி இரண்டு டிரா - -CARDINAL அர்ஜென்டினா ௨ புள்ளிகள் பின்தங்கி அர்ஜென்டினா இரண்டு புள்ளிகள் பின்தங்கி - -CARDINAL ௨ கோல்கள் அடிக்கப்பட்டன இரண்டு கோல்கள் அடிக்கப்பட்டன - -CARDINAL ௮ கூடுதல் ரன்கள் எட்டு கூடுதல் ரன்கள் - -CARDINAL ௪ வைடு பந்துகள் நான்கு வைடு பந்துகள் - -CARDINAL வகுப்பு ௯ வகுப்பு ஒன்பது - -CARDINAL வகுப்பு ௫ வகுப்பு ஐந்து - -CARDINAL ௯ பகுதிகள் ஒன்பது பகுதிகள் - -CARDINAL வகுப்பு ௪ பாடம் ௩ வகுப்பு நான்கு பாடம் மூன்று - -CARDINAL பாடம் ௯ பாடம் ஒன்பது - -CARDINAL பக்க எண் ௮ பக்க எண் எட்டு - -CARDINAL ௪ பாட்டில்கள் நான்கு பாட்டில்கள் - -CARDINAL ௧௦௦ இல் ௪ மதிப்பெண்கள் நூறு இல் நான்கு மதிப்பெண்கள் - -CARDINAL ௮ மதிப்பெண்கள் எட்டு மதிப்பெண்கள் - -CARDINAL கண்ணாடி எண் ௨ கண்ணாடி எண் இரண்டு - -CARDINAL ௭ செருப்புகள் ஏழு செருப்புகள் - -CARDINAL ௫ காலணிகள் ஐந்து காலணிகள் - -CARDINAL ௨ சாண்டல்கள் இரண்டு சாண்டல்கள் - -CARDINAL ௭ விளையாட்டுகளில் வெற்றி ஏழு விளையாட்டுகளில் வெற்றி - -CARDINAL ௬ மூடிகள் ஆறு மூடிகள் - -CARDINAL ௧௦௦௦ ரூபாய் ௨ நோட்டுகள் ஆயிரம் ரூபாய் இரண்டு நோட்டுகள் - -CARDINAL ௧௯ இல் ௩ கண்ணாடிகள் பத்தொன்பது இல் மூன்று கண்ணாடிகள் - -CARDINAL பக்கம் ௧௯௯ பாடம் ௬ பக்கம் நூற்று தொண்ணூற்று ஒன்பது பாடம் ஆறு - -CARDINAL ௮ பாராக்கள் எட்டு பாராக்கள் - -CARDINAL பகுதி ௫ பாடம் ௧௯ பகுதி ஐந்து பாடம் பத்தொன்பது - -CARDINAL ௮௦ ரன்கள் ௬ விக்கெட்டுகள் எண்பது ரன்கள் ஆறு விக்கெட்டுகள் - -CARDINAL ௯ கூடுதல் ரன்கள் ஒன்பது கூடுதல் ரன்கள் - -CARDINAL ௧௧ பந்துகள் ௮ ரன்கள் பதினொன்று பந்துகள் எட்டு ரன்கள் - -CARDINAL ௨ மஞ்சள் ௮ சிவப்பு அட்டைகள் இரண்டு மஞ்சள் எட்டு சிவப்பு அட்டைகள் - -CARDINAL அத்தியாயம் ௧௨ சுலோகம் ௮ அத்தியாயம் பன்னிரண்டு சுலோகம் எட்டு - -CARDINAL பக்கம் ௮௮ அத்தியாயம் ௭ பக்கம் எண்பத்து எட்டு அத்தியாயம் ஏழு - -CARDINAL ௧௦௦ ரன்கள் ௫ விக்கெட்டுகள் நூறு ரன்கள் ஐந்து விக்கெட்டுகள் - -CARDINAL ௮ கோல்களால் வெற்றி எட்டு கோல்களால் வெற்றி - -CARDINAL ௩ சக்கர வாகனம் மூன்று சக்கர வாகனம் - -CARDINAL அத்தியாயம் ௧௯ பகுதி ௪ அத்தியாயம் பத்தொன்பது பகுதி நான்கு - -CARDINAL ௧௧ மாதங்கள் ௮ நாட்கள் பதினொன்று மாதங்கள் எட்டு நாட்கள் - -CARDINAL ௯ நாட்கள் ௧௨ மணி நேரம் ஒன்பது நாட்கள் பன்னிரண்டு மணி நேரம் - -CARDINAL ௪ கட்டுகள் ௧௩ அட்டைகள் நான்கு கட்டுகள் பதிமூன்று அட்டைகள் - -CARDINAL ௭ போட்டிகள் ௧௨ விக்கெட்டுகள் ஏழு போட்டிகள் பன்னிரண்டு விக்கெட்டுகள் - -CARDINAL ௧ மனிதன் ஒன்று மனிதன் - -CARDINAL ௨ பெண்கள் இரண்டு பெண்கள் - -CARDINAL ௩ குழந்தைகள் மூன்று குழந்தைகள் - -CARDINAL ௪ புத்தகங்கள் நான்கு புத்தகங்கள் - -CARDINAL ௫ அறைகள் ஐந்து அறைகள் - -CARDINAL ௬ வீடுகள் ஆறு வீடுகள் - -CARDINAL ௭ பக்கங்கள் ஏழு பக்கங்கள் - -CARDINAL ௮ நாணயங்கள் எட்டு நாணயங்கள் - -CARDINAL ௯ பெட்டிகள் ஒன்பது பெட்டிகள் - -CARDINAL ௧௦ வேலைகள் பத்து வேலைகள் - -CARDINAL ௧௧ பழங்கள் ௨ பூக்கள் பதினொன்று பழங்கள் இரண்டு பூக்கள் - -CARDINAL ௩ பூக்கள் மூன்று பூக்கள் - -CARDINAL ௧௩ பூந்தொட்டிகள் ௪ செடிகள் பதிமூன்று பூந்தொட்டிகள் நான்கு செடிகள் - -CARDINAL ௪ பப்பாளிப்பழங்கள் நான்கு பப்பாளிப்பழங்கள் - -CARDINAL ௫ மாம்பழங்கள் ஐந்து மாம்பழங்கள் - -CARDINAL ௬ வாழைப்பழங்கள் ஆறு வாழைப்பழங்கள் - -CARDINAL ௭ திராட்சைப்பழங்கள் ஏழு திராட்சைப்பழங்கள் - -CARDINAL ௮ ஆரஞ்சுப்பழங்கள் எட்டு ஆரஞ்சுப்பழங்கள் - -CARDINAL ௯ ஆப்பிள்கள் ஒன்பது ஆப்பிள்கள் - -CARDINAL ௧௦ சப்போட்டா பழங்கள் பத்து சப்போட்டா பழங்கள் - -CARDINAL ௧ தாமரை ஒன்று தாமரை - -CARDINAL ௨ கற்கள் இரண்டு கற்கள் - -CARDINAL ௩ நாற்காலிகள் மூன்று நாற்காலிகள் - -CARDINAL ௪ பைகள் நான்கு பைகள் - -CARDINAL ௫ தொலைபேசிகள் ஐந்து தொலைபேசிகள் - -CARDINAL ௬ அறைகள் ஆறு அறைகள் - -CARDINAL ௭ பெண்கள் ஏழு பெண்கள் - -CARDINAL ௮ புத்தகங்கள் எட்டு புத்தகங்கள் - -CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் - -CARDINAL ௧௦ நதிகள் பத்து நதிகள் - -CARDINAL ௩ எருமைகள் மூன்று எருமைகள் - -CARDINAL ௨ காலணிகள் இரண்டு காலணிகள் - -CARDINAL ௩ நாய்கள் மூன்று நாய்கள் - -CARDINAL ௪ குதிரைகள் நான்கு குதிரைகள் - -CARDINAL ௫ மகன்கள் ஐந்து மகன்கள் - -CARDINAL ௬ சேவல்கள் ஆறு சேவல்கள் - -CARDINAL ௭ கழுதைகள் ஏழு கழுதைகள் - -CARDINAL ௮ சிறுமிகள் எட்டு சிறுமிகள் - -CARDINAL ௯ சிறுவர்கள் ஒன்பது சிறுவர்கள் - -CARDINAL ௧௦ கேள்விகள் பத்து கேள்விகள் - -CARDINAL ௧ சட்டை ஒன்று சட்டை - -CARDINAL ௨ படகுகள் இரண்டு படகுகள் - -CARDINAL ௩ பெட்டிகள் மூன்று பெட்டிகள் - -CARDINAL ௪ மூடிகள் நான்கு மூடிகள் - -CARDINAL ௫ நோட்டுகள் ஐந்து நோட்டுகள் - -CARDINAL ௬ நாணயங்கள் ஆறு நாணயங்கள் - -CARDINAL ௭ காயங்கள் ஏழு காயங்கள் - -CARDINAL ௮ நிறங்கள் எட்டு நிறங்கள் - -CARDINAL ௯ மக்கள் ஒன்பது மக்கள் - -CARDINAL ௧௦ நாட்கள் பத்து நாட்கள் - -CARDINAL ௫ விஷயங்கள் ஐந்து விஷயங்கள் - -CARDINAL ௨ மருந்துகள் இரண்டு மருந்துகள் - -CARDINAL ௩ கூடுகள் மூன்று கூடுகள் - -CARDINAL ௪ தோழிகள் நான்கு தோழிகள் - -CARDINAL ௫ செடிகள் ஐந்து செடிகள் - -CARDINAL ௬ திரைகள் ஆறு திரைகள் - -CARDINAL ௭ பூனைகள் ஏழு பூனைகள் - -CARDINAL ௮ எலிகள் எட்டு எலிகள் - -CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் - -CARDINAL ௧௦ கண்கள் பத்து கண்கள் - -CARDINAL ௬ சுவர்கள் ஆறு சுவர்கள் - -CARDINAL ௨ கடிகாரங்கள் இரண்டு கடிகாரங்கள் - -CARDINAL ௩ பப்பாளிப்பழங்கள் மூன்று பப்பாளிப்பழங்கள் - -CARDINAL ௪ மிதிவண்டிகள் நான்கு மிதிவண்டிகள் - -CARDINAL ௫ ஜன்னல்கள் ஐந்து ஜன்னல்கள் - -CARDINAL ௬ கிளைகள் ஆறு கிளைகள் - -CARDINAL ௭ பொம்மைகள் ஏழு பொம்மைகள் - -CARDINAL ௮ கவிதைகள் எட்டு கவிதைகள் - -CARDINAL ௯ கதைகள் ஒன்பது கதைகள் - -CARDINAL ௧௦ கதைகள் பத்து கதைகள் - -CARDINAL ௭ மொட்டுகள் ஏழு மொட்டுகள் - -CARDINAL ௨ கோழிகள் இரண்டு கோழிகள் - -CARDINAL ௩ தெருக்கள் மூன்று தெருக்கள் - -CARDINAL ௪ தேதிகள் நான்கு தேதிகள் - -CARDINAL ௫ கருவிகள் ஐந்து கருவிகள் - -CARDINAL ௬ கன்னியர்கள் ஆறு கன்னியர்கள் - -CARDINAL ௭ தட்டுகள் ஏழு தட்டுகள் - -CARDINAL ௮ பெண்கள் எட்டு பெண்கள் - -CARDINAL ௯ இரவுகள் ஒன்பது இரவுகள் - -CARDINAL ௧௦ காய்கறிகள் பத்து காய்கறிகள் - -CARDINAL ௮ குழந்தைகள் எட்டு குழந்தைகள் - -CARDINAL ௨ தொப்பிகள் இரண்டு தொப்பிகள் - -CARDINAL ௩ சிறுமிகள் மூன்று சிறுமிகள் - -CARDINAL ௪ நதிகள் நான்கு நதிகள் - -CARDINAL ௫ பெண்கள் ஐந்து பெண்கள் - -CARDINAL ௬ பொட்டுகள் ஆறு பொட்டுகள் - -CARDINAL ௭ பெட்டிகள் ஏழு பெட்டிகள் - -CARDINAL ௯ பொம்மைகள் ஒன்பது பொம்மைகள் - -CARDINAL ௧௦ கதைகள் பத்து கதைகள் - -CARDINAL ௯ இதழ்கள் ஒன்பது இதழ்கள் - -CARDINAL ௨ கொடிகள் இரண்டு கொடிகள் - -CARDINAL ௩ கவிதைகள் மூன்று கவிதைகள் - -CARDINAL ௪ ஏரிகள் நான்கு ஏரிகள் - -CARDINAL ௫ செருப்புகள் ஐந்து செருப்புகள் - -CARDINAL ௬ பசுக்கள் ஆறு பசுக்கள் - -CARDINAL ௭ சாலைகள் ஏழு சாலைகள் - -CARDINAL ௮ கண்கள் எட்டு கண்கள் - -CARDINAL ௧௦ பேச்சுகள் பத்து பேச்சுகள் - -CARDINAL ௧௦௧ நூற்று ஒன்று - -CARDINAL ௧௦௨ நூற்று இரண்டு - -CARDINAL ௧௦௩ நூற்று மூன்று - -CARDINAL ௧௦௪ நூற்று நான்கு - -CARDINAL ௧௦௫ நூற்று ஐந்து - -CARDINAL ௧௦௬ நூற்று ஆறு - -CARDINAL ௧௦௭ நூற்று ஏழு - -CARDINAL ௧௦௮ நூற்று எட்டு - -CARDINAL ௧௦௯ நூற்று ஒன்பது - -CARDINAL ௧௧௦ நூற்று பத்து - -CARDINAL ௧௧௧ நூற்று பதினொன்று - -CARDINAL ௧௧௨ நூற்று பன்னிரண்டு - -CARDINAL ௧௧௩ நூற்று பதிமூன்று - -CARDINAL ௧௧௪ நூற்று பதினான்கு - -CARDINAL ௧௧௫ நூற்று பதினைந்து - -CARDINAL ௧௧௬ நூற்று பதினாறு - -CARDINAL ௮௧௭ எட்டுநூற்று பதினேழு - -CARDINAL ௮௧௮ எட்டுநூற்று பதினெட்டு - -CARDINAL ௮௧௯ எட்டுநூற்று பத்தொன்பது - -CARDINAL ௮௨௦ எட்டுநூற்று இருபது - -CARDINAL ௮௨௧ எட்டுநூற்று இருபத்து ஒன்று - -CARDINAL ௮௨௨ எட்டுநூற்று இருபத்து இரண்டு - -CARDINAL ௮௨௩ எட்டுநூற்று இருபத்து மூன்று - -CARDINAL ௮௨௪ எட்டுநூற்று இருபத்து நான்கு - -CARDINAL ௮௨௫ எட்டுநூற்று இருபத்து ஐந்து - -CARDINAL ௮௨௬ எட்டுநூற்று இருபத்து ஆறு - -CARDINAL ௮௨௭ எட்டுநூற்று இருபத்து ஏழு - -CARDINAL ௮௨௮ எட்டுநூற்று இருபத்து எட்டு - -CARDINAL ௮௨௯ எட்டுநூற்று இருபத்து ஒன்பது - -CARDINAL ௮௩௦ எட்டுநூற்று முப்பது - -CARDINAL ௮௩௧ எட்டுநூற்று முப்பத்து ஒன்று - -CARDINAL ௮௩௨ எட்டுநூற்று முப்பத்து இரண்டு - -CARDINAL ௮௩௩ எட்டுநூற்று முப்பத்து மூன்று - -CARDINAL ௮௩௪ எட்டுநூற்று முப்பத்து நான்கு - -CARDINAL ௮௩௫ எட்டுநூற்று முப்பத்து ஐந்து - -CARDINAL ௮௩௬ எட்டுநூற்று முப்பத்து ஆறு - -CARDINAL ௭௩௮ எழுநூற்று முப்பத்து எட்டு - -CARDINAL ௭௩௯ எழுநூற்று முப்பத்து ஒன்பது - -CARDINAL ௭௪௦ எழுநூற்று நாற்பது - -CARDINAL ௭௪௧ எழுநூற்று நாற்பத்து ஒன்று - -CARDINAL ௭௪௨ எழுநூற்று நாற்பத்து இரண்டு - -CARDINAL ௭௪௩ எழுநூற்று நாற்பத்து மூன்று - -CARDINAL ௭௪௪ எழுநூற்று நாற்பத்து நான்கு - -CARDINAL ௭௪௫ எழுநூற்று நாற்பத்து ஐந்து - -CARDINAL ௪௪௬ நானூற்று நாற்பத்து ஆறு - -CARDINAL ௪௪௭ நானூற்று நாற்பத்து ஏழு - -CARDINAL ௪௪௮ நானூற்று நாற்பத்து எட்டு - -CARDINAL ௪௪௯ நானூற்று நாற்பத்து ஒன்பது - -CARDINAL ௪௫௦ நானூற்று ஐம்பது - -CARDINAL ௪௬௧ நானூற்று அறுபத்து ஒன்று - -CARDINAL ௧௭௫ நூற்று எழுபத்து ஐந்து - -CARDINAL ௧௮௧ நூற்று எண்பத்து ஒன்று - -CARDINAL ௧௯௦ நூற்று தொண்ணூறு - -CARDINAL ௧௯௯ நூற்று தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௧ ஆயிரத்து ஒன்று - -CARDINAL ௧௦௦௨ ஆயிரத்து இரண்டு - -CARDINAL ௧௦௦௩ ஆயிரத்து மூன்று - -CARDINAL ௧௦௦௪ ஆயிரத்து நான்கு - -CARDINAL ௧௦௦௫ ஆயிரத்து ஐந்து - -CARDINAL ௧௦௦௬ ஆயிரத்து ஆறு - -CARDINAL ௧௦௦௭ ஆயிரத்து ஏழு - -CARDINAL ௧௦௦௮ ஆயிரத்து எட்டு - -CARDINAL ௧௦௦௯ ஆயிரத்து ஒன்பது - -CARDINAL ௧௦௧௦ ஆயிரத்து பத்து - -CARDINAL ௧௦௧௧ ஆயிரத்து பதினொன்று - -CARDINAL ௧௦௧௨ ஆயிரத்து பன்னிரண்டு - -CARDINAL ௧௦௧௩ ஆயிரத்து பதிமூன்று - -CARDINAL ௧௦௧௪ ஆயிரத்து பதினான்கு - -CARDINAL ௧௦௧௫ ஆயிரத்து பதினைந்து - -CARDINAL ௧௦௧௬ ஆயிரத்து பதினாறு - -CARDINAL ௧௦௧௭ ஆயிரத்து பதினேழு - -CARDINAL ௧௦௧௮ ஆயிரத்து பதினெட்டு - -CARDINAL ௧௦௧௯ ஆயிரத்து பத்தொன்பது - -CARDINAL ௧௦௨௦ ஆயிரத்து இருபது - -CARDINAL ௧௦௨௧ ஆயிரத்து இருபத்து ஒன்று - -CARDINAL ௧௦௨௨ ஆயிரத்து இருபத்து இரண்டு - -CARDINAL ௧௧௨௩ ஆயிரத்து நூற்று இருபத்து மூன்று - -CARDINAL ௧௪௨௪ ஆயிரத்து நானூற்று இருபத்து நான்கு - -CARDINAL ௧௫௨௫ ஆயிரத்து ஐந்நூற்று இருபத்து ஐந்து - -CARDINAL ௧௩௨௬ ஆயிரத்து முந்நூற்று இருபத்து ஆறு - -CARDINAL ௧௪௨௭ ஆயிரத்து நானூற்று இருபத்து ஏழு - -CARDINAL ௧௬௨௮ ஆயிரத்து அறுநூற்று இருபத்து எட்டு - -CARDINAL ௧௭௨௯ ஆயிரத்து எழுநூற்று இருபத்து ஒன்பது - -CARDINAL ௧௮௩௦ ஆயிரத்து எட்டுநூற்று முப்பது - -CARDINAL ௧௧௩௧ ஆயிரத்து நூற்று முப்பத்து ஒன்று - -CARDINAL ௧௨௩௨ ஆயிரத்து இருநூற்று முப்பத்து இரண்டு - -CARDINAL ௧௩௩௩ ஆயிரத்து முந்நூற்று முப்பத்து மூன்று - -CARDINAL ௧௪௩௪ ஆயிரத்து நானூற்று முப்பத்து நான்கு - -CARDINAL ௧௫௩௫ ஆயிரத்து ஐந்நூற்று முப்பத்து ஐந்து - -CARDINAL ௧௬௩௬ ஆயிரத்து அறுநூற்று முப்பத்து ஆறு - -CARDINAL ௧௭௩௭ ஆயிரத்து எழுநூற்று முப்பத்து ஏழு - -CARDINAL ௧௮௩௮ ஆயிரத்து எட்டுநூற்று முப்பத்து எட்டு - -CARDINAL ௧௯௩௯ ஆயிரத்து ஒன்பதுநூற்று முப்பத்து ஒன்பது - -CARDINAL ௧௦௪௦ ஆயிரத்து நாற்பது - -CARDINAL ௧௦௪௧ ஆயிரத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௪௨ ஆயிரத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௪௩ ஆயிரத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௪௪ ஆயிரத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௪௫ ஆயிரத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௪௬ ஆயிரத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௪௭ ஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௪௮ ஆயிரத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௪௯ ஆயிரத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௫௦ ஆயிரத்து ஐம்பது - -CARDINAL ௧௦௬௧ ஆயிரத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௭௫ ஆயிரத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௮௧ ஆயிரத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௯௦ ஆயிரத்து தொண்ணூறு - -CARDINAL ௧௦௯௯ ஆயிரத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௧ பத்துஆயிரத்து ஒன்று - -CARDINAL ௧௦௦௦௨ பத்துஆயிரத்து இரண்டு - -CARDINAL ௧௦௨௦௩ பத்துஆயிரத்து இருநூற்று மூன்று - -CARDINAL ௧௦௩௦௪ பத்துஆயிரத்து முந்நூற்று நான்கு - -CARDINAL ௧௧௩௦௫ பதினொன்றுஆயிரத்து முந்நூற்று ஐந்து - -CARDINAL ௧௨௪௫௬ பன்னிரண்டுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௧௩௦௪௭ பதிமூன்றுஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௮ பத்துஆயிரத்து எட்டு - -CARDINAL ௧௦௦௦௯ பத்துஆயிரத்து ஒன்பது - -CARDINAL ௧௦௦௧௦ பத்துஆயிரத்து பத்து - -CARDINAL ௧௦௦௧௧ பத்துஆயிரத்து பதினொன்று - -CARDINAL ௧௦௦௧௨ பத்துஆயிரத்து பன்னிரண்டு - -CARDINAL ௧௦௦௧௩ பத்துஆயிரத்து பதிமூன்று - -CARDINAL ௧௦௦௧௪ பத்துஆயிரத்து பதினான்கு - -CARDINAL ௧௦௦௧௫ பத்துஆயிரத்து பதினைந்து - -CARDINAL ௧௦௦௧௬ பத்துஆயிரத்து பதினாறு - -CARDINAL ௧௦௦௧௭ பத்துஆயிரத்து பதினேழு - -CARDINAL ௧௦௦௧௮ பத்துஆயிரத்து பதினெட்டு - -CARDINAL ௧௦௦௧௯ பத்துஆயிரத்து பத்தொன்பது - -CARDINAL ௧௦௦௨௦ பத்துஆயிரத்து இருபது - -CARDINAL ௧௦௦௨௧ பத்துஆயிரத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௨௨ பத்துஆயிரத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௨௩ பத்துஆயிரத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௨௪ பத்துஆயிரத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௨௫ பத்துஆயிரத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௨௬ பத்துஆயிரத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௨௭ பத்துஆயிரத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௨௮ பத்துஆயிரத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௨௯ பத்துஆயிரத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௩௦ பத்துஆயிரத்து முப்பது - -CARDINAL ௧௦௦௩௧ பத்துஆயிரத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௩௨ பத்துஆயிரத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௩௩ பத்துஆயிரத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௩௪ பத்துஆயிரத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௩௫ பத்துஆயிரத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௩௬ பத்துஆயிரத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௩௭ பத்துஆயிரத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௩௮ பத்துஆயிரத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௩௯ பத்துஆயிரத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௪௦ பத்துஆயிரத்து நாற்பது - -CARDINAL ௧௦௦௪௧ பத்துஆயிரத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௪௨ பத்துஆயிரத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௪௩ பத்துஆயிரத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௪௪ பத்துஆயிரத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௪௫ பத்துஆயிரத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௪௬ பத்துஆயிரத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௪௭ பத்துஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௪௮ பத்துஆயிரத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௪௯ பத்துஆயிரத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௫௦ பத்துஆயிரத்து ஐம்பது - -CARDINAL ௧௦௦௬௧ பத்துஆயிரத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௭௫ பத்துஆயிரத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௮௧ பத்துஆயிரத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௯௦ பத்துஆயிரத்து தொண்ணூறு - -CARDINAL ௧௦௦௯௯ பத்துஆயிரத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௧ ஒன்று இலட்சத்து ஒன்று - -CARDINAL ௧௧௦௦௦௨ ஒன்று இலட்சத்து பத்துஆயிரத்து இரண்டு - -CARDINAL ௧௨௦௪௦௩ ஒன்று இலட்சத்து இருபதுஆயிரத்து நானூற்று மூன்று - -CARDINAL ௧௪௧௫௦௪ ஒன்று இலட்சத்து நாற்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று நான்கு - -CARDINAL ௧௫௧௫௧௫ ஒன்று இலட்சத்து ஐம்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று பதினைந்து - -CARDINAL ௧௦௦௦௦௬ ஒன்று இலட்சத்து ஆறு - -CARDINAL ௧௦௦௦௦௭ ஒன்று இலட்சத்து ஏழு - -CARDINAL ௧௦௦௦௦௮ ஒன்று இலட்சத்து எட்டு - -CARDINAL ௧௦௦௦௦௯ ஒன்று இலட்சத்து ஒன்பது - -CARDINAL ௧௦௦௦௧௦ ஒன்று இலட்சத்து பத்து - -CARDINAL ௧௦௦௦௧௧ ஒன்று இலட்சத்து பதினொன்று - -CARDINAL ௧௦௦௦௧௨ ஒன்று இலட்சத்து பன்னிரண்டு - -CARDINAL ௧௦௦௦௧௩ ஒன்று இலட்சத்து பதிமூன்று - -CARDINAL ௧௦௦௦௧௪ ஒன்று இலட்சத்து பதினான்கு - -CARDINAL ௧௦௦௦௧௫ ஒன்று இலட்சத்து பதினைந்து - -CARDINAL ௧௦௦௦௧௬ ஒன்று இலட்சத்து பதினாறு - -CARDINAL ௧௦௦௦௧௭ ஒன்று இலட்சத்து பதினேழு - -CARDINAL ௧௦௦௦௧௮ ஒன்று இலட்சத்து பதினெட்டு - -CARDINAL ௧௦௦௦௧௯ ஒன்று இலட்சத்து பத்தொன்பது - -CARDINAL ௧௦௦௦௨௦ ஒன்று இலட்சத்து இருபது - -CARDINAL ௧௦௦௦௨௧ ஒன்று இலட்சத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௨௨ ஒன்று இலட்சத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௨௩ ஒன்று இலட்சத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௦௨௪ ஒன்று இலட்சத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௦௨௫ ஒன்று இலட்சத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௨௬ ஒன்று இலட்சத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௦௨௭ ஒன்று இலட்சத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௦௨௮ ஒன்று இலட்சத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௦௨௯ ஒன்று இலட்சத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௩௦ ஒன்று இலட்சத்து முப்பது - -CARDINAL ௧௦௦௦௩௧ ஒன்று இலட்சத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௩௨ ஒன்று இலட்சத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௩௩ ஒன்று இலட்சத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௩௪ ஒன்று இலட்சத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௩௫ ஒன்று இலட்சத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௩௬ ஒன்று இலட்சத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௩௭ ஒன்று இலட்சத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௩௮ ஒன்று இலட்சத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௩௯ ஒன்று இலட்சத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௪௦ ஒன்று இலட்சத்து நாற்பது - -CARDINAL ௧௦௦௦௪௧ ஒன்று இலட்சத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௪௨ ஒன்று இலட்சத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௪௩ ஒன்று இலட்சத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௪௪ ஒன்று இலட்சத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௪௫ ஒன்று இலட்சத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௪௬ ஒன்று இலட்சத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௪௭ ஒன்று இலட்சத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௪௮ ஒன்று இலட்சத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௪௯ ஒன்று இலட்சத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௫௦ ஒன்று இலட்சத்து ஐம்பது - -CARDINAL ௧௦௦௦௬௧ ஒன்று இலட்சத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௭௫ ஒன்று இலட்சத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௮௧ ஒன்று இலட்சத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௯௦ ஒன்று இலட்சத்து தொண்ணூறு - -CARDINAL ௧௦௦௦௯௯ ஒன்று இலட்சத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௦௧ பத்து இலட்சத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௨ பத்து இலட்சத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௩ பத்து இலட்சத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௪ பத்து இலட்சத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௫ பத்து இலட்சத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௬ பத்து இலட்சத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௭ பத்து இலட்சத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௮ பத்து இலட்சத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௯ பத்து இலட்சத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௧௦ பத்து இலட்சத்து பத்து - -CARDINAL ௧௦௦௦௦௧௧ பத்து இலட்சத்து பதினொன்று - -CARDINAL ௧௦௦௦௦௧௨ பத்து இலட்சத்து பன்னிரண்டு - -CARDINAL ௧௦௦௦௦௧௩ பத்து இலட்சத்து பதிமூன்று - -CARDINAL ௧௦௦௦௦௧௪ பத்து இலட்சத்து பதினான்கு - -CARDINAL ௧௦௦௦௦௧௫ பத்து இலட்சத்து பதினைந்து - -CARDINAL ௧௦௦௦௦௧௬ பத்து இலட்சத்து பதினாறு - -CARDINAL ௧௦௦௦௦௧௭ பத்து இலட்சத்து பதினேழு - -CARDINAL ௧௦௦௦௦௧௮ பத்து இலட்சத்து பதினெட்டு - -CARDINAL ௧௦௦௦௦௧௯ பத்து இலட்சத்து பத்தொன்பது - -CARDINAL ௧௦௦௦௦௨௦ பத்து இலட்சத்து இருபது - -CARDINAL ௧௦௦௦௦௨௧ பத்து இலட்சத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௨௨ பத்து இலட்சத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௦௨௩ பத்து இலட்சத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௦௦௨௪ பத்து இலட்சத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௦௦௨௫ பத்து இலட்சத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௨௬ பத்து இலட்சத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௦௦௨௭ பத்து இலட்சத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௦௦௨௮ பத்து இலட்சத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௦௦௨௯ பத்து இலட்சத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௩௦ பத்து இலட்சத்து முப்பது - -CARDINAL ௧௦௦௦௦௩௧ பத்து இலட்சத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௩௨ பத்து இலட்சத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௩௩ பத்து இலட்சத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௩௪ பத்து இலட்சத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௩௫ பத்து இலட்சத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௩௬ பத்து இலட்சத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௩௭ பத்து இலட்சத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௩௮ பத்து இலட்சத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௩௯ பத்து இலட்சத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௪௦ பத்து இலட்சத்து நாற்பது - -CARDINAL ௧௦௦௦௦௪௧ பத்து இலட்சத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௪௨ பத்து இலட்சத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௪௩ பத்து இலட்சத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௪௪ பத்து இலட்சத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௪௫ பத்து இலட்சத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௪௬ பத்து இலட்சத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௪௭ பத்து இலட்சத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௪௮ பத்து இலட்சத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௪௯ பத்து இலட்சத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௫௦ பத்து இலட்சத்து ஐம்பது - -CARDINAL ௧௦௦௦௦௬௧ பத்து இலட்சத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௭௫ பத்து இலட்சத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௮௧ பத்து இலட்சத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௯௦ பத்து இலட்சத்து தொண்ணூறு - -CARDINAL ௧௦௦௦௦௯௯ பத்து இலட்சத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௦௦௧ ஒன்று கோடியே ஒன்று - -CARDINAL ௧௦௦௦௦௦௦௨ ஒன்று கோடியே இரண்டு - -CARDINAL ௧௦௦௦௦௦௦௩ ஒன்று கோடியே மூன்று - -CARDINAL ௧௦௦௦௦௦௦௪ ஒன்று கோடியே நான்கு - -CARDINAL ௧௦௦௦௦௦௦௫ ஒன்று கோடியே ஐந்து - -CARDINAL ௧௦௦௦௦௦௦௬ ஒன்று கோடியே ஆறு - -CARDINAL ௧௦௦௦௦௦௦௭ ஒன்று கோடியே ஏழு - -CARDINAL ௧௦௦௦௦௦௦௮ ஒன்று கோடியே எட்டு - -CARDINAL ௧௦௦௦௦௦௦௯ ஒன்று கோடியே ஒன்பது - -CARDINAL ௧௦௦௦௦௦௧௦ ஒன்று கோடியே பத்து - -CARDINAL ௧௦௦௦௦௦௧௧ ஒன்று கோடியே பதினொன்று - -CARDINAL ௧௦௦௦௦௦௧௨ ஒன்று கோடியே பன்னிரண்டு - -CARDINAL ௧௦௦௦௦௦௧௩ ஒன்று கோடியே பதிமூன்று - -CARDINAL ௧௦௦௦௦௦௧௪ ஒன்று கோடியே பதினான்கு - -CARDINAL ௧௦௦௦௦௦௧௫ ஒன்று கோடியே பதினைந்து - -CARDINAL ௧௦௦௦௦௦௧௬ ஒன்று கோடியே பதினாறு - -CARDINAL ௧௦௦௦௦௦௧௭ ஒன்று கோடியே பதினேழு - -CARDINAL ௧௦௦௦௦௦௧௮ ஒன்று கோடியே பதினெட்டு - -CARDINAL ௧௦௦௦௦௦௧௯ ஒன்று கோடியே பத்தொன்பது - -CARDINAL ௧௦௦௦௦௦௨௦ ஒன்று கோடியே இருபது - -CARDINAL ௧௦௦௦௦௦௨௧ ஒன்று கோடியே இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௨௨ ஒன்று கோடியே இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௨௩ ஒன்று கோடியே இருபத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௨௪ ஒன்று கோடியே இருபத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௨௫ ஒன்று கோடியே இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௨௬ ஒன்று கோடியே இருபத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௨௭ ஒன்று கோடியே இருபத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௨௮ ஒன்று கோடியே இருபத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௨௯ ஒன்று கோடியே இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௩௦ ஒன்று கோடியே முப்பது - -CARDINAL ௧௦௦௦௦௦௩௧ ஒன்று கோடியே முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௩௨ ஒன்று கோடியே முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௩௩ ஒன்று கோடியே முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௩௪ ஒன்று கோடியே முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௩௫ ஒன்று கோடியே முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௩௬ ஒன்று கோடியே முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௩௭ ஒன்று கோடியே முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௩௮ ஒன்று கோடியே முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௩௯ ஒன்று கோடியே முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௪௦ ஒன்று கோடியே நாற்பது - -CARDINAL ௧௦௦௦௦௦௪௧ ஒன்று கோடியே நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௪௨ ஒன்று கோடியே நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௪௩ ஒன்று கோடியே நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௪௪ ஒன்று கோடியே நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௪௫ ஒன்று கோடியே நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௪௬ ஒன்று கோடியே நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௪௭ ஒன்று கோடியே நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௪௮ ஒன்று கோடியே நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௪௯ ஒன்று கோடியே நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௫௦ ஒன்று கோடியே ஐம்பது - -CARDINAL ௧௦௦௦௦௦௬௧ ஒன்று கோடியே அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௭௫ ஒன்று கோடியே எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௮௧ ஒன்று கோடியே எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௯௦ ஒன்று கோடியே தொண்ணூறு - -CARDINAL ௧௦௦௦௦௦௯௯ ஒன்று கோடியே தொண்ணூற்று ஒன்பது - -CARDINAL ௧௩௨௩ ஆயிரத்து முந்நூற்று இருபத்து மூன்று - -CARDINAL ௧௩௪௫ ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து - -CARDINAL ௧௩௪௫௬ பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௧௨௩௪௬ பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு - -CARDINAL ௧௨௩௪௫௬ ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௮௭௨௯௮௭ எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு - -CARDINAL ௯௮௭௬௦௯ ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது - -CARDINAL ௯௮௭௬௭௮௯ தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது - -CARDINAL ௨௩௪௫௫௬௭ இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௨௩௪௫௫௬௭ ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௨௧௨௧௨௧௨௨ பன்னிரண்டு கோடியே பன்னிரண்டு இலட்சத்து பன்னிரண்டுஆயிரத்து நூற்று இருபத்து இரண்டு - -CARDINAL ௧௦௦௨௩௪௫௫௬௭ ஒன்று அரபு இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௧௨௨௩௪௫௫௬௭ ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௦௨௨௩௪௫௫௬௭ ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௧௦௨௨௩௪௫௫௬௭ பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௫௧௦௨௨௩௪௫௫௬௭ ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - From 5a39cebb333dc19ca970ffc0f0ff4e717b0510af Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 12:43:27 +0530 Subject: [PATCH 08/29] Updated cardinal Signed-off-by: surendran-246 --- blind_testcases_ta | 1398 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1398 insertions(+) create mode 100644 blind_testcases_ta diff --git a/blind_testcases_ta b/blind_testcases_ta new file mode 100644 index 000000000..4a2911adf --- /dev/null +++ b/blind_testcases_ta @@ -0,0 +1,1398 @@ +CARDINAL ௪ சிக்ஸர்கள் ௧௪ பவுண்டரிகள் நான்கு சிக்ஸர்கள் பதினான்கு பவுண்டரிகள் + +CARDINAL ௬ ரன்கள் எடுத்தார் ஆறு ரன்கள் எடுத்தார் + +CARDINAL ௩ கோல்கள் அடித்தார் மூன்று கோல்கள் அடித்தார் + +CARDINAL ௯ சிக்ஸர்கள் ஒன்பது சிக்ஸர்கள் + +CARDINAL ௫ பவுண்டரிகள் ஐந்து பவுண்டரிகள் + +CARDINAL ௨ சிக்ஸர்கள் ௧௨ ரன்கள் இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் + +CARDINAL ௯ புள்ளிகள் ஒன்பது புள்ளிகள் + +CARDINAL ௪ பேர் உயிரிழப்பு ௧௮ பேர் காயம் நான்கு பேர் உயிரிழப்பு பதினெட்டு பேர் காயம் + +CARDINAL ௫ கோல்கள் அடித்தனர் ஐந்து கோல்கள் அடித்தனர் + +CARDINAL ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள் மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் + +CARDINAL ௧ ஓவர் ௧௩ ரன்கள் ஒன்று ஓவர் பதிமூன்று ரன்கள் + +CARDINAL ௩ ஓவர்கள் மூன்று ஓவர்கள் + +CARDINAL ௫ கோல்கள் ஐந்து கோல்கள் + +CARDINAL ௩ ஆப்பிள்கள் மூன்று ஆப்பிள்கள் + +CARDINAL ௭ வாழைப்பழங்கள் ஏழு வாழைப்பழங்கள் + +CARDINAL ௩ தோல்வி ௧௨ வெற்றி மூன்று தோல்வி பன்னிரண்டு வெற்றி + +CARDINAL ௫ தோல்விகள் ௧ டிரா ௧௭ வெற்றிகள் ஐந்து தோல்விகள் ஒன்று டிரா பதினேழு வெற்றிகள் + +CARDINAL ௮ போட்டிகள் டிரா எட்டு போட்டிகள் டிரா + +CARDINAL ௪ பவுண்டரிகள் நான்கு பவுண்டரிகள் + +CARDINAL ௮ சிக்ஸர்கள் ௨ அவுட் எட்டு சிக்ஸர்கள் இரண்டு அவுட் + +CARDINAL ௬ வீரர்கள் அவுட் ஆறு வீரர்கள் அவுட் + +CARDINAL ௪ ரன்கள் ௩ பவுண்டரிகள் நான்கு ரன்கள் மூன்று பவுண்டரிகள் + +CARDINAL ஒன்பிளஸ் ௮ ப்ரோ ஒன்பிளஸ் எட்டு ப்ரோ + +CARDINAL ௫ சார்ஜர்கள் ஐந்து சார்ஜர்கள் + +CARDINAL ௪ ஓவரில் ௧௭ ரன்கள் நான்கு ஓவரில் பதினேழு ரன்கள் + +CARDINAL ௫ சாக்லேட்டுகள் ௯ டாபிகள் ஐந்து சாக்லேட்டுகள் ஒன்பது டாபிகள் + +CARDINAL ௬ பேட்ஸ்மேன்கள் ௨ பவுலர்கள் ஆறு பேட்ஸ்மேன்கள் இரண்டு பவுலர்கள் + +CARDINAL ௧ விக்கெட் கீப்பர் ஒன்று விக்கெட் கீப்பர் + +CARDINAL ௮ கேட்ச் அவுட் எட்டு கேட்ச் அவுட் + +CARDINAL ௫ விக்கெட்டுக்கு ௧௦ ரன்கள் ஐந்து விக்கெட்டுக்கு பத்து ரன்கள் + +CARDINAL ௭ வெற்றி ௨ டிரா ஏழு வெற்றி இரண்டு டிரா + +CARDINAL ௨ பவுண்டரிகள் இரண்டு பவுண்டரிகள் + +CARDINAL ௬ ரன்கள் ௫ விக்கெட்டுகள் ஆறு ரன்கள் ஐந்து விக்கெட்டுகள் + +CARDINAL ௭ பந்துகள் ௧௧ ரன்கள் ஏழு பந்துகள் பதினொன்று ரன்கள் + +CARDINAL ௬ சாக்லேட்டுகள் ௪ டாபிகள் ஆறு சாக்லேட்டுகள் நான்கு டாபிகள் + +CARDINAL ௮ வெண்கலங்கள் ௨ தங்கங்கள் எட்டு வெண்கலங்கள் இரண்டு தங்கங்கள் + +CARDINAL ௧ தங்கப் பதக்கம் ஒன்று தங்கப் பதக்கம் + +CARDINAL ௩ ரன்கள் மூன்று ரன்கள் + +CARDINAL ௫ ஓவர்கள் ஐந்து ஓவர்கள் + +CARDINAL ௬ பந்து ஆறு பந்து + +CARDINAL ௩ இன்னிங்ஸ் மூன்று இன்னிங்ஸ் + +CARDINAL வசனம் ௭ பாடம் ௧௫ வசனம் ஏழு பாடம் பதினைந்து + +CARDINAL பாடம் எண் ௨ வசனம் ௪ பாடம் எண் இரண்டு வசனம் நான்கு + +CARDINAL பக்க எண் ௮ பத்தி ௬ பக்க எண் எட்டு பத்தி ஆறு + +CARDINAL ௨ பந்துகள் ௪ ரன்கள் இரண்டு பந்துகள் நான்கு ரன்கள் + +CARDINAL ௬ விக்கெட்டுகள் ஆறு விக்கெட்டுகள் + +CARDINAL ௨ புள்ளி ௫ கோல்கள் இரண்டு புள்ளி ஐந்து கோல்கள் + +CARDINAL பாடம் ௧௦ ஸ்லோகம் ௨ பாடம் பத்து ஸ்லோகம் இரண்டு + +CARDINAL அத்தியாயம் ௫ காட்சி ௬ அத்தியாயம் ஐந்து காட்சி ஆறு + +CARDINAL ௬ கேள்விகள் ௫ தவறு ஆறு கேள்விகள் ஐந்து தவறு + +CARDINAL ௩ ரோஜா ௪ மல்லிகை ௨ சாமந்தி மூன்று ரோஜா நான்கு மல்லிகை இரண்டு சாமந்தி + +CARDINAL ௨ ஃப்ரீ ஹிட் ௧ நோ பால் இரண்டு ஃப்ரீ ஹிட் ஒன்று நோ பால் + +CARDINAL ௩ போன் ௧ சார்ஜர் மூன்று போன் ஒன்று சார்ஜர் + +CARDINAL ௬ டிரா ௭ தோல்வி ௯ வெற்றி ஆறு டிரா ஏழு தோல்வி ஒன்பது வெற்றி + +CARDINAL ௪ கார் ௨ பைக் நான்கு கார் இரண்டு பைக் + +CARDINAL ௧ கூடை ௮ பழம் ஒன்று கூடை எட்டு பழம் + +CARDINAL ௩ வரிசை ௮ நபர் மூன்று வரிசை எட்டு நபர் + +CARDINAL ௧௦ பென்சில் ௨ பேனா பத்து பென்சில் இரண்டு பேனா + +CARDINAL ௫ கட்டிடம் ஐந்து கட்டிடம் + +CARDINAL ௬ குழந்தை ஆறு குழந்தை + +CARDINAL பத்தி ௧௩ வரிசை ௪ பத்தி பதிமூன்று வரிசை நான்கு + +CARDINAL ௩ தங்கம் ௪ வெள்ளி மூன்று தங்கம் நான்கு வெள்ளி + +CARDINAL ௫ குழிகள் ஐந்து குழிகள் + +CARDINAL ௮ குப்பம் எட்டு குப்பம் + +CARDINAL ௩ லேப்டாப் மூன்று லேப்டாப் + +CARDINAL ௧ சிக்ஸர் ௨ பவுண்டரிகள் ஒன்று சிக்ஸர் இரண்டு பவுண்டரிகள் + +CARDINAL ௫ பஸ் ஐந்து பஸ் + +CARDINAL ௨ லாரி இரண்டு லாரி + +CARDINAL ௩ வண்டி மூன்று வண்டி + +CARDINAL ௬ சுறா ௩௦ முதலீட்டாளர்கள் ஆறு சுறா முப்பது முதலீட்டாளர்கள் + +CARDINAL ௨ அமைச்சர் ௫௦ பிரச்சனைகள் இரண்டு அமைச்சர் ஐம்பது பிரச்சனைகள் + +CARDINAL ௬ பவுலர் ஆறு பவுலர் + +CARDINAL ஸ்லோகம் ௩ பாடம் ௧ ஸ்லோகம் மூன்று பாடம் ஒன்று + +CARDINAL வரிசை ௬ பத்தி ௯ வரிசை ஆறு பத்தி ஒன்பது + +CARDINAL புத்தகம் ௧ பாடம் ௮ புத்தகம் ஒன்று பாடம் எட்டு + +CARDINAL சிறுகதை எண் ௨ வரிசை ௬ சிறுகதை எண் இரண்டு வரிசை ஆறு + +CARDINAL கைதி எண் ௪ கைதி எண் நான்கு + +CARDINAL பக்க எண் ௧௦ வரிசை ௨ பக்க எண் பத்து வரிசை இரண்டு + +CARDINAL ௪ மருத்துவர் நான்கு மருத்துவர் + +CARDINAL ௨ பந்து ௩ ரன் இரண்டு பந்து மூன்று ரன் + +CARDINAL புள்ளிகள் ௨ கோல் ௪ புள்ளிகள் இரண்டு கோல் நான்கு + +CARDINAL பாடம் எண் ௪ பாடம் எண் நான்கு + +CARDINAL ௮ ஓவர் எட்டு ஓவர் + +CARDINAL ௭ ரன் ௨ ஓவர் ஏழு ரன் இரண்டு ஓவர் + +CARDINAL ௪ பந்து ௮ ரன் நான்கு பந்து எட்டு ரன் + +CARDINAL ௩ பாட்டில் ௫ கிளாஸ் மூன்று பாட்டில் ஐந்து கிளாஸ் + +CARDINAL ௬ ரன் ஆறு ரன் + +CARDINAL ௬ கோல் ஆறு கோல் + +CARDINAL ௧௦ புள்ளிகள் ௩ கோல் பத்து புள்ளிகள் மூன்று கோல் + +CARDINAL ௧௪ சிக்ஸர் ௩ பவுண்டரி பதினான்கு சிக்ஸர் மூன்று பவுண்டரி + +CARDINAL ௬ ஆப்பிள் ௩ வாழைப்பழம் ஆறு ஆப்பிள் மூன்று வாழைப்பழம் + +CARDINAL ௩ மேட்ச் டிரா மூன்று மேட்ச் டிரா + +CARDINAL ௬ மேட்ச் தோல்வி ஆறு மேட்ச் தோல்வி + +CARDINAL ௯ மேட்ச் வெற்றி ஒன்பது மேட்ச் வெற்றி + +CARDINAL ஸ்லோகம் ௬ பாடம் ௯ ஸ்லோகம் ஆறு பாடம் ஒன்பது + +CARDINAL பதம் ௪ வரிசை எண் ௩ பதம் நான்கு வரிசை எண் மூன்று + +CARDINAL பாடம் ௧௦ பக்கம் ௪ பாடம் பத்து பக்கம் நான்கு + +CARDINAL ௫ கார் ௨ மோட்டார் சைக்கிள் ஐந்து கார் இரண்டு மோட்டார் சைக்கிள் + +CARDINAL ௭ புள்ளிகள் ௨ கோல் ஏழு புள்ளிகள் இரண்டு கோல் + +CARDINAL ௪ இரவு ௩ பகல் நான்கு இரவு மூன்று பகல் + +CARDINAL ௧ ஆஸ் ௧ ராணி ௫ சீட்டுகள் ஒன்று ஆஸ் ஒன்று ராணி ஐந்து சீட்டுகள் + +CARDINAL வரிசை ௨ பத்தி ௧ வரிசை இரண்டு பத்தி ஒன்று + +CARDINAL ௫ ஜோடி காலணி ஐந்து ஜோடி காலணி + +CARDINAL ௧௦ ஓவரில் ௯ ரன் பத்து ஓவரில் ஒன்பது ரன் + +CARDINAL ௮ ரன் எட்டு ரன் + +CARDINAL ௪ சிக்ஸர்கள் ௧ ஃபோர் நான்கு சிக்ஸர்கள் ஒன்று ஃபோர் + +CARDINAL பக்க எண் ௯ இன் வரிசை ௪ பக்க எண் ஒன்பது இன் வரிசை நான்கு + +CARDINAL பாரா ௧௦ இன் பகுதி ௩ பாரா பத்து இன் பகுதி மூன்று + +CARDINAL ஆயத் ௪ ருகூ ௬ ஆயத் நான்கு ருகூ ஆறு + +CARDINAL பாரா ௯ ருகூ ௬ பாரா ஒன்பது ருகூ ஆறு + +CARDINAL ௮ கால்சட்டைகள் ௯ சட்டைகள் எட்டு கால்சட்டைகள் ஒன்பது சட்டைகள் + +CARDINAL ௪ ரொட்டி ௨ காய்கறி நான்கு ரொட்டி இரண்டு காய்கறி + +CARDINAL ௩ மேட்ச் ௪ வெற்றி மூன்று மேட்ச் நான்கு வெற்றி + +CARDINAL ௪ தோல்வி ௩ வெற்றி ௧ டிரா நான்கு தோல்வி மூன்று வெற்றி ஒன்று டிரா + +CARDINAL படம் ௧௯ பாடம் ௨ படம் பத்தொன்பது பாடம் இரண்டு + +CARDINAL பாடம் ௧ பக்கம் ௧௨௨ பாடம் ஒன்று பக்கம் நூற்று இருபத்து இரண்டு + +CARDINAL பாடம் ௩ வரிசை ௬ பாடம் மூன்று வரிசை ஆறு + +CARDINAL ஸ்லோகம் ௧௦ பக்கம் ௩ ஸ்லோகம் பத்து பக்கம் மூன்று + +CARDINAL ௬ புள்ளிகள் ௩ கோல் ஆறு புள்ளிகள் மூன்று கோல் + +CARDINAL ௨ டெஸ்ட் போட்டிகள் ௬ ஒன்றுநாள் போட்டிகள் இரண்டு டெஸ்ட் போட்டிகள் ஆறு ஒன்றுநாள் போட்டிகள் + +CARDINAL ௨ ஓவரில் ௭ ரன் இரண்டு ஓவரில் ஏழு ரன் + +CARDINAL ௮ ஓவரில் ௪௫ ரன் எட்டு ஓவரில் நாற்பத்து ஐந்து ரன் + +CARDINAL ௯ ஓவரில் ௬௦ ரன் ஒன்பது ஓவரில் அறுபது ரன் + +CARDINAL ௫ போட்டிகள் ௪ வெற்றிகள் ஐந்து போட்டிகள் நான்கு வெற்றிகள் + +CARDINAL ௨ வெற்றி ௪ தோல்வி ௫ டிரா இரண்டு வெற்றி நான்கு தோல்வி ஐந்து டிரா + +CARDINAL ஸ்லோகம் ௯ பக்கம் ௭ ஸ்லோகம் ஒன்பது பக்கம் ஏழு + +CARDINAL பாடம் ௨ பக்கம் ௬௬ பாடம் இரண்டு பக்கம் அறுபத்து ஆறு + +CARDINAL ௨ டயகிராம் ௧௩ பக்க எண் இரண்டு டயகிராம் பதிமூன்று பக்க எண் + +CARDINAL பட எண் ௮ பாடம் ௪ பட எண் எட்டு பாடம் நான்கு + +CARDINAL பக்க எண் ௧௦ பாடம் ௩ பக்க எண் பத்து பாடம் மூன்று + +CARDINAL ருகு ௩ ஆயத் ௮ ருகு மூன்று ஆயத் எட்டு + +CARDINAL ருகு ௪ ஆயத் ௬ வரி ௩௩ ருகு நான்கு ஆயத் ஆறு வரி முப்பத்து மூன்று + +CARDINAL பாரா ௨ ருகு ௭ வரி ௧௫ பாரா இரண்டு ருகு ஏழு வரி பதினைந்து + +CARDINAL ௩௦ பாரா வரி ௮ முப்பது பாரா வரி எட்டு + +CARDINAL ௪ சிக்ஸர்கள் ௧௨ ஃபோர்கள் நான்கு சிக்ஸர்கள் பன்னிரண்டு ஃபோர்கள் + +CARDINAL ௫ புள்ளிகள் ௭ கோல்கள் ஐந்து புள்ளிகள் ஏழு கோல்கள் + +CARDINAL பதிப்பு ௨ தலைமுறை ௪ பதிப்பு இரண்டு தலைமுறை நான்கு + +CARDINAL ௮ செங்கற்கள் ௩௨ கற்கள் எட்டு செங்கற்கள் முப்பத்து இரண்டு கற்கள் + +CARDINAL ௯ ஓவரில் ௧௫ ரன்கள் ஒன்பது ஓவரில் பதினைந்து ரன்கள் + +CARDINAL ௪ விக்கெட் ௧௧௩ ரன்கள் நான்கு விக்கெட் நூற்று பதிமூன்று ரன்கள் + +CARDINAL ௭ விக்கெட் ௨௧௧ ரன்கள் ஏழு விக்கெட் இருநூற்று பதினொன்று ரன்கள் + +CARDINAL ௪ சிக்ஸர்கள் ௫ ஃபோர்கள் ௪௪ ரன்கள் நான்கு சிக்ஸர்கள் ஐந்து ஃபோர்கள் நாற்பத்து நான்கு ரன்கள் + +CARDINAL ருகு ௮ வரி ௧௦ ருகு எட்டு வரி பத்து + +CARDINAL பாடம் ௯ வரி ௧௩ பாடம் ஒன்பது வரி பதிமூன்று + +CARDINAL பகுதி ௧௦ வரி ௬ சுலோகம் ௨ பகுதி பத்து வரி ஆறு சுலோகம் இரண்டு + +CARDINAL பகுதி ௧௨ சுலோகம் ௩ வரி ௧௭ பகுதி பன்னிரண்டு சுலோகம் மூன்று வரி பதினேழு + +CARDINAL ௭ ஓவர் ஏழு ஓவர் + +CARDINAL ௬ ஃபோர்கள் ஆறு ஃபோர்கள் + +CARDINAL ௩ ஒன்றுநாள் ௫ டெஸ்ட் போட்டிகள் மூன்று ஒன்றுநாள் ஐந்து டெஸ்ட் போட்டிகள் + +CARDINAL ௭ வீரர்கள் ௨ காயம் ஏழு வீரர்கள் இரண்டு காயம் + +CARDINAL பதிப்பு ௩ தலைமுறை ௧௦ பதிப்பு மூன்று தலைமுறை பத்து + +CARDINAL ருகு ௧௪ பாரா ௮ ருகு பதினான்கு பாரா எட்டு + +CARDINAL சுலோகம் ௮ பாடம் ௬ சுலோகம் எட்டு பாடம் ஆறு + +CARDINAL விரிவுரை ௩ வகுப்பு ௮ விரிவுரை மூன்று வகுப்பு எட்டு + +CARDINAL வகுப்பு ௧௦ பிரிவு ௨ வகுப்பு பத்து பிரிவு இரண்டு + +CARDINAL ௩ டிரா ௨ தோல்வி மூன்று டிரா இரண்டு தோல்வி + +CARDINAL சுலோகம் ௩ பாடம் ௧௧ சுலோகம் மூன்று பாடம் பதினொன்று + +CARDINAL வரி ௬ பாடம் ௧௦ வரி ஆறு பாடம் பத்து + +CARDINAL ருகு ௨ பாரா ௧௫ ருகு இரண்டு பாரா பதினைந்து + +CARDINAL ௪ சிக்ஸர்கள் ௫ பந்துகள் நான்கு சிக்ஸர்கள் ஐந்து பந்துகள் + +CARDINAL ௨ பந்துகள் ௧ ரன் இரண்டு பந்துகள் ஒன்று ரன் + +CARDINAL வரி ௮ அத்தியாயம் ௧௯ வரி எட்டு அத்தியாயம் பத்தொன்பது + +CARDINAL பக்கம் ௧௦ பத்தி ௨ பக்கம் பத்து பத்தி இரண்டு + +CARDINAL ௯ ஓவரில் ௧௭ ரன்கள் ஒன்பது ஓவரில் பதினேழு ரன்கள் + +CARDINAL ௪ பந்துகளில் ௬ நான்கு பந்துகளில் ஆறு + +CARDINAL ௧௭ பந்துகளில் ௧௦ ரன்கள் பதினேழு பந்துகளில் பத்து ரன்கள் + +CARDINAL ௫ ஓவர் ௬௬ ரன்கள் ஐந்து ஓவர் அறுபத்து ஆறு ரன்கள் + +CARDINAL ௮ புள்ளிகள் ௯ கோல்கள் எட்டு புள்ளிகள் ஒன்பது கோல்கள் + +CARDINAL ௫ கொய்யாப்பழங்கள் ஐந்து கொய்யாப்பழங்கள் + +CARDINAL ௬ ருகு ௭ பாரா ஆறு ருகு ஏழு பாரா + +CARDINAL சுலோகம் ௮ பதம் ௯ சுலோகம் எட்டு பதம் ஒன்பது + +CARDINAL ௭ ஓவரில் ௨௧ ரன்கள் ஏழு ஓவரில் இருபத்து ஒன்று ரன்கள் + +CARDINAL ௧ ஓவரில் ௩ ரன்கள் ஒன்று ஓவரில் மூன்று ரன்கள் + +CARDINAL ௭ சிக்ஸர்கள் ௫ ஃபோர்கள் ஏழு சிக்ஸர்கள் ஐந்து ஃபோர்கள் + +CARDINAL ௩ சுலோகங்கள் மூன்று சுலோகங்கள் + +CARDINAL ௬ பக்கங்கள் ஆறு பக்கங்கள் + +CARDINAL ௫ சிக்ஸர்கள் ஐந்து சிக்ஸர்கள் + +CARDINAL ௩ பாட்டில்கள் ௧௦ கண்ணாடிகள் மூன்று பாட்டில்கள் பத்து கண்ணாடிகள் + +CARDINAL ௩ போட்டிகள் மூன்று போட்டிகள் + +CARDINAL ௬ போட்டிகள் ௪ டிரா ஆறு போட்டிகள் நான்கு டிரா + +CARDINAL ௨ பந்துகளில் ௩ ரன்கள் இரண்டு பந்துகளில் மூன்று ரன்கள் + +CARDINAL ௩ புள்ளிகள் ௪ கோல்கள் மூன்று புள்ளிகள் நான்கு கோல்கள் + +CARDINAL ஆயத் ௪ வரி ௯ ஆயத் நான்கு வரி ஒன்பது + +CARDINAL பாரா ௪ ருகு ௧௦ வரி ௧௭ பாரா நான்கு ருகு பத்து வரி பதினேழு + +CARDINAL பாரா ௬ ருகு ௨௫ வரி ௨௦ பாரா ஆறு ருகு இருபத்து ஐந்து வரி இருபது + +CARDINAL பாடம் ௩ தோஹா ௪ வரி ௨ பாடம் மூன்று தோஹா நான்கு வரி இரண்டு + +CARDINAL வரி ௮ சொல் ௬ வரி எட்டு சொல் ஆறு + +CARDINAL கட்டுரை ௧௦ பத்தி ௨ கட்டுரை பத்து பத்தி இரண்டு + +CARDINAL ௭ ஸ்வரங்கள் ஏழு ஸ்வரங்கள் + +CARDINAL பாடல் ௪ முகடை ௨ பாடல் நான்கு முகடை இரண்டு + +CARDINAL டிக்கெட் எண் ௯ வரி ௮ டிக்கெட் எண் ஒன்பது வரி எட்டு + +CARDINAL ஆயத் ௧௦ வரி ௧௮ ஆயத் பத்து வரி பதினெட்டு + +CARDINAL ௬ ஓவர் ௨௦ ரன்கள் ஆறு ஓவர் இருபது ரன்கள் + +CARDINAL ௮௦ ரன்கள் ௩ விக்கெட்டுகள் எண்பது ரன்கள் மூன்று விக்கெட்டுகள் + +CARDINAL ௪ ஸ்பின்னர்கள் ௩ பேட்ஸ்மேன்கள் ௧ விக்கெட் கீப்பர் நான்கு ஸ்பின்னர்கள் மூன்று பேட்ஸ்மேன்கள் ஒன்று விக்கெட் கீப்பர் + +CARDINAL ௧ கோல் கீப்பர் ௬ வீரர்கள் ஒன்று கோல் கீப்பர் ஆறு வீரர்கள் + +CARDINAL பாடம் ௧௮ பதம் ௫ பாடம் பதினெட்டு பதம் ஐந்து + +CARDINAL தோஹா ௬ வரி ௯ தோஹா ஆறு வரி ஒன்பது + +CARDINAL படம் ௬ பக்கம் ௮௦ படம் ஆறு பக்கம் எண்பது + +CARDINAL ௨ டிரா ௩ வெற்றி இரண்டு டிரா மூன்று வெற்றி + +CARDINAL ௪ வைவா ௩ தேர்வுகள் நான்கு வைவா மூன்று தேர்வுகள் + +CARDINAL ௪ தேர்வுகள் ௬ செஷனல்கள் நான்கு தேர்வுகள் ஆறு செஷனல்கள் + +CARDINAL ௩ தட்டுகள் ௪ கிண்ணங்கள் ௨ கரண்டிகள் மூன்று தட்டுகள் நான்கு கிண்ணங்கள் இரண்டு கரண்டிகள் + +CARDINAL ௪ டிரா ௫ வெற்றி நான்கு டிரா ஐந்து வெற்றி + +CARDINAL ௮ சிக்ஸர்கள் ௧௪ ஃபோர்கள் எட்டு சிக்ஸர்கள் பதினான்கு ஃபோர்கள் + +CARDINAL ௫ ஓவர்கள் ௪ விக்கெட்டுகள் ஐந்து ஓவர்கள் நான்கு விக்கெட்டுகள் + +CARDINAL ௩ ரன்கள் ௨ விக்கெட்டுகள் மூன்று ரன்கள் இரண்டு விக்கெட்டுகள் + +CARDINAL ௬ ஓவர்கள் ௪ ரன்கள் ஆறு ஓவர்கள் நான்கு ரன்கள் + +CARDINAL ௪ டெஸ்ட் போட்டிகள் ௧ ஒன்றுநாள் போட்டி நான்கு டெஸ்ட் போட்டிகள் ஒன்று ஒன்றுநாள் போட்டி + +CARDINAL ௨ புள்ளிகள் ௧௨ கோல்கள் இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் + +CARDINAL ௭ கரண்டிகள் உடைந்தன ஏழு கரண்டிகள் உடைந்தன + +CARDINAL ௧௦ இல் ௬ மதிப்பெண்கள் பத்து இல் ஆறு மதிப்பெண்கள் + +CARDINAL பாடம் ௨ பக்க எண் ௧௨ பாடம் இரண்டு பக்க எண் பன்னிரண்டு + +CARDINAL ௧ ஓவரில் ௬ பந்துகள் ஒன்று ஓவரில் ஆறு பந்துகள் + +CARDINAL ௭ ஷாட்டுகள் சரியாக பட்டன ஏழு ஷாட்டுகள் சரியாக பட்டன + +CARDINAL இந்தியாவுக்கு ௪ புள்ளிகள் முன்னிலை இந்தியாவுக்கு நான்கு புள்ளிகள் முன்னிலை + +CARDINAL சதத்திற்கு ௩ ரன்கள் மீதம் சதத்திற்கு மூன்று ரன்கள் மீதம் + +CARDINAL ௧ தோல்வி ௨ டிரா ஒன்று தோல்வி இரண்டு டிரா + +CARDINAL அர்ஜென்டினா ௨ புள்ளிகள் பின்தங்கி அர்ஜென்டினா இரண்டு புள்ளிகள் பின்தங்கி + +CARDINAL ௨ கோல்கள் அடிக்கப்பட்டன இரண்டு கோல்கள் அடிக்கப்பட்டன + +CARDINAL ௮ கூடுதல் ரன்கள் எட்டு கூடுதல் ரன்கள் + +CARDINAL ௪ வைடு பந்துகள் நான்கு வைடு பந்துகள் + +CARDINAL வகுப்பு ௯ வகுப்பு ஒன்பது + +CARDINAL வகுப்பு ௫ வகுப்பு ஐந்து + +CARDINAL ௯ பகுதிகள் ஒன்பது பகுதிகள் + +CARDINAL வகுப்பு ௪ பாடம் ௩ வகுப்பு நான்கு பாடம் மூன்று + +CARDINAL பாடம் ௯ பாடம் ஒன்பது + +CARDINAL பக்க எண் ௮ பக்க எண் எட்டு + +CARDINAL ௪ பாட்டில்கள் நான்கு பாட்டில்கள் + +CARDINAL ௧௦௦ இல் ௪ மதிப்பெண்கள் நூறு இல் நான்கு மதிப்பெண்கள் + +CARDINAL ௮ மதிப்பெண்கள் எட்டு மதிப்பெண்கள் + +CARDINAL கண்ணாடி எண் ௨ கண்ணாடி எண் இரண்டு + +CARDINAL ௭ செருப்புகள் ஏழு செருப்புகள் + +CARDINAL ௫ காலணிகள் ஐந்து காலணிகள் + +CARDINAL ௨ சாண்டல்கள் இரண்டு சாண்டல்கள் + +CARDINAL ௭ விளையாட்டுகளில் வெற்றி ஏழு விளையாட்டுகளில் வெற்றி + +CARDINAL ௬ மூடிகள் ஆறு மூடிகள் + +CARDINAL ௧௦௦௦ ரூபாய் ௨ நோட்டுகள் ஆயிரம் ரூபாய் இரண்டு நோட்டுகள் + +CARDINAL ௧௯ இல் ௩ கண்ணாடிகள் பத்தொன்பது இல் மூன்று கண்ணாடிகள் + +CARDINAL பக்கம் ௧௯௯ பாடம் ௬ பக்கம் நூற்று தொண்ணூற்று ஒன்பது பாடம் ஆறு + +CARDINAL ௮ பாராக்கள் எட்டு பாராக்கள் + +CARDINAL பகுதி ௫ பாடம் ௧௯ பகுதி ஐந்து பாடம் பத்தொன்பது + +CARDINAL ௮௦ ரன்கள் ௬ விக்கெட்டுகள் எண்பது ரன்கள் ஆறு விக்கெட்டுகள் + +CARDINAL ௯ கூடுதல் ரன்கள் ஒன்பது கூடுதல் ரன்கள் + +CARDINAL ௧௧ பந்துகள் ௮ ரன்கள் பதினொன்று பந்துகள் எட்டு ரன்கள் + +CARDINAL ௨ மஞ்சள் ௮ சிவப்பு அட்டைகள் இரண்டு மஞ்சள் எட்டு சிவப்பு அட்டைகள் + +CARDINAL அத்தியாயம் ௧௨ சுலோகம் ௮ அத்தியாயம் பன்னிரண்டு சுலோகம் எட்டு + +CARDINAL பக்கம் ௮௮ அத்தியாயம் ௭ பக்கம் எண்பத்து எட்டு அத்தியாயம் ஏழு + +CARDINAL ௧௦௦ ரன்கள் ௫ விக்கெட்டுகள் நூறு ரன்கள் ஐந்து விக்கெட்டுகள் + +CARDINAL ௮ கோல்களால் வெற்றி எட்டு கோல்களால் வெற்றி + +CARDINAL ௩ சக்கர வாகனம் மூன்று சக்கர வாகனம் + +CARDINAL அத்தியாயம் ௧௯ பகுதி ௪ அத்தியாயம் பத்தொன்பது பகுதி நான்கு + +CARDINAL ௧௧ மாதங்கள் ௮ நாட்கள் பதினொன்று மாதங்கள் எட்டு நாட்கள் + +CARDINAL ௯ நாட்கள் ௧௨ மணி நேரம் ஒன்பது நாட்கள் பன்னிரண்டு மணி நேரம் + +CARDINAL ௪ கட்டுகள் ௧௩ அட்டைகள் நான்கு கட்டுகள் பதிமூன்று அட்டைகள் + +CARDINAL ௭ போட்டிகள் ௧௨ விக்கெட்டுகள் ஏழு போட்டிகள் பன்னிரண்டு விக்கெட்டுகள் + +CARDINAL ௧ மனிதன் ஒன்று மனிதன் + +CARDINAL ௨ பெண்கள் இரண்டு பெண்கள் + +CARDINAL ௩ குழந்தைகள் மூன்று குழந்தைகள் + +CARDINAL ௪ புத்தகங்கள் நான்கு புத்தகங்கள் + +CARDINAL ௫ அறைகள் ஐந்து அறைகள் + +CARDINAL ௬ வீடுகள் ஆறு வீடுகள் + +CARDINAL ௭ பக்கங்கள் ஏழு பக்கங்கள் + +CARDINAL ௮ நாணயங்கள் எட்டு நாணயங்கள் + +CARDINAL ௯ பெட்டிகள் ஒன்பது பெட்டிகள் + +CARDINAL ௧௦ வேலைகள் பத்து வேலைகள் + +CARDINAL ௧௧ பழங்கள் ௨ பூக்கள் பதினொன்று பழங்கள் இரண்டு பூக்கள் + +CARDINAL ௩ பூக்கள் மூன்று பூக்கள் + +CARDINAL ௧௩ பூந்தொட்டிகள் ௪ செடிகள் பதிமூன்று பூந்தொட்டிகள் நான்கு செடிகள் + +CARDINAL ௪ பப்பாளிப்பழங்கள் நான்கு பப்பாளிப்பழங்கள் + +CARDINAL ௫ மாம்பழங்கள் ஐந்து மாம்பழங்கள் + +CARDINAL ௬ வாழைப்பழங்கள் ஆறு வாழைப்பழங்கள் + +CARDINAL ௭ திராட்சைப்பழங்கள் ஏழு திராட்சைப்பழங்கள் + +CARDINAL ௮ ஆரஞ்சுப்பழங்கள் எட்டு ஆரஞ்சுப்பழங்கள் + +CARDINAL ௯ ஆப்பிள்கள் ஒன்பது ஆப்பிள்கள் + +CARDINAL ௧௦ சப்போட்டா பழங்கள் பத்து சப்போட்டா பழங்கள் + +CARDINAL ௧ தாமரை ஒன்று தாமரை + +CARDINAL ௨ கற்கள் இரண்டு கற்கள் + +CARDINAL ௩ நாற்காலிகள் மூன்று நாற்காலிகள் + +CARDINAL ௪ பைகள் நான்கு பைகள் + +CARDINAL ௫ தொலைபேசிகள் ஐந்து தொலைபேசிகள் + +CARDINAL ௬ அறைகள் ஆறு அறைகள் + +CARDINAL ௭ பெண்கள் ஏழு பெண்கள் + +CARDINAL ௮ புத்தகங்கள் எட்டு புத்தகங்கள் + +CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் + +CARDINAL ௧௦ நதிகள் பத்து நதிகள் + +CARDINAL ௩ எருமைகள் மூன்று எருமைகள் + +CARDINAL ௨ காலணிகள் இரண்டு காலணிகள் + +CARDINAL ௩ நாய்கள் மூன்று நாய்கள் + +CARDINAL ௪ குதிரைகள் நான்கு குதிரைகள் + +CARDINAL ௫ மகன்கள் ஐந்து மகன்கள் + +CARDINAL ௬ சேவல்கள் ஆறு சேவல்கள் + +CARDINAL ௭ கழுதைகள் ஏழு கழுதைகள் + +CARDINAL ௮ சிறுமிகள் எட்டு சிறுமிகள் + +CARDINAL ௯ சிறுவர்கள் ஒன்பது சிறுவர்கள் + +CARDINAL ௧௦ கேள்விகள் பத்து கேள்விகள் + +CARDINAL ௧ சட்டை ஒன்று சட்டை + +CARDINAL ௨ படகுகள் இரண்டு படகுகள் + +CARDINAL ௩ பெட்டிகள் மூன்று பெட்டிகள் + +CARDINAL ௪ மூடிகள் நான்கு மூடிகள் + +CARDINAL ௫ நோட்டுகள் ஐந்து நோட்டுகள் + +CARDINAL ௬ நாணயங்கள் ஆறு நாணயங்கள் + +CARDINAL ௭ காயங்கள் ஏழு காயங்கள் + +CARDINAL ௮ நிறங்கள் எட்டு நிறங்கள் + +CARDINAL ௯ மக்கள் ஒன்பது மக்கள் + +CARDINAL ௧௦ நாட்கள் பத்து நாட்கள் + +CARDINAL ௫ விஷயங்கள் ஐந்து விஷயங்கள் + +CARDINAL ௨ மருந்துகள் இரண்டு மருந்துகள் + +CARDINAL ௩ கூடுகள் மூன்று கூடுகள் + +CARDINAL ௪ தோழிகள் நான்கு தோழிகள் + +CARDINAL ௫ செடிகள் ஐந்து செடிகள் + +CARDINAL ௬ திரைகள் ஆறு திரைகள் + +CARDINAL ௭ பூனைகள் ஏழு பூனைகள் + +CARDINAL ௮ எலிகள் எட்டு எலிகள் + +CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் + +CARDINAL ௧௦ கண்கள் பத்து கண்கள் + +CARDINAL ௬ சுவர்கள் ஆறு சுவர்கள் + +CARDINAL ௨ கடிகாரங்கள் இரண்டு கடிகாரங்கள் + +CARDINAL ௩ பப்பாளிப்பழங்கள் மூன்று பப்பாளிப்பழங்கள் + +CARDINAL ௪ மிதிவண்டிகள் நான்கு மிதிவண்டிகள் + +CARDINAL ௫ ஜன்னல்கள் ஐந்து ஜன்னல்கள் + +CARDINAL ௬ கிளைகள் ஆறு கிளைகள் + +CARDINAL ௭ பொம்மைகள் ஏழு பொம்மைகள் + +CARDINAL ௮ கவிதைகள் எட்டு கவிதைகள் + +CARDINAL ௯ கதைகள் ஒன்பது கதைகள் + +CARDINAL ௧௦ கதைகள் பத்து கதைகள் + +CARDINAL ௭ மொட்டுகள் ஏழு மொட்டுகள் + +CARDINAL ௨ கோழிகள் இரண்டு கோழிகள் + +CARDINAL ௩ தெருக்கள் மூன்று தெருக்கள் + +CARDINAL ௪ தேதிகள் நான்கு தேதிகள் + +CARDINAL ௫ கருவிகள் ஐந்து கருவிகள் + +CARDINAL ௬ கன்னியர்கள் ஆறு கன்னியர்கள் + +CARDINAL ௭ தட்டுகள் ஏழு தட்டுகள் + +CARDINAL ௮ பெண்கள் எட்டு பெண்கள் + +CARDINAL ௯ இரவுகள் ஒன்பது இரவுகள் + +CARDINAL ௧௦ காய்கறிகள் பத்து காய்கறிகள் + +CARDINAL ௮ குழந்தைகள் எட்டு குழந்தைகள் + +CARDINAL ௨ தொப்பிகள் இரண்டு தொப்பிகள் + +CARDINAL ௩ சிறுமிகள் மூன்று சிறுமிகள் + +CARDINAL ௪ நதிகள் நான்கு நதிகள் + +CARDINAL ௫ பெண்கள் ஐந்து பெண்கள் + +CARDINAL ௬ பொட்டுகள் ஆறு பொட்டுகள் + +CARDINAL ௭ பெட்டிகள் ஏழு பெட்டிகள் + +CARDINAL ௯ பொம்மைகள் ஒன்பது பொம்மைகள் + +CARDINAL ௧௦ கதைகள் பத்து கதைகள் + +CARDINAL ௯ இதழ்கள் ஒன்பது இதழ்கள் + +CARDINAL ௨ கொடிகள் இரண்டு கொடிகள் + +CARDINAL ௩ கவிதைகள் மூன்று கவிதைகள் + +CARDINAL ௪ ஏரிகள் நான்கு ஏரிகள் + +CARDINAL ௫ செருப்புகள் ஐந்து செருப்புகள் + +CARDINAL ௬ பசுக்கள் ஆறு பசுக்கள் + +CARDINAL ௭ சாலைகள் ஏழு சாலைகள் + +CARDINAL ௮ கண்கள் எட்டு கண்கள் + +CARDINAL ௧௦ பேச்சுகள் பத்து பேச்சுகள் + +CARDINAL ௧௦௧ நூற்று ஒன்று + +CARDINAL ௧௦௨ நூற்று இரண்டு + +CARDINAL ௧௦௩ நூற்று மூன்று + +CARDINAL ௧௦௪ நூற்று நான்கு + +CARDINAL ௧௦௫ நூற்று ஐந்து + +CARDINAL ௧௦௬ நூற்று ஆறு + +CARDINAL ௧௦௭ நூற்று ஏழு + +CARDINAL ௧௦௮ நூற்று எட்டு + +CARDINAL ௧௦௯ நூற்று ஒன்பது + +CARDINAL ௧௧௦ நூற்று பத்து + +CARDINAL ௧௧௧ நூற்று பதினொன்று + +CARDINAL ௧௧௨ நூற்று பன்னிரண்டு + +CARDINAL ௧௧௩ நூற்று பதிமூன்று + +CARDINAL ௧௧௪ நூற்று பதினான்கு + +CARDINAL ௧௧௫ நூற்று பதினைந்து + +CARDINAL ௧௧௬ நூற்று பதினாறு + +CARDINAL ௮௧௭ எட்டுநூற்று பதினேழு + +CARDINAL ௮௧௮ எட்டுநூற்று பதினெட்டு + +CARDINAL ௮௧௯ எட்டுநூற்று பத்தொன்பது + +CARDINAL ௮௨௦ எட்டுநூற்று இருபது + +CARDINAL ௮௨௧ எட்டுநூற்று இருபத்து ஒன்று + +CARDINAL ௮௨௨ எட்டுநூற்று இருபத்து இரண்டு + +CARDINAL ௮௨௩ எட்டுநூற்று இருபத்து மூன்று + +CARDINAL ௮௨௪ எட்டுநூற்று இருபத்து நான்கு + +CARDINAL ௮௨௫ எட்டுநூற்று இருபத்து ஐந்து + +CARDINAL ௮௨௬ எட்டுநூற்று இருபத்து ஆறு + +CARDINAL ௮௨௭ எட்டுநூற்று இருபத்து ஏழு + +CARDINAL ௮௨௮ எட்டுநூற்று இருபத்து எட்டு + +CARDINAL ௮௨௯ எட்டுநூற்று இருபத்து ஒன்பது + +CARDINAL ௮௩௦ எட்டுநூற்று முப்பது + +CARDINAL ௮௩௧ எட்டுநூற்று முப்பத்து ஒன்று + +CARDINAL ௮௩௨ எட்டுநூற்று முப்பத்து இரண்டு + +CARDINAL ௮௩௩ எட்டுநூற்று முப்பத்து மூன்று + +CARDINAL ௮௩௪ எட்டுநூற்று முப்பத்து நான்கு + +CARDINAL ௮௩௫ எட்டுநூற்று முப்பத்து ஐந்து + +CARDINAL ௮௩௬ எட்டுநூற்று முப்பத்து ஆறு + +CARDINAL ௭௩௮ எழுநூற்று முப்பத்து எட்டு + +CARDINAL ௭௩௯ எழுநூற்று முப்பத்து ஒன்பது + +CARDINAL ௭௪௦ எழுநூற்று நாற்பது + +CARDINAL ௭௪௧ எழுநூற்று நாற்பத்து ஒன்று + +CARDINAL ௭௪௨ எழுநூற்று நாற்பத்து இரண்டு + +CARDINAL ௭௪௩ எழுநூற்று நாற்பத்து மூன்று + +CARDINAL ௭௪௪ எழுநூற்று நாற்பத்து நான்கு + +CARDINAL ௭௪௫ எழுநூற்று நாற்பத்து ஐந்து + +CARDINAL ௪௪௬ நானூற்று நாற்பத்து ஆறு + +CARDINAL ௪௪௭ நானூற்று நாற்பத்து ஏழு + +CARDINAL ௪௪௮ நானூற்று நாற்பத்து எட்டு + +CARDINAL ௪௪௯ நானூற்று நாற்பத்து ஒன்பது + +CARDINAL ௪௫௦ நானூற்று ஐம்பது + +CARDINAL ௪௬௧ நானூற்று அறுபத்து ஒன்று + +CARDINAL ௧௭௫ நூற்று எழுபத்து ஐந்து + +CARDINAL ௧௮௧ நூற்று எண்பத்து ஒன்று + +CARDINAL ௧௯௦ நூற்று தொண்ணூறு + +CARDINAL ௧௯௯ நூற்று தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௧ ஆயிரத்து ஒன்று + +CARDINAL ௧௦௦௨ ஆயிரத்து இரண்டு + +CARDINAL ௧௦௦௩ ஆயிரத்து மூன்று + +CARDINAL ௧௦௦௪ ஆயிரத்து நான்கு + +CARDINAL ௧௦௦௫ ஆயிரத்து ஐந்து + +CARDINAL ௧௦௦௬ ஆயிரத்து ஆறு + +CARDINAL ௧௦௦௭ ஆயிரத்து ஏழு + +CARDINAL ௧௦௦௮ ஆயிரத்து எட்டு + +CARDINAL ௧௦௦௯ ஆயிரத்து ஒன்பது + +CARDINAL ௧௦௧௦ ஆயிரத்து பத்து + +CARDINAL ௧௦௧௧ ஆயிரத்து பதினொன்று + +CARDINAL ௧௦௧௨ ஆயிரத்து பன்னிரண்டு + +CARDINAL ௧௦௧௩ ஆயிரத்து பதிமூன்று + +CARDINAL ௧௦௧௪ ஆயிரத்து பதினான்கு + +CARDINAL ௧௦௧௫ ஆயிரத்து பதினைந்து + +CARDINAL ௧௦௧௬ ஆயிரத்து பதினாறு + +CARDINAL ௧௦௧௭ ஆயிரத்து பதினேழு + +CARDINAL ௧௦௧௮ ஆயிரத்து பதினெட்டு + +CARDINAL ௧௦௧௯ ஆயிரத்து பத்தொன்பது + +CARDINAL ௧௦௨௦ ஆயிரத்து இருபது + +CARDINAL ௧௦௨௧ ஆயிரத்து இருபத்து ஒன்று + +CARDINAL ௧௦௨௨ ஆயிரத்து இருபத்து இரண்டு + +CARDINAL ௧௧௨௩ ஆயிரத்து நூற்று இருபத்து மூன்று + +CARDINAL ௧௪௨௪ ஆயிரத்து நானூற்று இருபத்து நான்கு + +CARDINAL ௧௫௨௫ ஆயிரத்து ஐந்நூற்று இருபத்து ஐந்து + +CARDINAL ௧௩௨௬ ஆயிரத்து முந்நூற்று இருபத்து ஆறு + +CARDINAL ௧௪௨௭ ஆயிரத்து நானூற்று இருபத்து ஏழு + +CARDINAL ௧௬௨௮ ஆயிரத்து அறுநூற்று இருபத்து எட்டு + +CARDINAL ௧௭௨௯ ஆயிரத்து எழுநூற்று இருபத்து ஒன்பது + +CARDINAL ௧௮௩௦ ஆயிரத்து எட்டுநூற்று முப்பது + +CARDINAL ௧௧௩௧ ஆயிரத்து நூற்று முப்பத்து ஒன்று + +CARDINAL ௧௨௩௨ ஆயிரத்து இருநூற்று முப்பத்து இரண்டு + +CARDINAL ௧௩௩௩ ஆயிரத்து முந்நூற்று முப்பத்து மூன்று + +CARDINAL ௧௪௩௪ ஆயிரத்து நானூற்று முப்பத்து நான்கு + +CARDINAL ௧௫௩௫ ஆயிரத்து ஐந்நூற்று முப்பத்து ஐந்து + +CARDINAL ௧௬௩௬ ஆயிரத்து அறுநூற்று முப்பத்து ஆறு + +CARDINAL ௧௭௩௭ ஆயிரத்து எழுநூற்று முப்பத்து ஏழு + +CARDINAL ௧௮௩௮ ஆயிரத்து எட்டுநூற்று முப்பத்து எட்டு + +CARDINAL ௧௯௩௯ ஆயிரத்து ஒன்பதுநூற்று முப்பத்து ஒன்பது + +CARDINAL ௧௦௪௦ ஆயிரத்து நாற்பது + +CARDINAL ௧௦௪௧ ஆயிரத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௪௨ ஆயிரத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௪௩ ஆயிரத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௪௪ ஆயிரத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௪௫ ஆயிரத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௪௬ ஆயிரத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௪௭ ஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௪௮ ஆயிரத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௪௯ ஆயிரத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௫௦ ஆயிரத்து ஐம்பது + +CARDINAL ௧௦௬௧ ஆயிரத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௭௫ ஆயிரத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௮௧ ஆயிரத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௯௦ ஆயிரத்து தொண்ணூறு + +CARDINAL ௧௦௯௯ ஆயிரத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௧ பத்துஆயிரத்து ஒன்று + +CARDINAL ௧௦௦௦௨ பத்துஆயிரத்து இரண்டு + +CARDINAL ௧௦௨௦௩ பத்துஆயிரத்து இருநூற்று மூன்று + +CARDINAL ௧௦௩௦௪ பத்துஆயிரத்து முந்நூற்று நான்கு + +CARDINAL ௧௧௩௦௫ பதினொன்றுஆயிரத்து முந்நூற்று ஐந்து + +CARDINAL ௧௨௪௫௬ பன்னிரண்டுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௧௩௦௪௭ பதிமூன்றுஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௮ பத்துஆயிரத்து எட்டு + +CARDINAL ௧௦௦௦௯ பத்துஆயிரத்து ஒன்பது + +CARDINAL ௧௦௦௧௦ பத்துஆயிரத்து பத்து + +CARDINAL ௧௦௦௧௧ பத்துஆயிரத்து பதினொன்று + +CARDINAL ௧௦௦௧௨ பத்துஆயிரத்து பன்னிரண்டு + +CARDINAL ௧௦௦௧௩ பத்துஆயிரத்து பதிமூன்று + +CARDINAL ௧௦௦௧௪ பத்துஆயிரத்து பதினான்கு + +CARDINAL ௧௦௦௧௫ பத்துஆயிரத்து பதினைந்து + +CARDINAL ௧௦௦௧௬ பத்துஆயிரத்து பதினாறு + +CARDINAL ௧௦௦௧௭ பத்துஆயிரத்து பதினேழு + +CARDINAL ௧௦௦௧௮ பத்துஆயிரத்து பதினெட்டு + +CARDINAL ௧௦௦௧௯ பத்துஆயிரத்து பத்தொன்பது + +CARDINAL ௧௦௦௨௦ பத்துஆயிரத்து இருபது + +CARDINAL ௧௦௦௨௧ பத்துஆயிரத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௨௨ பத்துஆயிரத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௨௩ பத்துஆயிரத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௨௪ பத்துஆயிரத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௨௫ பத்துஆயிரத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௨௬ பத்துஆயிரத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௨௭ பத்துஆயிரத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௨௮ பத்துஆயிரத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௨௯ பத்துஆயிரத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௩௦ பத்துஆயிரத்து முப்பது + +CARDINAL ௧௦௦௩௧ பத்துஆயிரத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௩௨ பத்துஆயிரத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௩௩ பத்துஆயிரத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௩௪ பத்துஆயிரத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௩௫ பத்துஆயிரத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௩௬ பத்துஆயிரத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௩௭ பத்துஆயிரத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௩௮ பத்துஆயிரத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௩௯ பத்துஆயிரத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௪௦ பத்துஆயிரத்து நாற்பது + +CARDINAL ௧௦௦௪௧ பத்துஆயிரத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௪௨ பத்துஆயிரத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௪௩ பத்துஆயிரத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௪௪ பத்துஆயிரத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௪௫ பத்துஆயிரத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௪௬ பத்துஆயிரத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௪௭ பத்துஆயிரத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௪௮ பத்துஆயிரத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௪௯ பத்துஆயிரத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௫௦ பத்துஆயிரத்து ஐம்பது + +CARDINAL ௧௦௦௬௧ பத்துஆயிரத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௭௫ பத்துஆயிரத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௮௧ பத்துஆயிரத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௯௦ பத்துஆயிரத்து தொண்ணூறு + +CARDINAL ௧௦௦௯௯ பத்துஆயிரத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௧ ஒன்று இலட்சத்து ஒன்று + +CARDINAL ௧௧௦௦௦௨ ஒன்று இலட்சத்து பத்துஆயிரத்து இரண்டு + +CARDINAL ௧௨௦௪௦௩ ஒன்று இலட்சத்து இருபதுஆயிரத்து நானூற்று மூன்று + +CARDINAL ௧௪௧௫௦௪ ஒன்று இலட்சத்து நாற்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று நான்கு + +CARDINAL ௧௫௧௫௧௫ ஒன்று இலட்சத்து ஐம்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று பதினைந்து + +CARDINAL ௧௦௦௦௦௬ ஒன்று இலட்சத்து ஆறு + +CARDINAL ௧௦௦௦௦௭ ஒன்று இலட்சத்து ஏழு + +CARDINAL ௧௦௦௦௦௮ ஒன்று இலட்சத்து எட்டு + +CARDINAL ௧௦௦௦௦௯ ஒன்று இலட்சத்து ஒன்பது + +CARDINAL ௧௦௦௦௧௦ ஒன்று இலட்சத்து பத்து + +CARDINAL ௧௦௦௦௧௧ ஒன்று இலட்சத்து பதினொன்று + +CARDINAL ௧௦௦௦௧௨ ஒன்று இலட்சத்து பன்னிரண்டு + +CARDINAL ௧௦௦௦௧௩ ஒன்று இலட்சத்து பதிமூன்று + +CARDINAL ௧௦௦௦௧௪ ஒன்று இலட்சத்து பதினான்கு + +CARDINAL ௧௦௦௦௧௫ ஒன்று இலட்சத்து பதினைந்து + +CARDINAL ௧௦௦௦௧௬ ஒன்று இலட்சத்து பதினாறு + +CARDINAL ௧௦௦௦௧௭ ஒன்று இலட்சத்து பதினேழு + +CARDINAL ௧௦௦௦௧௮ ஒன்று இலட்சத்து பதினெட்டு + +CARDINAL ௧௦௦௦௧௯ ஒன்று இலட்சத்து பத்தொன்பது + +CARDINAL ௧௦௦௦௨௦ ஒன்று இலட்சத்து இருபது + +CARDINAL ௧௦௦௦௨௧ ஒன்று இலட்சத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௨௨ ஒன்று இலட்சத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௨௩ ஒன்று இலட்சத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௦௨௪ ஒன்று இலட்சத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௦௨௫ ஒன்று இலட்சத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௨௬ ஒன்று இலட்சத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௦௨௭ ஒன்று இலட்சத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௦௨௮ ஒன்று இலட்சத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௦௨௯ ஒன்று இலட்சத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௩௦ ஒன்று இலட்சத்து முப்பது + +CARDINAL ௧௦௦௦௩௧ ஒன்று இலட்சத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௩௨ ஒன்று இலட்சத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௩௩ ஒன்று இலட்சத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௩௪ ஒன்று இலட்சத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௩௫ ஒன்று இலட்சத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௩௬ ஒன்று இலட்சத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௩௭ ஒன்று இலட்சத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௩௮ ஒன்று இலட்சத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௩௯ ஒன்று இலட்சத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௪௦ ஒன்று இலட்சத்து நாற்பது + +CARDINAL ௧௦௦௦௪௧ ஒன்று இலட்சத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௪௨ ஒன்று இலட்சத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௪௩ ஒன்று இலட்சத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௪௪ ஒன்று இலட்சத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௪௫ ஒன்று இலட்சத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௪௬ ஒன்று இலட்சத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௪௭ ஒன்று இலட்சத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௪௮ ஒன்று இலட்சத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௪௯ ஒன்று இலட்சத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௫௦ ஒன்று இலட்சத்து ஐம்பது + +CARDINAL ௧௦௦௦௬௧ ஒன்று இலட்சத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௭௫ ஒன்று இலட்சத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௮௧ ஒன்று இலட்சத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௯௦ ஒன்று இலட்சத்து தொண்ணூறு + +CARDINAL ௧௦௦௦௯௯ ஒன்று இலட்சத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௦௧ பத்து இலட்சத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௨ பத்து இலட்சத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௩ பத்து இலட்சத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௪ பத்து இலட்சத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௫ பத்து இலட்சத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௬ பத்து இலட்சத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௭ பத்து இலட்சத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௮ பத்து இலட்சத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௯ பத்து இலட்சத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௧௦ பத்து இலட்சத்து பத்து + +CARDINAL ௧௦௦௦௦௧௧ பத்து இலட்சத்து பதினொன்று + +CARDINAL ௧௦௦௦௦௧௨ பத்து இலட்சத்து பன்னிரண்டு + +CARDINAL ௧௦௦௦௦௧௩ பத்து இலட்சத்து பதிமூன்று + +CARDINAL ௧௦௦௦௦௧௪ பத்து இலட்சத்து பதினான்கு + +CARDINAL ௧௦௦௦௦௧௫ பத்து இலட்சத்து பதினைந்து + +CARDINAL ௧௦௦௦௦௧௬ பத்து இலட்சத்து பதினாறு + +CARDINAL ௧௦௦௦௦௧௭ பத்து இலட்சத்து பதினேழு + +CARDINAL ௧௦௦௦௦௧௮ பத்து இலட்சத்து பதினெட்டு + +CARDINAL ௧௦௦௦௦௧௯ பத்து இலட்சத்து பத்தொன்பது + +CARDINAL ௧௦௦௦௦௨௦ பத்து இலட்சத்து இருபது + +CARDINAL ௧௦௦௦௦௨௧ பத்து இலட்சத்து இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௨௨ பத்து இலட்சத்து இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௦௨௩ பத்து இலட்சத்து இருபத்து மூன்று + +CARDINAL ௧௦௦௦௦௨௪ பத்து இலட்சத்து இருபத்து நான்கு + +CARDINAL ௧௦௦௦௦௨௫ பத்து இலட்சத்து இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௨௬ பத்து இலட்சத்து இருபத்து ஆறு + +CARDINAL ௧௦௦௦௦௨௭ பத்து இலட்சத்து இருபத்து ஏழு + +CARDINAL ௧௦௦௦௦௨௮ பத்து இலட்சத்து இருபத்து எட்டு + +CARDINAL ௧௦௦௦௦௨௯ பத்து இலட்சத்து இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௩௦ பத்து இலட்சத்து முப்பது + +CARDINAL ௧௦௦௦௦௩௧ பத்து இலட்சத்து முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௩௨ பத்து இலட்சத்து முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௩௩ பத்து இலட்சத்து முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௩௪ பத்து இலட்சத்து முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௩௫ பத்து இலட்சத்து முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௩௬ பத்து இலட்சத்து முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௩௭ பத்து இலட்சத்து முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௩௮ பத்து இலட்சத்து முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௩௯ பத்து இலட்சத்து முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௪௦ பத்து இலட்சத்து நாற்பது + +CARDINAL ௧௦௦௦௦௪௧ பத்து இலட்சத்து நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௪௨ பத்து இலட்சத்து நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௪௩ பத்து இலட்சத்து நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௪௪ பத்து இலட்சத்து நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௪௫ பத்து இலட்சத்து நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௪௬ பத்து இலட்சத்து நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௪௭ பத்து இலட்சத்து நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௪௮ பத்து இலட்சத்து நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௪௯ பத்து இலட்சத்து நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௫௦ பத்து இலட்சத்து ஐம்பது + +CARDINAL ௧௦௦௦௦௬௧ பத்து இலட்சத்து அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௭௫ பத்து இலட்சத்து எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௮௧ பத்து இலட்சத்து எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௯௦ பத்து இலட்சத்து தொண்ணூறு + +CARDINAL ௧௦௦௦௦௯௯ பத்து இலட்சத்து தொண்ணூற்று ஒன்பது + +CARDINAL ௧௦௦௦௦௦௦௧ ஒன்று கோடியே ஒன்று + +CARDINAL ௧௦௦௦௦௦௦௨ ஒன்று கோடியே இரண்டு + +CARDINAL ௧௦௦௦௦௦௦௩ ஒன்று கோடியே மூன்று + +CARDINAL ௧௦௦௦௦௦௦௪ ஒன்று கோடியே நான்கு + +CARDINAL ௧௦௦௦௦௦௦௫ ஒன்று கோடியே ஐந்து + +CARDINAL ௧௦௦௦௦௦௦௬ ஒன்று கோடியே ஆறு + +CARDINAL ௧௦௦௦௦௦௦௭ ஒன்று கோடியே ஏழு + +CARDINAL ௧௦௦௦௦௦௦௮ ஒன்று கோடியே எட்டு + +CARDINAL ௧௦௦௦௦௦௦௯ ஒன்று கோடியே ஒன்பது + +CARDINAL ௧௦௦௦௦௦௧௦ ஒன்று கோடியே பத்து + +CARDINAL ௧௦௦௦௦௦௧௧ ஒன்று கோடியே பதினொன்று + +CARDINAL ௧௦௦௦௦௦௧௨ ஒன்று கோடியே பன்னிரண்டு + +CARDINAL ௧௦௦௦௦௦௧௩ ஒன்று கோடியே பதிமூன்று + +CARDINAL ௧௦௦௦௦௦௧௪ ஒன்று கோடியே பதினான்கு + +CARDINAL ௧௦௦௦௦௦௧௫ ஒன்று கோடியே பதினைந்து + +CARDINAL ௧௦௦௦௦௦௧௬ ஒன்று கோடியே பதினாறு + +CARDINAL ௧௦௦௦௦௦௧௭ ஒன்று கோடியே பதினேழு + +CARDINAL ௧௦௦௦௦௦௧௮ ஒன்று கோடியே பதினெட்டு + +CARDINAL ௧௦௦௦௦௦௧௯ ஒன்று கோடியே பத்தொன்பது + +CARDINAL ௧௦௦௦௦௦௨௦ ஒன்று கோடியே இருபது + +CARDINAL ௧௦௦௦௦௦௨௧ ஒன்று கோடியே இருபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௨௨ ஒன்று கோடியே இருபத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௨௩ ஒன்று கோடியே இருபத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௨௪ ஒன்று கோடியே இருபத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௨௫ ஒன்று கோடியே இருபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௨௬ ஒன்று கோடியே இருபத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௨௭ ஒன்று கோடியே இருபத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௨௮ ஒன்று கோடியே இருபத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௨௯ ஒன்று கோடியே இருபத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௩௦ ஒன்று கோடியே முப்பது + +CARDINAL ௧௦௦௦௦௦௩௧ ஒன்று கோடியே முப்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௩௨ ஒன்று கோடியே முப்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௩௩ ஒன்று கோடியே முப்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௩௪ ஒன்று கோடியே முப்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௩௫ ஒன்று கோடியே முப்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௩௬ ஒன்று கோடியே முப்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௩௭ ஒன்று கோடியே முப்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௩௮ ஒன்று கோடியே முப்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௩௯ ஒன்று கோடியே முப்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௪௦ ஒன்று கோடியே நாற்பது + +CARDINAL ௧௦௦௦௦௦௪௧ ஒன்று கோடியே நாற்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௪௨ ஒன்று கோடியே நாற்பத்து இரண்டு + +CARDINAL ௧௦௦௦௦௦௪௩ ஒன்று கோடியே நாற்பத்து மூன்று + +CARDINAL ௧௦௦௦௦௦௪௪ ஒன்று கோடியே நாற்பத்து நான்கு + +CARDINAL ௧௦௦௦௦௦௪௫ ஒன்று கோடியே நாற்பத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௪௬ ஒன்று கோடியே நாற்பத்து ஆறு + +CARDINAL ௧௦௦௦௦௦௪௭ ஒன்று கோடியே நாற்பத்து ஏழு + +CARDINAL ௧௦௦௦௦௦௪௮ ஒன்று கோடியே நாற்பத்து எட்டு + +CARDINAL ௧௦௦௦௦௦௪௯ ஒன்று கோடியே நாற்பத்து ஒன்பது + +CARDINAL ௧௦௦௦௦௦௫௦ ஒன்று கோடியே ஐம்பது + +CARDINAL ௧௦௦௦௦௦௬௧ ஒன்று கோடியே அறுபத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௭௫ ஒன்று கோடியே எழுபத்து ஐந்து + +CARDINAL ௧௦௦௦௦௦௮௧ ஒன்று கோடியே எண்பத்து ஒன்று + +CARDINAL ௧௦௦௦௦௦௯௦ ஒன்று கோடியே தொண்ணூறு + +CARDINAL ௧௦௦௦௦௦௯௯ ஒன்று கோடியே தொண்ணூற்று ஒன்பது + +CARDINAL ௧௩௨௩ ஆயிரத்து முந்நூற்று இருபத்து மூன்று + +CARDINAL ௧௩௪௫ ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து + +CARDINAL ௧௩௪௫௬ பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௧௨௩௪௬ பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு + +CARDINAL ௧௨௩௪௫௬ ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு + +CARDINAL ௮௭௨௯௮௭ எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு + +CARDINAL ௯௮௭௬௦௯ ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது + +CARDINAL ௯௮௭௬௭௮௯ தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது + +CARDINAL ௨௩௪௫௫௬௭ இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௨௩௪௫௫௬௭ ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௨௧௨௧௨௧௨௨ பன்னிரண்டு கோடியே பன்னிரண்டு இலட்சத்து பன்னிரண்டுஆயிரத்து நூற்று இருபத்து இரண்டு + +CARDINAL ௧௦௦௨௩௪௫௫௬௭ ஒன்று அரபு இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௧௨௨௩௪௫௫௬௭ ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௦௨௨௩௪௫௫௬௭ ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௧௧௦௨௨௩௪௫௫௬௭ பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + +CARDINAL ௫௧௦௨௨௩௪௫௫௬௭ ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு + From a0815e95cb426e083a51f59b0497b05aa796e99e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 07:24:06 +0000 Subject: [PATCH 09/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: surendran-246 --- .../text_normalization/normalize.py | 10 +- .../text_normalization/ta/__init__.py | 2 +- .../text_normalization/ta/graph_utils.py | 2 +- .../text_normalization/ta/taggers/__init__.py | 2 +- .../text_normalization/ta/taggers/cardinal.py | 872 +++++++++--------- .../ta/taggers/tokenize_and_classify.py | 14 +- .../ta/verbalizers/__init__.py | 2 +- .../ta/verbalizers/verbalize.py | 28 +- run_cardinal_tests.py | 94 +- .../nemo_text_processing/ta/test_cardinal.py | 14 +- 10 files changed, 519 insertions(+), 521 deletions(-) diff --git a/nemo_text_processing/text_normalization/normalize.py b/nemo_text_processing/text_normalization/normalize.py index 01d8f3354..efb13bf4a 100644 --- a/nemo_text_processing/text_normalization/normalize.py +++ b/nemo_text_processing/text_normalization/normalize.py @@ -163,10 +163,10 @@ def __init__( from nemo_text_processing.text_normalization.hi.taggers.tokenize_and_classify import ClassifyFst from nemo_text_processing.text_normalization.hi.verbalizers.post_processing import PostProcessingFst from nemo_text_processing.text_normalization.hi.verbalizers.verbalize_final import VerbalizeFinalFst - + if post_process: self.post_processor = PostProcessingFst(cache_dir=cache_dir, overwrite_cache=overwrite_cache) - + elif lang == 'it': from nemo_text_processing.text_normalization.it.taggers.tokenize_and_classify import ClassifyFst from nemo_text_processing.text_normalization.it.verbalizers.verbalize_final import VerbalizeFinalFst @@ -399,7 +399,11 @@ def normalize( return text output = SPACE_DUP.sub(' ', output[1:]) - if self.lang in ["en", "hi", "ta", "vi"] and hasattr(self, 'post_processor') and self.post_processor is not None: + if ( + self.lang in ["en", "hi", "ta", "vi"] + and hasattr(self, 'post_processor') + and self.post_processor is not None + ): output = self.post_process(output) if punct_post_process: diff --git a/nemo_text_processing/text_normalization/ta/__init__.py b/nemo_text_processing/text_normalization/ta/__init__.py index 2f2f217f3..4fc25d0d3 100644 --- a/nemo_text_processing/text_normalization/ta/__init__.py +++ b/nemo_text_processing/text_normalization/ta/__init__.py @@ -10,4 +10,4 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. \ No newline at end of file +# limitations under the License. diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 20082e127..ee097e256 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -38,7 +38,7 @@ TA_IRANDARAI = "இரண்டரை" # 2.5 TA_ONRUKAAL = "ஒன்றுகால்" # quarter more (1.25) TA_ARAI = "அரை" # half more (X.5) -TA_MUKKAAL = "முக்கால்" # quarter less (0.75) +TA_MUKKAAL = "முக்கால்" # quarter less (0.75) # Tamil decimal representations TA_POINT_FIVE = ".௫" # .5 diff --git a/nemo_text_processing/text_normalization/ta/taggers/__init__.py b/nemo_text_processing/text_normalization/ta/taggers/__init__.py index 2f2f217f3..4fc25d0d3 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/__init__.py +++ b/nemo_text_processing/text_normalization/ta/taggers/__init__.py @@ -10,4 +10,4 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. \ No newline at end of file +# limitations under the License. diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 2c6e83596..df8ecabb5 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -14,449 +14,445 @@ import pynini from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import ( - NEMO_ALL_DIGIT, - NEMO_ALL_ZERO, - GraphFst, - insert_space, + NEMO_ALL_DIGIT, + NEMO_ALL_ZERO, + GraphFst, + insert_space, ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path + class CardinalFst(GraphFst): - """ - Finite state transducer for classifying cardinals, e.g. - -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } - Args: - deterministic: if True will provide a single transduction option, - for False multiple transduction are generated (used for audio-based normalization) - """ - def __init__(self, deterministic: bool = True, lm: bool = False): - super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) - zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) - hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) - teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) - teens_ties = pynini.union(teens_ties_hi, teens_ties_en) - teens_and_ties = pynutil.add_weight(teens_ties, -0.1) - self.digit = digit - self.zero = zero - self.hundred_ta = hundred_ta - self.teens_and_ties = teens_and_ties - # single_digit early — covers ASCII + Tamil digits + zero - single_digit = digit | zero - # Single digit graph for digit-by-digit reading - single_digit_graph = digit | zero - self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) - zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - def create_graph_suffix(digit_graph, suffix, zeros_counts): - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix - return digit_graph + (z ** zeros_counts) + suffix - def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): - ins = pynutil.insert(" ") - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix + ins + sub_graph - return digit_graph + suffix + (z ** zeros_counts) + ins + sub_graph - - # HUNDREDS GRAPH - # Use hundred_ta.tsv for fused exact hundreds (நூற்று, இருநூற்று, ... - # எட்டுநூற்று, எழுநூற்று, நானூற்று etc.) - # For 101-199: நூற்று + space + remainder - # For 201-999: fused prefix (no space) + space + remainder - # Fused hundred prefix for composites (201-999 non-exact) - fused_hundred_prefix = pynini.union( - pynini.cross("2", "இருநூற்று"), - pynini.cross("3", "முந்நூற்று"), - pynini.cross("4", "நானூற்று"), - pynini.cross("5", "ஐந்நூற்று"), - pynini.cross("6", "அறுநூற்று"), - pynini.cross("7", "எழுநூற்று"), - pynini.cross("8", "எட்டுநூற்று"), - pynini.cross("9", "ஒன்பதுநூற்று"), - pynini.cross("௨", "இருநூற்று"), - pynini.cross("௩", "முந்நூற்று"), - pynini.cross("௪", "நானூற்று"), - pynini.cross("௫", "ஐந்நூற்று"), - pynini.cross("௬", "அறுநூற்று"), - pynini.cross("௭", "எழுநூற்று"), - pynini.cross("௮", "எட்டுநூற்று"), - pynini.cross("௯", "ஒன்பதுநூற்று"), - ).optimize() - # Start with fused exact forms from hundred_ta.tsv - exact_hundred = pynutil.add_weight(pynini.union( - pynini.cross("100", "நூறு"), - pynini.cross("௧௦௦", "நூறு"), - ).optimize(), -1.0) - graph_hundreds = hundred_ta - # 101-109 (ASCII and Tamil digits) - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + zero_delete - + pynutil.insert(" ") - + single_digit - ) - # 110-119 - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + pynutil.insert(" ") - + teens_ties - ) - # 201-209, 301-309 ... 901-909 - graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit - # 210-219 ... 910-919 - graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties - # 220-299 ... 920-999 (two-digit tie/tens tail already in teens_ties) - # teens_ties handles 20,21,...99 so this covers the remaining composites - graph_hundreds = graph_hundreds.optimize() - self.graph_hundreds = graph_hundreds - # THOUSANDS GRAPH - # 1000 → ஆயிரம் (exact, no leading ஒன்று) - # 1001-1099 → ஆயிரத்து + space + remainder - # 1100-1999 → ஆயிரத்து + space + graph_hundreds - # 2000-9000 → fused exact (இரண்டாயிரம், மூன்றாயிரம் ...) - # 2001-9999 → fused prefix (ஐந்தாயிரத்து ...) + space + remainder - one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") - one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") - fused_thousands_exact = pynini.union( - pynini.cross("2", "இரண்டாயிரம்"), - pynini.cross("3", "மூன்றாயிரம்"), - pynini.cross("4", "நான்காயிரம்"), - pynini.cross("5", "ஐந்தாயிரம்"), - pynini.cross("6", "ஆறாயிரம்"), - pynini.cross("7", "ஏழாயிரம்"), - pynini.cross("8", "எட்டாயிரம்"), - pynini.cross("9", "ஒன்பதாயிரம்"), - pynini.cross("௨", "இரண்டாயிரம்"), - pynini.cross("௩", "மூன்றாயிரம்"), - pynini.cross("௪", "நான்காயிரம்"), - pynini.cross("௫", "ஐந்தாயிரம்"), - pynini.cross("௬", "ஆறாயிரம்"), - pynini.cross("௭", "ஏழாயிரம்"), - pynini.cross("௮", "எட்டாயிரம்"), - pynini.cross("௯", "ஒன்பதாயிரம்"), - ).optimize() - fused_thousands_prefix = pynini.union( - pynini.cross("2", "இரண்டாயிரத்து"), - pynini.cross("3", "மூன்றாயிரத்து"), - pynini.cross("4", "நான்காயிரத்து"), - pynini.cross("5", "ஐந்தாயிரத்து"), - pynini.cross("6", "ஆறாயிரத்து"), - pynini.cross("7", "ஏழாயிரத்து"), - pynini.cross("8", "எட்டாயிரத்து"), - pynini.cross("9", "ஒன்பதாயிரத்து"), - pynini.cross("௨", "இரண்டாயிரத்து"), - pynini.cross("௩", "மூன்றாயிரத்து"), - pynini.cross("௪", "நான்காயிரத்து"), - pynini.cross("௫", "ஐந்தாயிரத்து"), - pynini.cross("௬", "ஆறாயிரத்து"), - pynini.cross("௭", "ஏழாயிரத்து"), - pynini.cross("௮", "எட்டாயிரத்து"), - pynini.cross("௯", "ஒன்பதாயிரத்து"), - ).optimize() - # 1000 exact - graph_thousands = one_k_exact + (zero_delete ** 3) - # 1001-1009 - graph_thousands |= one_k_tail + (zero_delete ** 2) + pynutil.insert(" ") + single_digit - # 1010-1099 - graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties - # 1100-1999 - graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds - # 2000-9000 exact - graph_thousands |= fused_thousands_exact + (zero_delete ** 3) - # 2001-9009 - graph_thousands |= fused_thousands_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit - # 2010-9099 - graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties - # 2100-9999 - graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds - graph_thousands = graph_thousands.optimize() - self.graph_thousands = graph_thousands - # TEN-THOUSANDS GRAPH - # e.g. 55000 → ஐம்பத்தைந்தாயிரம், 55199 → ஐம்பத்தைந்தாயிரத்து ... - # teens_and_ties already covers 10-99; we fuse them with ஆயிரம்/ஆயிரத்து - suffix_ten_k_exact = pynutil.insert("ஆயிரம்") - suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") - # exact ten-thousands (X0000 where X is a two-digit teens/ties) - graph_ten_thousands = create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) - # +single digit tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) - # +teens tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) - # +hundreds tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) - graph_ten_thousands = graph_ten_thousands.optimize() - self.graph_ten_thousands = graph_ten_thousands - - # LAKHS — இலட்சம் / இலட்சத்து - suffix_lakhs = pynutil.insert(" இலட்சம்") - suffix_lakhs_tail = pynutil.insert(" இலட்சத்து") - digit_one_as_oru = pynini.union( - pynini.cross("1", "ஒன்று"), - pynini.cross("௧", "ஒன்று"), - pynini.cross("2", "இரண்டு"), - pynini.cross("3", "மூன்று"), - pynini.cross("4", "நான்கு"), - pynini.cross("5", "ஐந்து"), - pynini.cross("6", "ஆறு"), - pynini.cross("7", "ஏழு"), - pynini.cross("8", "எட்டு"), - pynini.cross("9", "ஒன்பது"), - pynini.cross("௨", "இரண்டு"), - pynini.cross("௩", "மூன்று"), - pynini.cross("௪", "நான்கு"), - pynini.cross("௫", "ஐந்து"), - pynini.cross("௬", "ஆறு"), - pynini.cross("௭", "ஏழு"), - pynini.cross("௮", "எட்டு"), - pynini.cross("௯", "ஒன்பது"), - ).optimize() - graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_lakhs = graph_lakhs.optimize() - self.graph_lakhs = graph_lakhs - graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_ten_lakhs.optimize() - self.graph_ten_lakhs = graph_ten_lakhs + """ + Finite state transducer for classifying cardinals, e.g. + -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) + """ + + def __init__(self, deterministic: bool = True, lm: bool = False): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) + teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) + teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) + teens_ties = pynini.union(teens_ties_hi, teens_ties_en) + teens_and_ties = pynutil.add_weight(teens_ties, -0.1) + self.digit = digit + self.zero = zero + self.hundred_ta = hundred_ta + self.teens_and_ties = teens_and_ties + # single_digit early — covers ASCII + Tamil digits + zero + single_digit = digit | zero + # Single digit graph for digit-by-digit reading + single_digit_graph = digit | zero + self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) + zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + + def create_graph_suffix(digit_graph, suffix, zeros_counts): + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + return digit_graph + (z**zeros_counts) + suffix + + def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): + ins = pynutil.insert(" ") + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + ins + sub_graph + return digit_graph + suffix + (z**zeros_counts) + ins + sub_graph + + # HUNDREDS GRAPH + # Use hundred_ta.tsv for fused exact hundreds (நூற்று, இருநூற்று, ... + # எட்டுநூற்று, எழுநூற்று, நானூற்று etc.) + # For 101-199: நூற்று + space + remainder + # For 201-999: fused prefix (no space) + space + remainder + # Fused hundred prefix for composites (201-999 non-exact) + fused_hundred_prefix = pynini.union( + pynini.cross("2", "இருநூற்று"), + pynini.cross("3", "முந்நூற்று"), + pynini.cross("4", "நானூற்று"), + pynini.cross("5", "ஐந்நூற்று"), + pynini.cross("6", "அறுநூற்று"), + pynini.cross("7", "எழுநூற்று"), + pynini.cross("8", "எட்டுநூற்று"), + pynini.cross("9", "ஒன்பதுநூற்று"), + pynini.cross("௨", "இருநூற்று"), + pynini.cross("௩", "முந்நூற்று"), + pynini.cross("௪", "நானூற்று"), + pynini.cross("௫", "ஐந்நூற்று"), + pynini.cross("௬", "அறுநூற்று"), + pynini.cross("௭", "எழுநூற்று"), + pynini.cross("௮", "எட்டுநூற்று"), + pynini.cross("௯", "ஒன்பதுநூற்று"), + ).optimize() + # Start with fused exact forms from hundred_ta.tsv + exact_hundred = pynutil.add_weight( + pynini.union( + pynini.cross("100", "நூறு"), + pynini.cross("௧௦௦", "நூறு"), + ).optimize(), + -1.0, + ) + graph_hundreds = hundred_ta + # 101-109 (ASCII and Tamil digits) + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + zero_delete + + pynutil.insert(" ") + + single_digit + ) + # 110-119 + graph_hundreds |= (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + pynutil.insert(" ") + teens_ties + # 201-209, 301-309 ... 901-909 + graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit + # 210-219 ... 910-919 + graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties + # 220-299 ... 920-999 (two-digit tie/tens tail already in teens_ties) + # teens_ties handles 20,21,...99 so this covers the remaining composites + graph_hundreds = graph_hundreds.optimize() + self.graph_hundreds = graph_hundreds + # THOUSANDS GRAPH + # 1000 → ஆயிரம் (exact, no leading ஒன்று) + # 1001-1099 → ஆயிரத்து + space + remainder + # 1100-1999 → ஆயிரத்து + space + graph_hundreds + # 2000-9000 → fused exact (இரண்டாயிரம், மூன்றாயிரம் ...) + # 2001-9999 → fused prefix (ஐந்தாயிரத்து ...) + space + remainder + one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") + one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") + fused_thousands_exact = pynini.union( + pynini.cross("2", "இரண்டாயிரம்"), + pynini.cross("3", "மூன்றாயிரம்"), + pynini.cross("4", "நான்காயிரம்"), + pynini.cross("5", "ஐந்தாயிரம்"), + pynini.cross("6", "ஆறாயிரம்"), + pynini.cross("7", "ஏழாயிரம்"), + pynini.cross("8", "எட்டாயிரம்"), + pynini.cross("9", "ஒன்பதாயிரம்"), + pynini.cross("௨", "இரண்டாயிரம்"), + pynini.cross("௩", "மூன்றாயிரம்"), + pynini.cross("௪", "நான்காயிரம்"), + pynini.cross("௫", "ஐந்தாயிரம்"), + pynini.cross("௬", "ஆறாயிரம்"), + pynini.cross("௭", "ஏழாயிரம்"), + pynini.cross("௮", "எட்டாயிரம்"), + pynini.cross("௯", "ஒன்பதாயிரம்"), + ).optimize() + fused_thousands_prefix = pynini.union( + pynini.cross("2", "இரண்டாயிரத்து"), + pynini.cross("3", "மூன்றாயிரத்து"), + pynini.cross("4", "நான்காயிரத்து"), + pynini.cross("5", "ஐந்தாயிரத்து"), + pynini.cross("6", "ஆறாயிரத்து"), + pynini.cross("7", "ஏழாயிரத்து"), + pynini.cross("8", "எட்டாயிரத்து"), + pynini.cross("9", "ஒன்பதாயிரத்து"), + pynini.cross("௨", "இரண்டாயிரத்து"), + pynini.cross("௩", "மூன்றாயிரத்து"), + pynini.cross("௪", "நான்காயிரத்து"), + pynini.cross("௫", "ஐந்தாயிரத்து"), + pynini.cross("௬", "ஆறாயிரத்து"), + pynini.cross("௭", "ஏழாயிரத்து"), + pynini.cross("௮", "எட்டாயிரத்து"), + pynini.cross("௯", "ஒன்பதாயிரத்து"), + ).optimize() + # 1000 exact + graph_thousands = one_k_exact + (zero_delete**3) + # 1001-1009 + graph_thousands |= one_k_tail + (zero_delete**2) + pynutil.insert(" ") + single_digit + # 1010-1099 + graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties + # 1100-1999 + graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds + # 2000-9000 exact + graph_thousands |= fused_thousands_exact + (zero_delete**3) + # 2001-9009 + graph_thousands |= fused_thousands_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit + # 2010-9099 + graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties + # 2100-9999 + graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds + graph_thousands = graph_thousands.optimize() + self.graph_thousands = graph_thousands + # TEN-THOUSANDS GRAPH + # e.g. 55000 → ஐம்பத்தைந்தாயிரம், 55199 → ஐம்பத்தைந்தாயிரத்து ... + # teens_and_ties already covers 10-99; we fuse them with ஆயிரம்/ஆயிரத்து + suffix_ten_k_exact = pynutil.insert("ஆயிரம்") + suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") + # exact ten-thousands (X0000 where X is a two-digit teens/ties) + graph_ten_thousands = create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) + # +single digit tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) + # +teens tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) + # +hundreds tail + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) + graph_ten_thousands = graph_ten_thousands.optimize() + self.graph_ten_thousands = graph_ten_thousands + + # LAKHS — இலட்சம் / இலட்சத்து + suffix_lakhs = pynutil.insert(" இலட்சம்") + suffix_lakhs_tail = pynutil.insert(" இலட்சத்து") + digit_one_as_oru = pynini.union( + pynini.cross("1", "ஒன்று"), + pynini.cross("௧", "ஒன்று"), + pynini.cross("2", "இரண்டு"), + pynini.cross("3", "மூன்று"), + pynini.cross("4", "நான்கு"), + pynini.cross("5", "ஐந்து"), + pynini.cross("6", "ஆறு"), + pynini.cross("7", "ஏழு"), + pynini.cross("8", "எட்டு"), + pynini.cross("9", "ஒன்பது"), + pynini.cross("௨", "இரண்டு"), + pynini.cross("௩", "மூன்று"), + pynini.cross("௪", "நான்கு"), + pynini.cross("௫", "ஐந்து"), + pynini.cross("௬", "ஆறு"), + pynini.cross("௭", "ஏழு"), + pynini.cross("௮", "எட்டு"), + pynini.cross("௯", "ஒன்பது"), + ).optimize() + graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_lakhs = graph_lakhs.optimize() + self.graph_lakhs = graph_lakhs + graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_ten_lakhs.optimize() + self.graph_ten_lakhs = graph_ten_lakhs + + # CRORES — கோடி / கோடியே + suffix_crores = pynutil.insert(" கோடி") + suffix_crores_tail = pynutil.insert(" கோடியே") + graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores = graph_crores.optimize() + graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_crores.optimize() + + # ARABS + suffix_arabs = pynutil.insert(" அரபு") + graph_arabs = create_graph_suffix(digit_one_as_oru, suffix_arabs, 9) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 8, single_digit) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 7, teens_ties) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 6, graph_hundreds) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 5, graph_thousands) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 4, graph_ten_thousands) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 3, graph_lakhs) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 2, graph_ten_lakhs) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 1, graph_crores) + graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 0, graph_ten_crores) + graph_arabs.optimize() + graph_ten_arabs = create_graph_suffix(teens_and_ties, suffix_arabs, 9) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 8, single_digit) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 7, teens_ties) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 6, graph_hundreds) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 5, graph_thousands) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 4, graph_ten_thousands) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 3, graph_lakhs) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 2, graph_ten_lakhs) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 1, graph_crores) + graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 0, graph_ten_crores) + graph_ten_arabs.optimize() + + # KHARABS + suffix_kharabs = pynutil.insert(" கரபு") + graph_kharabs = create_graph_suffix(digit_one_as_oru, suffix_kharabs, 11) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 10, single_digit) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 9, teens_ties) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 8, graph_hundreds) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 7, graph_thousands) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 6, graph_ten_thousands) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 5, graph_lakhs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 4, graph_ten_lakhs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 3, graph_crores) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 2, graph_ten_crores) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 1, graph_arabs) + graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 0, graph_ten_arabs) + graph_kharabs.optimize() + graph_ten_kharabs = create_graph_suffix(teens_and_ties, suffix_kharabs, 11) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 10, single_digit) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 9, teens_ties) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 8, graph_hundreds) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 7, graph_thousands) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 6, graph_ten_thousands) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 5, graph_lakhs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 4, graph_ten_lakhs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 3, graph_crores) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 2, graph_ten_crores) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 1, graph_arabs) + graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 0, graph_ten_arabs) + graph_ten_kharabs.optimize() - # CRORES — கோடி / கோடியே - suffix_crores = pynutil.insert(" கோடி") - suffix_crores_tail = pynutil.insert(" கோடியே") - graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores = graph_crores.optimize() - graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_crores.optimize() + # NILS + suffix_nils = pynutil.insert(" நீல்") + graph_nils = create_graph_suffix(digit_one_as_oru, suffix_nils, 13) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 12, single_digit) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 11, teens_ties) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 10, graph_hundreds) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 9, graph_thousands) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 8, graph_ten_thousands) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 7, graph_lakhs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 6, graph_ten_lakhs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 5, graph_crores) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 4, graph_ten_crores) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 3, graph_arabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 2, graph_ten_arabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 1, graph_kharabs) + graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 0, graph_ten_kharabs) + graph_nils.optimize() + graph_ten_nils = create_graph_suffix(teens_and_ties, suffix_nils, 13) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 12, single_digit) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 11, teens_ties) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 10, graph_hundreds) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 9, graph_thousands) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 8, graph_ten_thousands) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 7, graph_lakhs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 6, graph_ten_lakhs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 5, graph_crores) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 4, graph_ten_crores) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 3, graph_arabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 2, graph_ten_arabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 1, graph_kharabs) + graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 0, graph_ten_kharabs) + graph_ten_nils.optimize() - # ARABS - suffix_arabs = pynutil.insert(" அரபு") - graph_arabs = create_graph_suffix(digit_one_as_oru, suffix_arabs, 9) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 8, single_digit) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 7, teens_ties) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 6, graph_hundreds) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 5, graph_thousands) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 4, graph_ten_thousands) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 3, graph_lakhs) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 2, graph_ten_lakhs) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 1, graph_crores) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 0, graph_ten_crores) - graph_arabs.optimize() - graph_ten_arabs = create_graph_suffix(teens_and_ties, suffix_arabs, 9) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 8, single_digit) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 7, teens_ties) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 6, graph_hundreds) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 5, graph_thousands) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 4, graph_ten_thousands) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 3, graph_lakhs) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 2, graph_ten_lakhs) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 1, graph_crores) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 0, graph_ten_crores) - graph_ten_arabs.optimize() - - # KHARABS - suffix_kharabs = pynutil.insert(" கரபு") - graph_kharabs = create_graph_suffix(digit_one_as_oru, suffix_kharabs, 11) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 10, single_digit) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 9, teens_ties) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 8, graph_hundreds) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 7, graph_thousands) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 6, graph_ten_thousands) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 5, graph_lakhs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 4, graph_ten_lakhs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 3, graph_crores) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 2, graph_ten_crores) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 1, graph_arabs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 0, graph_ten_arabs) - graph_kharabs.optimize() - graph_ten_kharabs = create_graph_suffix(teens_and_ties, suffix_kharabs, 11) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 10, single_digit) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 9, teens_ties) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 8, graph_hundreds) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 7, graph_thousands) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 6, graph_ten_thousands) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 5, graph_lakhs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 4, graph_ten_lakhs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 3, graph_crores) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 2, graph_ten_crores) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 1, graph_arabs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 0, graph_ten_arabs) - graph_ten_kharabs.optimize() + # PADMAS + suffix_padmas = pynutil.insert(" பத்மம்") + graph_padmas = create_graph_suffix(digit_one_as_oru, suffix_padmas, 15) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 14, single_digit) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 13, teens_ties) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 12, graph_hundreds) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 11, graph_thousands) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 10, graph_ten_thousands) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 9, graph_lakhs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 8, graph_ten_lakhs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 7, graph_crores) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 6, graph_ten_crores) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 5, graph_arabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 4, graph_ten_arabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 3, graph_kharabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 2, graph_ten_kharabs) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 1, graph_nils) + graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 0, graph_ten_nils) + graph_padmas.optimize() + graph_ten_padmas = create_graph_suffix(teens_and_ties, suffix_padmas, 15) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 14, single_digit) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 13, teens_ties) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 12, graph_hundreds) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 11, graph_thousands) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 10, graph_ten_thousands) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 9, graph_lakhs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 8, graph_ten_lakhs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 7, graph_crores) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 6, graph_ten_crores) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 5, graph_arabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 4, graph_ten_arabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 3, graph_kharabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 2, graph_ten_kharabs) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 1, graph_nils) + graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 0, graph_ten_nils) + graph_ten_padmas.optimize() - # NILS - suffix_nils = pynutil.insert(" நீல்") - graph_nils = create_graph_suffix(digit_one_as_oru, suffix_nils, 13) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 12, single_digit) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 11, teens_ties) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 10, graph_hundreds) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 9, graph_thousands) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 8, graph_ten_thousands) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 7, graph_lakhs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 6, graph_ten_lakhs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 5, graph_crores) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 4, graph_ten_crores) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 3, graph_arabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 2, graph_ten_arabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 1, graph_kharabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 0, graph_ten_kharabs) - graph_nils.optimize() - graph_ten_nils = create_graph_suffix(teens_and_ties, suffix_nils, 13) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 12, single_digit) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 11, teens_ties) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 10, graph_hundreds) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 9, graph_thousands) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 8, graph_ten_thousands) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 7, graph_lakhs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 6, graph_ten_lakhs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 5, graph_crores) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 4, graph_ten_crores) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 3, graph_arabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 2, graph_ten_arabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 1, graph_kharabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 0, graph_ten_kharabs) - graph_ten_nils.optimize() - - # PADMAS - suffix_padmas = pynutil.insert(" பத்மம்") - graph_padmas = create_graph_suffix(digit_one_as_oru, suffix_padmas, 15) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 14, single_digit) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 13, teens_ties) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 12, graph_hundreds) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 11, graph_thousands) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 10, graph_ten_thousands) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 9, graph_lakhs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 8, graph_ten_lakhs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 7, graph_crores) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 6, graph_ten_crores) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 5, graph_arabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 4, graph_ten_arabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 3, graph_kharabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 2, graph_ten_kharabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 1, graph_nils) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 0, graph_ten_nils) - graph_padmas.optimize() - graph_ten_padmas = create_graph_suffix(teens_and_ties, suffix_padmas, 15) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 14, single_digit) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 13, teens_ties) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 12, graph_hundreds) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 11, graph_thousands) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 10, graph_ten_thousands) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 9, graph_lakhs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 8, graph_ten_lakhs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 7, graph_crores) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 6, graph_ten_crores) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 5, graph_arabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 4, graph_ten_arabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 3, graph_kharabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 2, graph_ten_kharabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 1, graph_nils) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 0, graph_ten_nils) - graph_ten_padmas.optimize() - - # SHANKHS - suffix_shankhs = pynutil.insert(" சங்கம்") - graph_shankhs = create_graph_suffix(digit_one_as_oru, suffix_shankhs, 17) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 16, single_digit) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 15, teens_ties) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 14, graph_hundreds) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 13, graph_thousands) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 12, graph_ten_thousands) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 11, graph_lakhs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 10, graph_ten_lakhs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 9, graph_crores) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 8, graph_ten_crores) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 7, graph_arabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 6, graph_ten_arabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 5, graph_kharabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 4, graph_ten_kharabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 3, graph_nils) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 2, graph_ten_nils) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 1, graph_padmas) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 0, graph_ten_padmas) - graph_shankhs.optimize() - graph_ten_shankhs = create_graph_suffix(teens_and_ties, suffix_shankhs, 17) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 16, single_digit) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 15, teens_ties) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 14, graph_hundreds) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 13, graph_thousands) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 12, graph_ten_thousands) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 11, graph_lakhs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 10, graph_ten_lakhs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 9, graph_crores) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 8, graph_ten_crores) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 7, graph_arabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 6, graph_ten_arabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 5, graph_kharabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 4, graph_ten_kharabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 3, graph_nils) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 2, graph_ten_nils) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 1, graph_padmas) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 0, graph_ten_padmas) - graph_ten_shankhs.optimize() + # SHANKHS + suffix_shankhs = pynutil.insert(" சங்கம்") + graph_shankhs = create_graph_suffix(digit_one_as_oru, suffix_shankhs, 17) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 16, single_digit) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 15, teens_ties) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 14, graph_hundreds) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 13, graph_thousands) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 12, graph_ten_thousands) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 11, graph_lakhs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 10, graph_ten_lakhs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 9, graph_crores) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 8, graph_ten_crores) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 7, graph_arabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 6, graph_ten_arabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 5, graph_kharabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 4, graph_ten_kharabs) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 3, graph_nils) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 2, graph_ten_nils) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 1, graph_padmas) + graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 0, graph_ten_padmas) + graph_shankhs.optimize() + graph_ten_shankhs = create_graph_suffix(teens_and_ties, suffix_shankhs, 17) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 16, single_digit) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 15, teens_ties) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 14, graph_hundreds) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 13, graph_thousands) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 12, graph_ten_thousands) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 11, graph_lakhs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 10, graph_ten_lakhs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 9, graph_crores) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 8, graph_ten_crores) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 7, graph_arabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 6, graph_ten_arabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 5, graph_kharabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 4, graph_ten_kharabs) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 3, graph_nils) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 2, graph_ten_nils) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 1, graph_padmas) + graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 0, graph_ten_padmas) + graph_ten_shankhs.optimize() - # LEADING ZERO and FINAL GRAPH - graph_leading_zero = zero + insert_space + single_digit - graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) - graph_without_leading_zeros = ( - digit - | zero - | teens_and_ties - | exact_hundred - | graph_hundreds - | graph_thousands - | graph_ten_thousands - | graph_lakhs - | graph_ten_lakhs - | graph_crores - | graph_ten_crores - | graph_arabs - | graph_ten_arabs - | graph_kharabs - | graph_ten_kharabs - | graph_nils - | graph_ten_nils - | graph_padmas - | graph_ten_padmas - | graph_shankhs - | graph_ten_shankhs - ) - self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() - cardinal_with_leading_zeros = pynini.compose( - NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph - ) - cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) - final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros - optional_minus_graph = pynini.closure( - pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1 - ) - self.final_graph = final_graph.optimize() - final_graph = ( - optional_minus_graph - + pynutil.insert("integer: \"") - + self.final_graph - + pynutil.insert("\"") - ) - final_graph = self.add_tokens(final_graph) - self.fst = final_graph \ No newline at end of file + # LEADING ZERO and FINAL GRAPH + graph_leading_zero = zero + insert_space + single_digit + graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) + graph_without_leading_zeros = ( + digit + | zero + | teens_and_ties + | exact_hundred + | graph_hundreds + | graph_thousands + | graph_ten_thousands + | graph_lakhs + | graph_ten_lakhs + | graph_crores + | graph_ten_crores + | graph_arabs + | graph_ten_arabs + | graph_kharabs + | graph_ten_kharabs + | graph_nils + | graph_ten_nils + | graph_padmas + | graph_ten_padmas + | graph_shankhs + | graph_ten_shankhs + ) + self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() + cardinal_with_leading_zeros = pynini.compose( + NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph + ) + cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) + final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros + optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) + self.final_graph = final_graph.optimize() + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph diff --git a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py index 86fdc3421..7d173ff2f 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py +++ b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py @@ -1,14 +1,14 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# +# You may obtain a copy of the License at +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. @@ -27,6 +27,7 @@ generator_main, ) from nemo_text_processing.text_normalization.ta.taggers.cardinal import CardinalFst + # from nemo_text_processing.text_normalization.hi.taggers.date import DateFst # from nemo_text_processing.text_normalization.hi.taggers.decimal import DecimalFst # from nemo_text_processing.text_normalization.hi.taggers.electronic import ElectronicFst @@ -35,6 +36,7 @@ # from nemo_text_processing.text_normalization.hi.taggers.money import MoneyFst # from nemo_text_processing.text_normalization.hi.taggers.ordinal import OrdinalFst from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst + # from nemo_text_processing.text_normalization.hi.taggers.telephone import TelephoneFst # from nemo_text_processing.text_normalization.hi.taggers.time import TimeFst # from nemo_text_processing.text_normalization.hi.taggers.whitelist import WhiteListFst @@ -118,7 +120,7 @@ def __init__( # electronic_graph = electronic.fst classify = ( - # pynutil.add_weight(whitelist_graph, 1.01)| + # pynutil.add_weight(whitelist_graph, 1.01)| pynutil.add_weight(cardinal_graph, 1.1) # | pynutil.add_weight(decimal_graph, 1.1) # | pynutil.add_weight(fraction_graph, 1.1) diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py b/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py index 2f2f217f3..4fc25d0d3 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/__init__.py @@ -10,4 +10,4 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. \ No newline at end of file +# limitations under the License. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py index dca601f77..e3012e7bd 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py @@ -14,16 +14,17 @@ from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst from nemo_text_processing.text_normalization.ta.verbalizers.cardinal import CardinalFst -#from nemo_text_processing.text_normalization.ta.verbalizers.date import DateFst -#from nemo_text_processing.text_normalization.hi.verbalizers.decimal import DecimalFst -#from nemo_text_processing.text_normalization.hi.verbalizers.electronic import ElectronicFst -#from nemo_text_processing.text_normalization.hi.verbalizers.fraction import FractionFst -#from nemo_text_processing.text_normalization.hi.verbalizers.measure import MeasureFst -#from nemo_text_processing.text_normalization.hi.verbalizers.money import MoneyFst -#from nemo_text_processing.text_normalization.hi.verbalizers.ordinal import OrdinalFst -#from nemo_text_processing.text_normalization.hi.verbalizers.telephone import TelephoneFst -#from nemo_text_processing.text_normalization.hi.verbalizers.time import TimeFst -#from nemo_text_processing.text_normalization.ta.verbalizers.whitelist import WhiteListFst + +# from nemo_text_processing.text_normalization.ta.verbalizers.date import DateFst +# from nemo_text_processing.text_normalization.hi.verbalizers.decimal import DecimalFst +# from nemo_text_processing.text_normalization.hi.verbalizers.electronic import ElectronicFst +# from nemo_text_processing.text_normalization.hi.verbalizers.fraction import FractionFst +# from nemo_text_processing.text_normalization.hi.verbalizers.measure import MeasureFst +# from nemo_text_processing.text_normalization.hi.verbalizers.money import MoneyFst +# from nemo_text_processing.text_normalization.hi.verbalizers.ordinal import OrdinalFst +# from nemo_text_processing.text_normalization.hi.verbalizers.telephone import TelephoneFst +# from nemo_text_processing.text_normalization.hi.verbalizers.time import TimeFst +# from nemo_text_processing.text_normalization.ta.verbalizers.whitelist import WhiteListFst class VerbalizeFst(GraphFst): @@ -42,10 +43,7 @@ def __init__(self, deterministic: bool = True): cardinal = CardinalFst(deterministic=deterministic) cardinal_graph = cardinal.fst - - graph = ( - cardinal_graph - - ) + + graph = cardinal_graph self.fst = graph diff --git a/run_cardinal_tests.py b/run_cardinal_tests.py index d7224ff74..35d36567d 100644 --- a/run_cardinal_tests.py +++ b/run_cardinal_tests.py @@ -1,48 +1,46 @@ -# run_cardinal_tests.py -- simple checker for the Cardinal exercise. -# Usage (from the repo root, inside your conda env): -# python run_cardinal_tests.py -# Example: -# python run_cardinal_tests.py LANGCODE DIRECTION test_cases_cardinal.txt -import sys -import importlib -import pynini - - -def apply_fst(fst, text): - lattice = text @ fst - if lattice.num_states() == 0: - return None # input was rejected by the grammar - out = pynini.shortestpath(lattice) - return out.string() if out.num_states() else None - - -def main(): - lang, direction, path = sys.argv[1], sys.argv[2], sys.argv[3] - base = "text_normalization" if direction == "tn" else "inverse_text_normalization" - tagger = importlib.import_module( - f"nemo_text_processing.{base}.{lang}.taggers.cardinal").CardinalFst().fst - verbalizer = importlib.import_module( - f"nemo_text_processing.{base}.{lang}.verbalizers.cardinal").CardinalFst().fst - - passed = failed = 0 - with open(path, encoding="utf-8") as f: - for line in f: - line = line.rstrip("\n") - if not line.strip() or "~" not in line: - continue - inp, expected = [s.strip() for s in line.split("~", 1)] - tagged = apply_fst(tagger, inp) - result = apply_fst(verbalizer, tagged) if tagged is not None else None - if result == expected: - passed += 1 - else: - failed += 1 - print(f"FAIL: {inp!r} -> got {result!r}, expected {expected!r}") - - print(f"\n{passed} passed, {failed} failed.") - sys.exit(1 if failed else 0) - - -if __name__ == "__main__": - main() - \ No newline at end of file +# run_cardinal_tests.py -- simple checker for the Cardinal exercise. +# Usage (from the repo root, inside your conda env): +# python run_cardinal_tests.py +# Example: +# python run_cardinal_tests.py LANGCODE DIRECTION test_cases_cardinal.txt +import importlib +import sys + +import pynini + + +def apply_fst(fst, text): + lattice = text @ fst + if lattice.num_states() == 0: + return None # input was rejected by the grammar + out = pynini.shortestpath(lattice) + return out.string() if out.num_states() else None + + +def main(): + lang, direction, path = sys.argv[1], sys.argv[2], sys.argv[3] + base = "text_normalization" if direction == "tn" else "inverse_text_normalization" + tagger = importlib.import_module(f"nemo_text_processing.{base}.{lang}.taggers.cardinal").CardinalFst().fst + verbalizer = importlib.import_module(f"nemo_text_processing.{base}.{lang}.verbalizers.cardinal").CardinalFst().fst + + passed = failed = 0 + with open(path, encoding="utf-8") as f: + for line in f: + line = line.rstrip("\n") + if not line.strip() or "~" not in line: + continue + inp, expected = [s.strip() for s in line.split("~", 1)] + tagged = apply_fst(tagger, inp) + result = apply_fst(verbalizer, tagged) if tagged is not None else None + if result == expected: + passed += 1 + else: + failed += 1 + print(f"FAIL: {inp!r} -> got {result!r}, expected {expected!r}") + + print(f"\n{passed} passed, {failed} failed.") + sys.exit(1 if failed else 0) + + +if __name__ == "__main__": + main() diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index 58b20abd7..4b9ba5cbd 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -25,7 +25,7 @@ class TestCardinal: normalizer = Normalizer( input_case='cased', lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False ) - #inverse_normalizer = InverseNormalizer(lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False) + # inverse_normalizer = InverseNormalizer(lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False) @parameterized.expand(parse_test_case_file('ta/data_text_normalization/test_cases_cardinal.txt')) @pytest.mark.run_only_on('CPU') @@ -34,9 +34,9 @@ def test_norm(self, test_input, expected): pred = self.normalizer.normalize(test_input, verbose=False) assert pred.strip() == expected.strip() - #@parameterized.expand(parse_test_case_file('ta/data_inverse_text_normalization/test_cases_cardinal.txt')) - #@pytest.mark.run_only_on('CPU') - #@pytest.mark.unit - #def test_denorm(self, test_input, expected): - #pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) - #assert pred == expected + # @parameterized.expand(parse_test_case_file('ta/data_inverse_text_normalization/test_cases_cardinal.txt')) + # @pytest.mark.run_only_on('CPU') + # @pytest.mark.unit + # def test_denorm(self, test_input, expected): + # pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) + # assert pred == expected From eaf2223540937fd85e15e285d8e5195887808938 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 13:48:56 +0530 Subject: [PATCH 10/29] Cardinal updated file Signed-off-by: surendran-246 --- nemo_text_processing/text_normalization/normalize.py | 2 +- nemo_text_processing/text_normalization/run_evaluate.py | 2 +- .../text_normalization/ta/verbalizers/post_processing.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nemo_text_processing/text_normalization/normalize.py b/nemo_text_processing/text_normalization/normalize.py index efb13bf4a..34834f081 100644 --- a/nemo_text_processing/text_normalization/normalize.py +++ b/nemo_text_processing/text_normalization/normalize.py @@ -1,4 +1,4 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/run_evaluate.py b/nemo_text_processing/text_normalization/run_evaluate.py index d0d5bada3..fd0fac207 100644 --- a/nemo_text_processing/text_normalization/run_evaluate.py +++ b/nemo_text_processing/text_normalization/run_evaluate.py @@ -1,4 +1,4 @@ -# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py index 9afad60e3..2d05b7cea 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From c0e51f13c28b0c0c59754776ba137f5eab02b2ef Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 7 Jul 2026 15:36:20 +0530 Subject: [PATCH 11/29] Updated cardinal Signed-off-by: surendran-246 --- blind_testcases_ta | 1398 ------------------------------- "eval \"$(ssh-agent -s)\" " | 7 - "eval \"$(ssh-agent -s)\" .pub" | 1 - run_cardinal_tests.py | 46 - 4 files changed, 1452 deletions(-) delete mode 100644 blind_testcases_ta delete mode 100644 "eval \"$(ssh-agent -s)\" " delete mode 100644 "eval \"$(ssh-agent -s)\" .pub" delete mode 100644 run_cardinal_tests.py diff --git a/blind_testcases_ta b/blind_testcases_ta deleted file mode 100644 index 4a2911adf..000000000 --- a/blind_testcases_ta +++ /dev/null @@ -1,1398 +0,0 @@ -CARDINAL ௪ சிக்ஸர்கள் ௧௪ பவுண்டரிகள் நான்கு சிக்ஸர்கள் பதினான்கு பவுண்டரிகள் - -CARDINAL ௬ ரன்கள் எடுத்தார் ஆறு ரன்கள் எடுத்தார் - -CARDINAL ௩ கோல்கள் அடித்தார் மூன்று கோல்கள் அடித்தார் - -CARDINAL ௯ சிக்ஸர்கள் ஒன்பது சிக்ஸர்கள் - -CARDINAL ௫ பவுண்டரிகள் ஐந்து பவுண்டரிகள் - -CARDINAL ௨ சிக்ஸர்கள் ௧௨ ரன்கள் இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் - -CARDINAL ௯ புள்ளிகள் ஒன்பது புள்ளிகள் - -CARDINAL ௪ பேர் உயிரிழப்பு ௧௮ பேர் காயம் நான்கு பேர் உயிரிழப்பு பதினெட்டு பேர் காயம் - -CARDINAL ௫ கோல்கள் அடித்தனர் ஐந்து கோல்கள் அடித்தனர் - -CARDINAL ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள் மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் - -CARDINAL ௧ ஓவர் ௧௩ ரன்கள் ஒன்று ஓவர் பதிமூன்று ரன்கள் - -CARDINAL ௩ ஓவர்கள் மூன்று ஓவர்கள் - -CARDINAL ௫ கோல்கள் ஐந்து கோல்கள் - -CARDINAL ௩ ஆப்பிள்கள் மூன்று ஆப்பிள்கள் - -CARDINAL ௭ வாழைப்பழங்கள் ஏழு வாழைப்பழங்கள் - -CARDINAL ௩ தோல்வி ௧௨ வெற்றி மூன்று தோல்வி பன்னிரண்டு வெற்றி - -CARDINAL ௫ தோல்விகள் ௧ டிரா ௧௭ வெற்றிகள் ஐந்து தோல்விகள் ஒன்று டிரா பதினேழு வெற்றிகள் - -CARDINAL ௮ போட்டிகள் டிரா எட்டு போட்டிகள் டிரா - -CARDINAL ௪ பவுண்டரிகள் நான்கு பவுண்டரிகள் - -CARDINAL ௮ சிக்ஸர்கள் ௨ அவுட் எட்டு சிக்ஸர்கள் இரண்டு அவுட் - -CARDINAL ௬ வீரர்கள் அவுட் ஆறு வீரர்கள் அவுட் - -CARDINAL ௪ ரன்கள் ௩ பவுண்டரிகள் நான்கு ரன்கள் மூன்று பவுண்டரிகள் - -CARDINAL ஒன்பிளஸ் ௮ ப்ரோ ஒன்பிளஸ் எட்டு ப்ரோ - -CARDINAL ௫ சார்ஜர்கள் ஐந்து சார்ஜர்கள் - -CARDINAL ௪ ஓவரில் ௧௭ ரன்கள் நான்கு ஓவரில் பதினேழு ரன்கள் - -CARDINAL ௫ சாக்லேட்டுகள் ௯ டாபிகள் ஐந்து சாக்லேட்டுகள் ஒன்பது டாபிகள் - -CARDINAL ௬ பேட்ஸ்மேன்கள் ௨ பவுலர்கள் ஆறு பேட்ஸ்மேன்கள் இரண்டு பவுலர்கள் - -CARDINAL ௧ விக்கெட் கீப்பர் ஒன்று விக்கெட் கீப்பர் - -CARDINAL ௮ கேட்ச் அவுட் எட்டு கேட்ச் அவுட் - -CARDINAL ௫ விக்கெட்டுக்கு ௧௦ ரன்கள் ஐந்து விக்கெட்டுக்கு பத்து ரன்கள் - -CARDINAL ௭ வெற்றி ௨ டிரா ஏழு வெற்றி இரண்டு டிரா - -CARDINAL ௨ பவுண்டரிகள் இரண்டு பவுண்டரிகள் - -CARDINAL ௬ ரன்கள் ௫ விக்கெட்டுகள் ஆறு ரன்கள் ஐந்து விக்கெட்டுகள் - -CARDINAL ௭ பந்துகள் ௧௧ ரன்கள் ஏழு பந்துகள் பதினொன்று ரன்கள் - -CARDINAL ௬ சாக்லேட்டுகள் ௪ டாபிகள் ஆறு சாக்லேட்டுகள் நான்கு டாபிகள் - -CARDINAL ௮ வெண்கலங்கள் ௨ தங்கங்கள் எட்டு வெண்கலங்கள் இரண்டு தங்கங்கள் - -CARDINAL ௧ தங்கப் பதக்கம் ஒன்று தங்கப் பதக்கம் - -CARDINAL ௩ ரன்கள் மூன்று ரன்கள் - -CARDINAL ௫ ஓவர்கள் ஐந்து ஓவர்கள் - -CARDINAL ௬ பந்து ஆறு பந்து - -CARDINAL ௩ இன்னிங்ஸ் மூன்று இன்னிங்ஸ் - -CARDINAL வசனம் ௭ பாடம் ௧௫ வசனம் ஏழு பாடம் பதினைந்து - -CARDINAL பாடம் எண் ௨ வசனம் ௪ பாடம் எண் இரண்டு வசனம் நான்கு - -CARDINAL பக்க எண் ௮ பத்தி ௬ பக்க எண் எட்டு பத்தி ஆறு - -CARDINAL ௨ பந்துகள் ௪ ரன்கள் இரண்டு பந்துகள் நான்கு ரன்கள் - -CARDINAL ௬ விக்கெட்டுகள் ஆறு விக்கெட்டுகள் - -CARDINAL ௨ புள்ளி ௫ கோல்கள் இரண்டு புள்ளி ஐந்து கோல்கள் - -CARDINAL பாடம் ௧௦ ஸ்லோகம் ௨ பாடம் பத்து ஸ்லோகம் இரண்டு - -CARDINAL அத்தியாயம் ௫ காட்சி ௬ அத்தியாயம் ஐந்து காட்சி ஆறு - -CARDINAL ௬ கேள்விகள் ௫ தவறு ஆறு கேள்விகள் ஐந்து தவறு - -CARDINAL ௩ ரோஜா ௪ மல்லிகை ௨ சாமந்தி மூன்று ரோஜா நான்கு மல்லிகை இரண்டு சாமந்தி - -CARDINAL ௨ ஃப்ரீ ஹிட் ௧ நோ பால் இரண்டு ஃப்ரீ ஹிட் ஒன்று நோ பால் - -CARDINAL ௩ போன் ௧ சார்ஜர் மூன்று போன் ஒன்று சார்ஜர் - -CARDINAL ௬ டிரா ௭ தோல்வி ௯ வெற்றி ஆறு டிரா ஏழு தோல்வி ஒன்பது வெற்றி - -CARDINAL ௪ கார் ௨ பைக் நான்கு கார் இரண்டு பைக் - -CARDINAL ௧ கூடை ௮ பழம் ஒன்று கூடை எட்டு பழம் - -CARDINAL ௩ வரிசை ௮ நபர் மூன்று வரிசை எட்டு நபர் - -CARDINAL ௧௦ பென்சில் ௨ பேனா பத்து பென்சில் இரண்டு பேனா - -CARDINAL ௫ கட்டிடம் ஐந்து கட்டிடம் - -CARDINAL ௬ குழந்தை ஆறு குழந்தை - -CARDINAL பத்தி ௧௩ வரிசை ௪ பத்தி பதிமூன்று வரிசை நான்கு - -CARDINAL ௩ தங்கம் ௪ வெள்ளி மூன்று தங்கம் நான்கு வெள்ளி - -CARDINAL ௫ குழிகள் ஐந்து குழிகள் - -CARDINAL ௮ குப்பம் எட்டு குப்பம் - -CARDINAL ௩ லேப்டாப் மூன்று லேப்டாப் - -CARDINAL ௧ சிக்ஸர் ௨ பவுண்டரிகள் ஒன்று சிக்ஸர் இரண்டு பவுண்டரிகள் - -CARDINAL ௫ பஸ் ஐந்து பஸ் - -CARDINAL ௨ லாரி இரண்டு லாரி - -CARDINAL ௩ வண்டி மூன்று வண்டி - -CARDINAL ௬ சுறா ௩௦ முதலீட்டாளர்கள் ஆறு சுறா முப்பது முதலீட்டாளர்கள் - -CARDINAL ௨ அமைச்சர் ௫௦ பிரச்சனைகள் இரண்டு அமைச்சர் ஐம்பது பிரச்சனைகள் - -CARDINAL ௬ பவுலர் ஆறு பவுலர் - -CARDINAL ஸ்லோகம் ௩ பாடம் ௧ ஸ்லோகம் மூன்று பாடம் ஒன்று - -CARDINAL வரிசை ௬ பத்தி ௯ வரிசை ஆறு பத்தி ஒன்பது - -CARDINAL புத்தகம் ௧ பாடம் ௮ புத்தகம் ஒன்று பாடம் எட்டு - -CARDINAL சிறுகதை எண் ௨ வரிசை ௬ சிறுகதை எண் இரண்டு வரிசை ஆறு - -CARDINAL கைதி எண் ௪ கைதி எண் நான்கு - -CARDINAL பக்க எண் ௧௦ வரிசை ௨ பக்க எண் பத்து வரிசை இரண்டு - -CARDINAL ௪ மருத்துவர் நான்கு மருத்துவர் - -CARDINAL ௨ பந்து ௩ ரன் இரண்டு பந்து மூன்று ரன் - -CARDINAL புள்ளிகள் ௨ கோல் ௪ புள்ளிகள் இரண்டு கோல் நான்கு - -CARDINAL பாடம் எண் ௪ பாடம் எண் நான்கு - -CARDINAL ௮ ஓவர் எட்டு ஓவர் - -CARDINAL ௭ ரன் ௨ ஓவர் ஏழு ரன் இரண்டு ஓவர் - -CARDINAL ௪ பந்து ௮ ரன் நான்கு பந்து எட்டு ரன் - -CARDINAL ௩ பாட்டில் ௫ கிளாஸ் மூன்று பாட்டில் ஐந்து கிளாஸ் - -CARDINAL ௬ ரன் ஆறு ரன் - -CARDINAL ௬ கோல் ஆறு கோல் - -CARDINAL ௧௦ புள்ளிகள் ௩ கோல் பத்து புள்ளிகள் மூன்று கோல் - -CARDINAL ௧௪ சிக்ஸர் ௩ பவுண்டரி பதினான்கு சிக்ஸர் மூன்று பவுண்டரி - -CARDINAL ௬ ஆப்பிள் ௩ வாழைப்பழம் ஆறு ஆப்பிள் மூன்று வாழைப்பழம் - -CARDINAL ௩ மேட்ச் டிரா மூன்று மேட்ச் டிரா - -CARDINAL ௬ மேட்ச் தோல்வி ஆறு மேட்ச் தோல்வி - -CARDINAL ௯ மேட்ச் வெற்றி ஒன்பது மேட்ச் வெற்றி - -CARDINAL ஸ்லோகம் ௬ பாடம் ௯ ஸ்லோகம் ஆறு பாடம் ஒன்பது - -CARDINAL பதம் ௪ வரிசை எண் ௩ பதம் நான்கு வரிசை எண் மூன்று - -CARDINAL பாடம் ௧௦ பக்கம் ௪ பாடம் பத்து பக்கம் நான்கு - -CARDINAL ௫ கார் ௨ மோட்டார் சைக்கிள் ஐந்து கார் இரண்டு மோட்டார் சைக்கிள் - -CARDINAL ௭ புள்ளிகள் ௨ கோல் ஏழு புள்ளிகள் இரண்டு கோல் - -CARDINAL ௪ இரவு ௩ பகல் நான்கு இரவு மூன்று பகல் - -CARDINAL ௧ ஆஸ் ௧ ராணி ௫ சீட்டுகள் ஒன்று ஆஸ் ஒன்று ராணி ஐந்து சீட்டுகள் - -CARDINAL வரிசை ௨ பத்தி ௧ வரிசை இரண்டு பத்தி ஒன்று - -CARDINAL ௫ ஜோடி காலணி ஐந்து ஜோடி காலணி - -CARDINAL ௧௦ ஓவரில் ௯ ரன் பத்து ஓவரில் ஒன்பது ரன் - -CARDINAL ௮ ரன் எட்டு ரன் - -CARDINAL ௪ சிக்ஸர்கள் ௧ ஃபோர் நான்கு சிக்ஸர்கள் ஒன்று ஃபோர் - -CARDINAL பக்க எண் ௯ இன் வரிசை ௪ பக்க எண் ஒன்பது இன் வரிசை நான்கு - -CARDINAL பாரா ௧௦ இன் பகுதி ௩ பாரா பத்து இன் பகுதி மூன்று - -CARDINAL ஆயத் ௪ ருகூ ௬ ஆயத் நான்கு ருகூ ஆறு - -CARDINAL பாரா ௯ ருகூ ௬ பாரா ஒன்பது ருகூ ஆறு - -CARDINAL ௮ கால்சட்டைகள் ௯ சட்டைகள் எட்டு கால்சட்டைகள் ஒன்பது சட்டைகள் - -CARDINAL ௪ ரொட்டி ௨ காய்கறி நான்கு ரொட்டி இரண்டு காய்கறி - -CARDINAL ௩ மேட்ச் ௪ வெற்றி மூன்று மேட்ச் நான்கு வெற்றி - -CARDINAL ௪ தோல்வி ௩ வெற்றி ௧ டிரா நான்கு தோல்வி மூன்று வெற்றி ஒன்று டிரா - -CARDINAL படம் ௧௯ பாடம் ௨ படம் பத்தொன்பது பாடம் இரண்டு - -CARDINAL பாடம் ௧ பக்கம் ௧௨௨ பாடம் ஒன்று பக்கம் நூற்று இருபத்து இரண்டு - -CARDINAL பாடம் ௩ வரிசை ௬ பாடம் மூன்று வரிசை ஆறு - -CARDINAL ஸ்லோகம் ௧௦ பக்கம் ௩ ஸ்லோகம் பத்து பக்கம் மூன்று - -CARDINAL ௬ புள்ளிகள் ௩ கோல் ஆறு புள்ளிகள் மூன்று கோல் - -CARDINAL ௨ டெஸ்ட் போட்டிகள் ௬ ஒன்றுநாள் போட்டிகள் இரண்டு டெஸ்ட் போட்டிகள் ஆறு ஒன்றுநாள் போட்டிகள் - -CARDINAL ௨ ஓவரில் ௭ ரன் இரண்டு ஓவரில் ஏழு ரன் - -CARDINAL ௮ ஓவரில் ௪௫ ரன் எட்டு ஓவரில் நாற்பத்து ஐந்து ரன் - -CARDINAL ௯ ஓவரில் ௬௦ ரன் ஒன்பது ஓவரில் அறுபது ரன் - -CARDINAL ௫ போட்டிகள் ௪ வெற்றிகள் ஐந்து போட்டிகள் நான்கு வெற்றிகள் - -CARDINAL ௨ வெற்றி ௪ தோல்வி ௫ டிரா இரண்டு வெற்றி நான்கு தோல்வி ஐந்து டிரா - -CARDINAL ஸ்லோகம் ௯ பக்கம் ௭ ஸ்லோகம் ஒன்பது பக்கம் ஏழு - -CARDINAL பாடம் ௨ பக்கம் ௬௬ பாடம் இரண்டு பக்கம் அறுபத்து ஆறு - -CARDINAL ௨ டயகிராம் ௧௩ பக்க எண் இரண்டு டயகிராம் பதிமூன்று பக்க எண் - -CARDINAL பட எண் ௮ பாடம் ௪ பட எண் எட்டு பாடம் நான்கு - -CARDINAL பக்க எண் ௧௦ பாடம் ௩ பக்க எண் பத்து பாடம் மூன்று - -CARDINAL ருகு ௩ ஆயத் ௮ ருகு மூன்று ஆயத் எட்டு - -CARDINAL ருகு ௪ ஆயத் ௬ வரி ௩௩ ருகு நான்கு ஆயத் ஆறு வரி முப்பத்து மூன்று - -CARDINAL பாரா ௨ ருகு ௭ வரி ௧௫ பாரா இரண்டு ருகு ஏழு வரி பதினைந்து - -CARDINAL ௩௦ பாரா வரி ௮ முப்பது பாரா வரி எட்டு - -CARDINAL ௪ சிக்ஸர்கள் ௧௨ ஃபோர்கள் நான்கு சிக்ஸர்கள் பன்னிரண்டு ஃபோர்கள் - -CARDINAL ௫ புள்ளிகள் ௭ கோல்கள் ஐந்து புள்ளிகள் ஏழு கோல்கள் - -CARDINAL பதிப்பு ௨ தலைமுறை ௪ பதிப்பு இரண்டு தலைமுறை நான்கு - -CARDINAL ௮ செங்கற்கள் ௩௨ கற்கள் எட்டு செங்கற்கள் முப்பத்து இரண்டு கற்கள் - -CARDINAL ௯ ஓவரில் ௧௫ ரன்கள் ஒன்பது ஓவரில் பதினைந்து ரன்கள் - -CARDINAL ௪ விக்கெட் ௧௧௩ ரன்கள் நான்கு விக்கெட் நூற்று பதிமூன்று ரன்கள் - -CARDINAL ௭ விக்கெட் ௨௧௧ ரன்கள் ஏழு விக்கெட் இருநூற்று பதினொன்று ரன்கள் - -CARDINAL ௪ சிக்ஸர்கள் ௫ ஃபோர்கள் ௪௪ ரன்கள் நான்கு சிக்ஸர்கள் ஐந்து ஃபோர்கள் நாற்பத்து நான்கு ரன்கள் - -CARDINAL ருகு ௮ வரி ௧௦ ருகு எட்டு வரி பத்து - -CARDINAL பாடம் ௯ வரி ௧௩ பாடம் ஒன்பது வரி பதிமூன்று - -CARDINAL பகுதி ௧௦ வரி ௬ சுலோகம் ௨ பகுதி பத்து வரி ஆறு சுலோகம் இரண்டு - -CARDINAL பகுதி ௧௨ சுலோகம் ௩ வரி ௧௭ பகுதி பன்னிரண்டு சுலோகம் மூன்று வரி பதினேழு - -CARDINAL ௭ ஓவர் ஏழு ஓவர் - -CARDINAL ௬ ஃபோர்கள் ஆறு ஃபோர்கள் - -CARDINAL ௩ ஒன்றுநாள் ௫ டெஸ்ட் போட்டிகள் மூன்று ஒன்றுநாள் ஐந்து டெஸ்ட் போட்டிகள் - -CARDINAL ௭ வீரர்கள் ௨ காயம் ஏழு வீரர்கள் இரண்டு காயம் - -CARDINAL பதிப்பு ௩ தலைமுறை ௧௦ பதிப்பு மூன்று தலைமுறை பத்து - -CARDINAL ருகு ௧௪ பாரா ௮ ருகு பதினான்கு பாரா எட்டு - -CARDINAL சுலோகம் ௮ பாடம் ௬ சுலோகம் எட்டு பாடம் ஆறு - -CARDINAL விரிவுரை ௩ வகுப்பு ௮ விரிவுரை மூன்று வகுப்பு எட்டு - -CARDINAL வகுப்பு ௧௦ பிரிவு ௨ வகுப்பு பத்து பிரிவு இரண்டு - -CARDINAL ௩ டிரா ௨ தோல்வி மூன்று டிரா இரண்டு தோல்வி - -CARDINAL சுலோகம் ௩ பாடம் ௧௧ சுலோகம் மூன்று பாடம் பதினொன்று - -CARDINAL வரி ௬ பாடம் ௧௦ வரி ஆறு பாடம் பத்து - -CARDINAL ருகு ௨ பாரா ௧௫ ருகு இரண்டு பாரா பதினைந்து - -CARDINAL ௪ சிக்ஸர்கள் ௫ பந்துகள் நான்கு சிக்ஸர்கள் ஐந்து பந்துகள் - -CARDINAL ௨ பந்துகள் ௧ ரன் இரண்டு பந்துகள் ஒன்று ரன் - -CARDINAL வரி ௮ அத்தியாயம் ௧௯ வரி எட்டு அத்தியாயம் பத்தொன்பது - -CARDINAL பக்கம் ௧௦ பத்தி ௨ பக்கம் பத்து பத்தி இரண்டு - -CARDINAL ௯ ஓவரில் ௧௭ ரன்கள் ஒன்பது ஓவரில் பதினேழு ரன்கள் - -CARDINAL ௪ பந்துகளில் ௬ நான்கு பந்துகளில் ஆறு - -CARDINAL ௧௭ பந்துகளில் ௧௦ ரன்கள் பதினேழு பந்துகளில் பத்து ரன்கள் - -CARDINAL ௫ ஓவர் ௬௬ ரன்கள் ஐந்து ஓவர் அறுபத்து ஆறு ரன்கள் - -CARDINAL ௮ புள்ளிகள் ௯ கோல்கள் எட்டு புள்ளிகள் ஒன்பது கோல்கள் - -CARDINAL ௫ கொய்யாப்பழங்கள் ஐந்து கொய்யாப்பழங்கள் - -CARDINAL ௬ ருகு ௭ பாரா ஆறு ருகு ஏழு பாரா - -CARDINAL சுலோகம் ௮ பதம் ௯ சுலோகம் எட்டு பதம் ஒன்பது - -CARDINAL ௭ ஓவரில் ௨௧ ரன்கள் ஏழு ஓவரில் இருபத்து ஒன்று ரன்கள் - -CARDINAL ௧ ஓவரில் ௩ ரன்கள் ஒன்று ஓவரில் மூன்று ரன்கள் - -CARDINAL ௭ சிக்ஸர்கள் ௫ ஃபோர்கள் ஏழு சிக்ஸர்கள் ஐந்து ஃபோர்கள் - -CARDINAL ௩ சுலோகங்கள் மூன்று சுலோகங்கள் - -CARDINAL ௬ பக்கங்கள் ஆறு பக்கங்கள் - -CARDINAL ௫ சிக்ஸர்கள் ஐந்து சிக்ஸர்கள் - -CARDINAL ௩ பாட்டில்கள் ௧௦ கண்ணாடிகள் மூன்று பாட்டில்கள் பத்து கண்ணாடிகள் - -CARDINAL ௩ போட்டிகள் மூன்று போட்டிகள் - -CARDINAL ௬ போட்டிகள் ௪ டிரா ஆறு போட்டிகள் நான்கு டிரா - -CARDINAL ௨ பந்துகளில் ௩ ரன்கள் இரண்டு பந்துகளில் மூன்று ரன்கள் - -CARDINAL ௩ புள்ளிகள் ௪ கோல்கள் மூன்று புள்ளிகள் நான்கு கோல்கள் - -CARDINAL ஆயத் ௪ வரி ௯ ஆயத் நான்கு வரி ஒன்பது - -CARDINAL பாரா ௪ ருகு ௧௦ வரி ௧௭ பாரா நான்கு ருகு பத்து வரி பதினேழு - -CARDINAL பாரா ௬ ருகு ௨௫ வரி ௨௦ பாரா ஆறு ருகு இருபத்து ஐந்து வரி இருபது - -CARDINAL பாடம் ௩ தோஹா ௪ வரி ௨ பாடம் மூன்று தோஹா நான்கு வரி இரண்டு - -CARDINAL வரி ௮ சொல் ௬ வரி எட்டு சொல் ஆறு - -CARDINAL கட்டுரை ௧௦ பத்தி ௨ கட்டுரை பத்து பத்தி இரண்டு - -CARDINAL ௭ ஸ்வரங்கள் ஏழு ஸ்வரங்கள் - -CARDINAL பாடல் ௪ முகடை ௨ பாடல் நான்கு முகடை இரண்டு - -CARDINAL டிக்கெட் எண் ௯ வரி ௮ டிக்கெட் எண் ஒன்பது வரி எட்டு - -CARDINAL ஆயத் ௧௦ வரி ௧௮ ஆயத் பத்து வரி பதினெட்டு - -CARDINAL ௬ ஓவர் ௨௦ ரன்கள் ஆறு ஓவர் இருபது ரன்கள் - -CARDINAL ௮௦ ரன்கள் ௩ விக்கெட்டுகள் எண்பது ரன்கள் மூன்று விக்கெட்டுகள் - -CARDINAL ௪ ஸ்பின்னர்கள் ௩ பேட்ஸ்மேன்கள் ௧ விக்கெட் கீப்பர் நான்கு ஸ்பின்னர்கள் மூன்று பேட்ஸ்மேன்கள் ஒன்று விக்கெட் கீப்பர் - -CARDINAL ௧ கோல் கீப்பர் ௬ வீரர்கள் ஒன்று கோல் கீப்பர் ஆறு வீரர்கள் - -CARDINAL பாடம் ௧௮ பதம் ௫ பாடம் பதினெட்டு பதம் ஐந்து - -CARDINAL தோஹா ௬ வரி ௯ தோஹா ஆறு வரி ஒன்பது - -CARDINAL படம் ௬ பக்கம் ௮௦ படம் ஆறு பக்கம் எண்பது - -CARDINAL ௨ டிரா ௩ வெற்றி இரண்டு டிரா மூன்று வெற்றி - -CARDINAL ௪ வைவா ௩ தேர்வுகள் நான்கு வைவா மூன்று தேர்வுகள் - -CARDINAL ௪ தேர்வுகள் ௬ செஷனல்கள் நான்கு தேர்வுகள் ஆறு செஷனல்கள் - -CARDINAL ௩ தட்டுகள் ௪ கிண்ணங்கள் ௨ கரண்டிகள் மூன்று தட்டுகள் நான்கு கிண்ணங்கள் இரண்டு கரண்டிகள் - -CARDINAL ௪ டிரா ௫ வெற்றி நான்கு டிரா ஐந்து வெற்றி - -CARDINAL ௮ சிக்ஸர்கள் ௧௪ ஃபோர்கள் எட்டு சிக்ஸர்கள் பதினான்கு ஃபோர்கள் - -CARDINAL ௫ ஓவர்கள் ௪ விக்கெட்டுகள் ஐந்து ஓவர்கள் நான்கு விக்கெட்டுகள் - -CARDINAL ௩ ரன்கள் ௨ விக்கெட்டுகள் மூன்று ரன்கள் இரண்டு விக்கெட்டுகள் - -CARDINAL ௬ ஓவர்கள் ௪ ரன்கள் ஆறு ஓவர்கள் நான்கு ரன்கள் - -CARDINAL ௪ டெஸ்ட் போட்டிகள் ௧ ஒன்றுநாள் போட்டி நான்கு டெஸ்ட் போட்டிகள் ஒன்று ஒன்றுநாள் போட்டி - -CARDINAL ௨ புள்ளிகள் ௧௨ கோல்கள் இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் - -CARDINAL ௭ கரண்டிகள் உடைந்தன ஏழு கரண்டிகள் உடைந்தன - -CARDINAL ௧௦ இல் ௬ மதிப்பெண்கள் பத்து இல் ஆறு மதிப்பெண்கள் - -CARDINAL பாடம் ௨ பக்க எண் ௧௨ பாடம் இரண்டு பக்க எண் பன்னிரண்டு - -CARDINAL ௧ ஓவரில் ௬ பந்துகள் ஒன்று ஓவரில் ஆறு பந்துகள் - -CARDINAL ௭ ஷாட்டுகள் சரியாக பட்டன ஏழு ஷாட்டுகள் சரியாக பட்டன - -CARDINAL இந்தியாவுக்கு ௪ புள்ளிகள் முன்னிலை இந்தியாவுக்கு நான்கு புள்ளிகள் முன்னிலை - -CARDINAL சதத்திற்கு ௩ ரன்கள் மீதம் சதத்திற்கு மூன்று ரன்கள் மீதம் - -CARDINAL ௧ தோல்வி ௨ டிரா ஒன்று தோல்வி இரண்டு டிரா - -CARDINAL அர்ஜென்டினா ௨ புள்ளிகள் பின்தங்கி அர்ஜென்டினா இரண்டு புள்ளிகள் பின்தங்கி - -CARDINAL ௨ கோல்கள் அடிக்கப்பட்டன இரண்டு கோல்கள் அடிக்கப்பட்டன - -CARDINAL ௮ கூடுதல் ரன்கள் எட்டு கூடுதல் ரன்கள் - -CARDINAL ௪ வைடு பந்துகள் நான்கு வைடு பந்துகள் - -CARDINAL வகுப்பு ௯ வகுப்பு ஒன்பது - -CARDINAL வகுப்பு ௫ வகுப்பு ஐந்து - -CARDINAL ௯ பகுதிகள் ஒன்பது பகுதிகள் - -CARDINAL வகுப்பு ௪ பாடம் ௩ வகுப்பு நான்கு பாடம் மூன்று - -CARDINAL பாடம் ௯ பாடம் ஒன்பது - -CARDINAL பக்க எண் ௮ பக்க எண் எட்டு - -CARDINAL ௪ பாட்டில்கள் நான்கு பாட்டில்கள் - -CARDINAL ௧௦௦ இல் ௪ மதிப்பெண்கள் நூறு இல் நான்கு மதிப்பெண்கள் - -CARDINAL ௮ மதிப்பெண்கள் எட்டு மதிப்பெண்கள் - -CARDINAL கண்ணாடி எண் ௨ கண்ணாடி எண் இரண்டு - -CARDINAL ௭ செருப்புகள் ஏழு செருப்புகள் - -CARDINAL ௫ காலணிகள் ஐந்து காலணிகள் - -CARDINAL ௨ சாண்டல்கள் இரண்டு சாண்டல்கள் - -CARDINAL ௭ விளையாட்டுகளில் வெற்றி ஏழு விளையாட்டுகளில் வெற்றி - -CARDINAL ௬ மூடிகள் ஆறு மூடிகள் - -CARDINAL ௧௦௦௦ ரூபாய் ௨ நோட்டுகள் ஆயிரம் ரூபாய் இரண்டு நோட்டுகள் - -CARDINAL ௧௯ இல் ௩ கண்ணாடிகள் பத்தொன்பது இல் மூன்று கண்ணாடிகள் - -CARDINAL பக்கம் ௧௯௯ பாடம் ௬ பக்கம் நூற்று தொண்ணூற்று ஒன்பது பாடம் ஆறு - -CARDINAL ௮ பாராக்கள் எட்டு பாராக்கள் - -CARDINAL பகுதி ௫ பாடம் ௧௯ பகுதி ஐந்து பாடம் பத்தொன்பது - -CARDINAL ௮௦ ரன்கள் ௬ விக்கெட்டுகள் எண்பது ரன்கள் ஆறு விக்கெட்டுகள் - -CARDINAL ௯ கூடுதல் ரன்கள் ஒன்பது கூடுதல் ரன்கள் - -CARDINAL ௧௧ பந்துகள் ௮ ரன்கள் பதினொன்று பந்துகள் எட்டு ரன்கள் - -CARDINAL ௨ மஞ்சள் ௮ சிவப்பு அட்டைகள் இரண்டு மஞ்சள் எட்டு சிவப்பு அட்டைகள் - -CARDINAL அத்தியாயம் ௧௨ சுலோகம் ௮ அத்தியாயம் பன்னிரண்டு சுலோகம் எட்டு - -CARDINAL பக்கம் ௮௮ அத்தியாயம் ௭ பக்கம் எண்பத்து எட்டு அத்தியாயம் ஏழு - -CARDINAL ௧௦௦ ரன்கள் ௫ விக்கெட்டுகள் நூறு ரன்கள் ஐந்து விக்கெட்டுகள் - -CARDINAL ௮ கோல்களால் வெற்றி எட்டு கோல்களால் வெற்றி - -CARDINAL ௩ சக்கர வாகனம் மூன்று சக்கர வாகனம் - -CARDINAL அத்தியாயம் ௧௯ பகுதி ௪ அத்தியாயம் பத்தொன்பது பகுதி நான்கு - -CARDINAL ௧௧ மாதங்கள் ௮ நாட்கள் பதினொன்று மாதங்கள் எட்டு நாட்கள் - -CARDINAL ௯ நாட்கள் ௧௨ மணி நேரம் ஒன்பது நாட்கள் பன்னிரண்டு மணி நேரம் - -CARDINAL ௪ கட்டுகள் ௧௩ அட்டைகள் நான்கு கட்டுகள் பதிமூன்று அட்டைகள் - -CARDINAL ௭ போட்டிகள் ௧௨ விக்கெட்டுகள் ஏழு போட்டிகள் பன்னிரண்டு விக்கெட்டுகள் - -CARDINAL ௧ மனிதன் ஒன்று மனிதன் - -CARDINAL ௨ பெண்கள் இரண்டு பெண்கள் - -CARDINAL ௩ குழந்தைகள் மூன்று குழந்தைகள் - -CARDINAL ௪ புத்தகங்கள் நான்கு புத்தகங்கள் - -CARDINAL ௫ அறைகள் ஐந்து அறைகள் - -CARDINAL ௬ வீடுகள் ஆறு வீடுகள் - -CARDINAL ௭ பக்கங்கள் ஏழு பக்கங்கள் - -CARDINAL ௮ நாணயங்கள் எட்டு நாணயங்கள் - -CARDINAL ௯ பெட்டிகள் ஒன்பது பெட்டிகள் - -CARDINAL ௧௦ வேலைகள் பத்து வேலைகள் - -CARDINAL ௧௧ பழங்கள் ௨ பூக்கள் பதினொன்று பழங்கள் இரண்டு பூக்கள் - -CARDINAL ௩ பூக்கள் மூன்று பூக்கள் - -CARDINAL ௧௩ பூந்தொட்டிகள் ௪ செடிகள் பதிமூன்று பூந்தொட்டிகள் நான்கு செடிகள் - -CARDINAL ௪ பப்பாளிப்பழங்கள் நான்கு பப்பாளிப்பழங்கள் - -CARDINAL ௫ மாம்பழங்கள் ஐந்து மாம்பழங்கள் - -CARDINAL ௬ வாழைப்பழங்கள் ஆறு வாழைப்பழங்கள் - -CARDINAL ௭ திராட்சைப்பழங்கள் ஏழு திராட்சைப்பழங்கள் - -CARDINAL ௮ ஆரஞ்சுப்பழங்கள் எட்டு ஆரஞ்சுப்பழங்கள் - -CARDINAL ௯ ஆப்பிள்கள் ஒன்பது ஆப்பிள்கள் - -CARDINAL ௧௦ சப்போட்டா பழங்கள் பத்து சப்போட்டா பழங்கள் - -CARDINAL ௧ தாமரை ஒன்று தாமரை - -CARDINAL ௨ கற்கள் இரண்டு கற்கள் - -CARDINAL ௩ நாற்காலிகள் மூன்று நாற்காலிகள் - -CARDINAL ௪ பைகள் நான்கு பைகள் - -CARDINAL ௫ தொலைபேசிகள் ஐந்து தொலைபேசிகள் - -CARDINAL ௬ அறைகள் ஆறு அறைகள் - -CARDINAL ௭ பெண்கள் ஏழு பெண்கள் - -CARDINAL ௮ புத்தகங்கள் எட்டு புத்தகங்கள் - -CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் - -CARDINAL ௧௦ நதிகள் பத்து நதிகள் - -CARDINAL ௩ எருமைகள் மூன்று எருமைகள் - -CARDINAL ௨ காலணிகள் இரண்டு காலணிகள் - -CARDINAL ௩ நாய்கள் மூன்று நாய்கள் - -CARDINAL ௪ குதிரைகள் நான்கு குதிரைகள் - -CARDINAL ௫ மகன்கள் ஐந்து மகன்கள் - -CARDINAL ௬ சேவல்கள் ஆறு சேவல்கள் - -CARDINAL ௭ கழுதைகள் ஏழு கழுதைகள் - -CARDINAL ௮ சிறுமிகள் எட்டு சிறுமிகள் - -CARDINAL ௯ சிறுவர்கள் ஒன்பது சிறுவர்கள் - -CARDINAL ௧௦ கேள்விகள் பத்து கேள்விகள் - -CARDINAL ௧ சட்டை ஒன்று சட்டை - -CARDINAL ௨ படகுகள் இரண்டு படகுகள் - -CARDINAL ௩ பெட்டிகள் மூன்று பெட்டிகள் - -CARDINAL ௪ மூடிகள் நான்கு மூடிகள் - -CARDINAL ௫ நோட்டுகள் ஐந்து நோட்டுகள் - -CARDINAL ௬ நாணயங்கள் ஆறு நாணயங்கள் - -CARDINAL ௭ காயங்கள் ஏழு காயங்கள் - -CARDINAL ௮ நிறங்கள் எட்டு நிறங்கள் - -CARDINAL ௯ மக்கள் ஒன்பது மக்கள் - -CARDINAL ௧௦ நாட்கள் பத்து நாட்கள் - -CARDINAL ௫ விஷயங்கள் ஐந்து விஷயங்கள் - -CARDINAL ௨ மருந்துகள் இரண்டு மருந்துகள் - -CARDINAL ௩ கூடுகள் மூன்று கூடுகள் - -CARDINAL ௪ தோழிகள் நான்கு தோழிகள் - -CARDINAL ௫ செடிகள் ஐந்து செடிகள் - -CARDINAL ௬ திரைகள் ஆறு திரைகள் - -CARDINAL ௭ பூனைகள் ஏழு பூனைகள் - -CARDINAL ௮ எலிகள் எட்டு எலிகள் - -CARDINAL ௯ வாகனங்கள் ஒன்பது வாகனங்கள் - -CARDINAL ௧௦ கண்கள் பத்து கண்கள் - -CARDINAL ௬ சுவர்கள் ஆறு சுவர்கள் - -CARDINAL ௨ கடிகாரங்கள் இரண்டு கடிகாரங்கள் - -CARDINAL ௩ பப்பாளிப்பழங்கள் மூன்று பப்பாளிப்பழங்கள் - -CARDINAL ௪ மிதிவண்டிகள் நான்கு மிதிவண்டிகள் - -CARDINAL ௫ ஜன்னல்கள் ஐந்து ஜன்னல்கள் - -CARDINAL ௬ கிளைகள் ஆறு கிளைகள் - -CARDINAL ௭ பொம்மைகள் ஏழு பொம்மைகள் - -CARDINAL ௮ கவிதைகள் எட்டு கவிதைகள் - -CARDINAL ௯ கதைகள் ஒன்பது கதைகள் - -CARDINAL ௧௦ கதைகள் பத்து கதைகள் - -CARDINAL ௭ மொட்டுகள் ஏழு மொட்டுகள் - -CARDINAL ௨ கோழிகள் இரண்டு கோழிகள் - -CARDINAL ௩ தெருக்கள் மூன்று தெருக்கள் - -CARDINAL ௪ தேதிகள் நான்கு தேதிகள் - -CARDINAL ௫ கருவிகள் ஐந்து கருவிகள் - -CARDINAL ௬ கன்னியர்கள் ஆறு கன்னியர்கள் - -CARDINAL ௭ தட்டுகள் ஏழு தட்டுகள் - -CARDINAL ௮ பெண்கள் எட்டு பெண்கள் - -CARDINAL ௯ இரவுகள் ஒன்பது இரவுகள் - -CARDINAL ௧௦ காய்கறிகள் பத்து காய்கறிகள் - -CARDINAL ௮ குழந்தைகள் எட்டு குழந்தைகள் - -CARDINAL ௨ தொப்பிகள் இரண்டு தொப்பிகள் - -CARDINAL ௩ சிறுமிகள் மூன்று சிறுமிகள் - -CARDINAL ௪ நதிகள் நான்கு நதிகள் - -CARDINAL ௫ பெண்கள் ஐந்து பெண்கள் - -CARDINAL ௬ பொட்டுகள் ஆறு பொட்டுகள் - -CARDINAL ௭ பெட்டிகள் ஏழு பெட்டிகள் - -CARDINAL ௯ பொம்மைகள் ஒன்பது பொம்மைகள் - -CARDINAL ௧௦ கதைகள் பத்து கதைகள் - -CARDINAL ௯ இதழ்கள் ஒன்பது இதழ்கள் - -CARDINAL ௨ கொடிகள் இரண்டு கொடிகள் - -CARDINAL ௩ கவிதைகள் மூன்று கவிதைகள் - -CARDINAL ௪ ஏரிகள் நான்கு ஏரிகள் - -CARDINAL ௫ செருப்புகள் ஐந்து செருப்புகள் - -CARDINAL ௬ பசுக்கள் ஆறு பசுக்கள் - -CARDINAL ௭ சாலைகள் ஏழு சாலைகள் - -CARDINAL ௮ கண்கள் எட்டு கண்கள் - -CARDINAL ௧௦ பேச்சுகள் பத்து பேச்சுகள் - -CARDINAL ௧௦௧ நூற்று ஒன்று - -CARDINAL ௧௦௨ நூற்று இரண்டு - -CARDINAL ௧௦௩ நூற்று மூன்று - -CARDINAL ௧௦௪ நூற்று நான்கு - -CARDINAL ௧௦௫ நூற்று ஐந்து - -CARDINAL ௧௦௬ நூற்று ஆறு - -CARDINAL ௧௦௭ நூற்று ஏழு - -CARDINAL ௧௦௮ நூற்று எட்டு - -CARDINAL ௧௦௯ நூற்று ஒன்பது - -CARDINAL ௧௧௦ நூற்று பத்து - -CARDINAL ௧௧௧ நூற்று பதினொன்று - -CARDINAL ௧௧௨ நூற்று பன்னிரண்டு - -CARDINAL ௧௧௩ நூற்று பதிமூன்று - -CARDINAL ௧௧௪ நூற்று பதினான்கு - -CARDINAL ௧௧௫ நூற்று பதினைந்து - -CARDINAL ௧௧௬ நூற்று பதினாறு - -CARDINAL ௮௧௭ எட்டுநூற்று பதினேழு - -CARDINAL ௮௧௮ எட்டுநூற்று பதினெட்டு - -CARDINAL ௮௧௯ எட்டுநூற்று பத்தொன்பது - -CARDINAL ௮௨௦ எட்டுநூற்று இருபது - -CARDINAL ௮௨௧ எட்டுநூற்று இருபத்து ஒன்று - -CARDINAL ௮௨௨ எட்டுநூற்று இருபத்து இரண்டு - -CARDINAL ௮௨௩ எட்டுநூற்று இருபத்து மூன்று - -CARDINAL ௮௨௪ எட்டுநூற்று இருபத்து நான்கு - -CARDINAL ௮௨௫ எட்டுநூற்று இருபத்து ஐந்து - -CARDINAL ௮௨௬ எட்டுநூற்று இருபத்து ஆறு - -CARDINAL ௮௨௭ எட்டுநூற்று இருபத்து ஏழு - -CARDINAL ௮௨௮ எட்டுநூற்று இருபத்து எட்டு - -CARDINAL ௮௨௯ எட்டுநூற்று இருபத்து ஒன்பது - -CARDINAL ௮௩௦ எட்டுநூற்று முப்பது - -CARDINAL ௮௩௧ எட்டுநூற்று முப்பத்து ஒன்று - -CARDINAL ௮௩௨ எட்டுநூற்று முப்பத்து இரண்டு - -CARDINAL ௮௩௩ எட்டுநூற்று முப்பத்து மூன்று - -CARDINAL ௮௩௪ எட்டுநூற்று முப்பத்து நான்கு - -CARDINAL ௮௩௫ எட்டுநூற்று முப்பத்து ஐந்து - -CARDINAL ௮௩௬ எட்டுநூற்று முப்பத்து ஆறு - -CARDINAL ௭௩௮ எழுநூற்று முப்பத்து எட்டு - -CARDINAL ௭௩௯ எழுநூற்று முப்பத்து ஒன்பது - -CARDINAL ௭௪௦ எழுநூற்று நாற்பது - -CARDINAL ௭௪௧ எழுநூற்று நாற்பத்து ஒன்று - -CARDINAL ௭௪௨ எழுநூற்று நாற்பத்து இரண்டு - -CARDINAL ௭௪௩ எழுநூற்று நாற்பத்து மூன்று - -CARDINAL ௭௪௪ எழுநூற்று நாற்பத்து நான்கு - -CARDINAL ௭௪௫ எழுநூற்று நாற்பத்து ஐந்து - -CARDINAL ௪௪௬ நானூற்று நாற்பத்து ஆறு - -CARDINAL ௪௪௭ நானூற்று நாற்பத்து ஏழு - -CARDINAL ௪௪௮ நானூற்று நாற்பத்து எட்டு - -CARDINAL ௪௪௯ நானூற்று நாற்பத்து ஒன்பது - -CARDINAL ௪௫௦ நானூற்று ஐம்பது - -CARDINAL ௪௬௧ நானூற்று அறுபத்து ஒன்று - -CARDINAL ௧௭௫ நூற்று எழுபத்து ஐந்து - -CARDINAL ௧௮௧ நூற்று எண்பத்து ஒன்று - -CARDINAL ௧௯௦ நூற்று தொண்ணூறு - -CARDINAL ௧௯௯ நூற்று தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௧ ஆயிரத்து ஒன்று - -CARDINAL ௧௦௦௨ ஆயிரத்து இரண்டு - -CARDINAL ௧௦௦௩ ஆயிரத்து மூன்று - -CARDINAL ௧௦௦௪ ஆயிரத்து நான்கு - -CARDINAL ௧௦௦௫ ஆயிரத்து ஐந்து - -CARDINAL ௧௦௦௬ ஆயிரத்து ஆறு - -CARDINAL ௧௦௦௭ ஆயிரத்து ஏழு - -CARDINAL ௧௦௦௮ ஆயிரத்து எட்டு - -CARDINAL ௧௦௦௯ ஆயிரத்து ஒன்பது - -CARDINAL ௧௦௧௦ ஆயிரத்து பத்து - -CARDINAL ௧௦௧௧ ஆயிரத்து பதினொன்று - -CARDINAL ௧௦௧௨ ஆயிரத்து பன்னிரண்டு - -CARDINAL ௧௦௧௩ ஆயிரத்து பதிமூன்று - -CARDINAL ௧௦௧௪ ஆயிரத்து பதினான்கு - -CARDINAL ௧௦௧௫ ஆயிரத்து பதினைந்து - -CARDINAL ௧௦௧௬ ஆயிரத்து பதினாறு - -CARDINAL ௧௦௧௭ ஆயிரத்து பதினேழு - -CARDINAL ௧௦௧௮ ஆயிரத்து பதினெட்டு - -CARDINAL ௧௦௧௯ ஆயிரத்து பத்தொன்பது - -CARDINAL ௧௦௨௦ ஆயிரத்து இருபது - -CARDINAL ௧௦௨௧ ஆயிரத்து இருபத்து ஒன்று - -CARDINAL ௧௦௨௨ ஆயிரத்து இருபத்து இரண்டு - -CARDINAL ௧௧௨௩ ஆயிரத்து நூற்று இருபத்து மூன்று - -CARDINAL ௧௪௨௪ ஆயிரத்து நானூற்று இருபத்து நான்கு - -CARDINAL ௧௫௨௫ ஆயிரத்து ஐந்நூற்று இருபத்து ஐந்து - -CARDINAL ௧௩௨௬ ஆயிரத்து முந்நூற்று இருபத்து ஆறு - -CARDINAL ௧௪௨௭ ஆயிரத்து நானூற்று இருபத்து ஏழு - -CARDINAL ௧௬௨௮ ஆயிரத்து அறுநூற்று இருபத்து எட்டு - -CARDINAL ௧௭௨௯ ஆயிரத்து எழுநூற்று இருபத்து ஒன்பது - -CARDINAL ௧௮௩௦ ஆயிரத்து எட்டுநூற்று முப்பது - -CARDINAL ௧௧௩௧ ஆயிரத்து நூற்று முப்பத்து ஒன்று - -CARDINAL ௧௨௩௨ ஆயிரத்து இருநூற்று முப்பத்து இரண்டு - -CARDINAL ௧௩௩௩ ஆயிரத்து முந்நூற்று முப்பத்து மூன்று - -CARDINAL ௧௪௩௪ ஆயிரத்து நானூற்று முப்பத்து நான்கு - -CARDINAL ௧௫௩௫ ஆயிரத்து ஐந்நூற்று முப்பத்து ஐந்து - -CARDINAL ௧௬௩௬ ஆயிரத்து அறுநூற்று முப்பத்து ஆறு - -CARDINAL ௧௭௩௭ ஆயிரத்து எழுநூற்று முப்பத்து ஏழு - -CARDINAL ௧௮௩௮ ஆயிரத்து எட்டுநூற்று முப்பத்து எட்டு - -CARDINAL ௧௯௩௯ ஆயிரத்து ஒன்பதுநூற்று முப்பத்து ஒன்பது - -CARDINAL ௧௦௪௦ ஆயிரத்து நாற்பது - -CARDINAL ௧௦௪௧ ஆயிரத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௪௨ ஆயிரத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௪௩ ஆயிரத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௪௪ ஆயிரத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௪௫ ஆயிரத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௪௬ ஆயிரத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௪௭ ஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௪௮ ஆயிரத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௪௯ ஆயிரத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௫௦ ஆயிரத்து ஐம்பது - -CARDINAL ௧௦௬௧ ஆயிரத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௭௫ ஆயிரத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௮௧ ஆயிரத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௯௦ ஆயிரத்து தொண்ணூறு - -CARDINAL ௧௦௯௯ ஆயிரத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௧ பத்துஆயிரத்து ஒன்று - -CARDINAL ௧௦௦௦௨ பத்துஆயிரத்து இரண்டு - -CARDINAL ௧௦௨௦௩ பத்துஆயிரத்து இருநூற்று மூன்று - -CARDINAL ௧௦௩௦௪ பத்துஆயிரத்து முந்நூற்று நான்கு - -CARDINAL ௧௧௩௦௫ பதினொன்றுஆயிரத்து முந்நூற்று ஐந்து - -CARDINAL ௧௨௪௫௬ பன்னிரண்டுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௧௩௦௪௭ பதிமூன்றுஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௮ பத்துஆயிரத்து எட்டு - -CARDINAL ௧௦௦௦௯ பத்துஆயிரத்து ஒன்பது - -CARDINAL ௧௦௦௧௦ பத்துஆயிரத்து பத்து - -CARDINAL ௧௦௦௧௧ பத்துஆயிரத்து பதினொன்று - -CARDINAL ௧௦௦௧௨ பத்துஆயிரத்து பன்னிரண்டு - -CARDINAL ௧௦௦௧௩ பத்துஆயிரத்து பதிமூன்று - -CARDINAL ௧௦௦௧௪ பத்துஆயிரத்து பதினான்கு - -CARDINAL ௧௦௦௧௫ பத்துஆயிரத்து பதினைந்து - -CARDINAL ௧௦௦௧௬ பத்துஆயிரத்து பதினாறு - -CARDINAL ௧௦௦௧௭ பத்துஆயிரத்து பதினேழு - -CARDINAL ௧௦௦௧௮ பத்துஆயிரத்து பதினெட்டு - -CARDINAL ௧௦௦௧௯ பத்துஆயிரத்து பத்தொன்பது - -CARDINAL ௧௦௦௨௦ பத்துஆயிரத்து இருபது - -CARDINAL ௧௦௦௨௧ பத்துஆயிரத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௨௨ பத்துஆயிரத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௨௩ பத்துஆயிரத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௨௪ பத்துஆயிரத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௨௫ பத்துஆயிரத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௨௬ பத்துஆயிரத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௨௭ பத்துஆயிரத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௨௮ பத்துஆயிரத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௨௯ பத்துஆயிரத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௩௦ பத்துஆயிரத்து முப்பது - -CARDINAL ௧௦௦௩௧ பத்துஆயிரத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௩௨ பத்துஆயிரத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௩௩ பத்துஆயிரத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௩௪ பத்துஆயிரத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௩௫ பத்துஆயிரத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௩௬ பத்துஆயிரத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௩௭ பத்துஆயிரத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௩௮ பத்துஆயிரத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௩௯ பத்துஆயிரத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௪௦ பத்துஆயிரத்து நாற்பது - -CARDINAL ௧௦௦௪௧ பத்துஆயிரத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௪௨ பத்துஆயிரத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௪௩ பத்துஆயிரத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௪௪ பத்துஆயிரத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௪௫ பத்துஆயிரத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௪௬ பத்துஆயிரத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௪௭ பத்துஆயிரத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௪௮ பத்துஆயிரத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௪௯ பத்துஆயிரத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௫௦ பத்துஆயிரத்து ஐம்பது - -CARDINAL ௧௦௦௬௧ பத்துஆயிரத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௭௫ பத்துஆயிரத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௮௧ பத்துஆயிரத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௯௦ பத்துஆயிரத்து தொண்ணூறு - -CARDINAL ௧௦௦௯௯ பத்துஆயிரத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௧ ஒன்று இலட்சத்து ஒன்று - -CARDINAL ௧௧௦௦௦௨ ஒன்று இலட்சத்து பத்துஆயிரத்து இரண்டு - -CARDINAL ௧௨௦௪௦௩ ஒன்று இலட்சத்து இருபதுஆயிரத்து நானூற்று மூன்று - -CARDINAL ௧௪௧௫௦௪ ஒன்று இலட்சத்து நாற்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று நான்கு - -CARDINAL ௧௫௧௫௧௫ ஒன்று இலட்சத்து ஐம்பத்து ஒன்றுஆயிரத்து ஐந்நூற்று பதினைந்து - -CARDINAL ௧௦௦௦௦௬ ஒன்று இலட்சத்து ஆறு - -CARDINAL ௧௦௦௦௦௭ ஒன்று இலட்சத்து ஏழு - -CARDINAL ௧௦௦௦௦௮ ஒன்று இலட்சத்து எட்டு - -CARDINAL ௧௦௦௦௦௯ ஒன்று இலட்சத்து ஒன்பது - -CARDINAL ௧௦௦௦௧௦ ஒன்று இலட்சத்து பத்து - -CARDINAL ௧௦௦௦௧௧ ஒன்று இலட்சத்து பதினொன்று - -CARDINAL ௧௦௦௦௧௨ ஒன்று இலட்சத்து பன்னிரண்டு - -CARDINAL ௧௦௦௦௧௩ ஒன்று இலட்சத்து பதிமூன்று - -CARDINAL ௧௦௦௦௧௪ ஒன்று இலட்சத்து பதினான்கு - -CARDINAL ௧௦௦௦௧௫ ஒன்று இலட்சத்து பதினைந்து - -CARDINAL ௧௦௦௦௧௬ ஒன்று இலட்சத்து பதினாறு - -CARDINAL ௧௦௦௦௧௭ ஒன்று இலட்சத்து பதினேழு - -CARDINAL ௧௦௦௦௧௮ ஒன்று இலட்சத்து பதினெட்டு - -CARDINAL ௧௦௦௦௧௯ ஒன்று இலட்சத்து பத்தொன்பது - -CARDINAL ௧௦௦௦௨௦ ஒன்று இலட்சத்து இருபது - -CARDINAL ௧௦௦௦௨௧ ஒன்று இலட்சத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௨௨ ஒன்று இலட்சத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௨௩ ஒன்று இலட்சத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௦௨௪ ஒன்று இலட்சத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௦௨௫ ஒன்று இலட்சத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௨௬ ஒன்று இலட்சத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௦௨௭ ஒன்று இலட்சத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௦௨௮ ஒன்று இலட்சத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௦௨௯ ஒன்று இலட்சத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௩௦ ஒன்று இலட்சத்து முப்பது - -CARDINAL ௧௦௦௦௩௧ ஒன்று இலட்சத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௩௨ ஒன்று இலட்சத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௩௩ ஒன்று இலட்சத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௩௪ ஒன்று இலட்சத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௩௫ ஒன்று இலட்சத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௩௬ ஒன்று இலட்சத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௩௭ ஒன்று இலட்சத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௩௮ ஒன்று இலட்சத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௩௯ ஒன்று இலட்சத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௪௦ ஒன்று இலட்சத்து நாற்பது - -CARDINAL ௧௦௦௦௪௧ ஒன்று இலட்சத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௪௨ ஒன்று இலட்சத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௪௩ ஒன்று இலட்சத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௪௪ ஒன்று இலட்சத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௪௫ ஒன்று இலட்சத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௪௬ ஒன்று இலட்சத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௪௭ ஒன்று இலட்சத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௪௮ ஒன்று இலட்சத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௪௯ ஒன்று இலட்சத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௫௦ ஒன்று இலட்சத்து ஐம்பது - -CARDINAL ௧௦௦௦௬௧ ஒன்று இலட்சத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௭௫ ஒன்று இலட்சத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௮௧ ஒன்று இலட்சத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௯௦ ஒன்று இலட்சத்து தொண்ணூறு - -CARDINAL ௧௦௦௦௯௯ ஒன்று இலட்சத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௦௧ பத்து இலட்சத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௨ பத்து இலட்சத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௩ பத்து இலட்சத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௪ பத்து இலட்சத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௫ பத்து இலட்சத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௬ பத்து இலட்சத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௭ பத்து இலட்சத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௮ பத்து இலட்சத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௯ பத்து இலட்சத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௧௦ பத்து இலட்சத்து பத்து - -CARDINAL ௧௦௦௦௦௧௧ பத்து இலட்சத்து பதினொன்று - -CARDINAL ௧௦௦௦௦௧௨ பத்து இலட்சத்து பன்னிரண்டு - -CARDINAL ௧௦௦௦௦௧௩ பத்து இலட்சத்து பதிமூன்று - -CARDINAL ௧௦௦௦௦௧௪ பத்து இலட்சத்து பதினான்கு - -CARDINAL ௧௦௦௦௦௧௫ பத்து இலட்சத்து பதினைந்து - -CARDINAL ௧௦௦௦௦௧௬ பத்து இலட்சத்து பதினாறு - -CARDINAL ௧௦௦௦௦௧௭ பத்து இலட்சத்து பதினேழு - -CARDINAL ௧௦௦௦௦௧௮ பத்து இலட்சத்து பதினெட்டு - -CARDINAL ௧௦௦௦௦௧௯ பத்து இலட்சத்து பத்தொன்பது - -CARDINAL ௧௦௦௦௦௨௦ பத்து இலட்சத்து இருபது - -CARDINAL ௧௦௦௦௦௨௧ பத்து இலட்சத்து இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௨௨ பத்து இலட்சத்து இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௦௨௩ பத்து இலட்சத்து இருபத்து மூன்று - -CARDINAL ௧௦௦௦௦௨௪ பத்து இலட்சத்து இருபத்து நான்கு - -CARDINAL ௧௦௦௦௦௨௫ பத்து இலட்சத்து இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௨௬ பத்து இலட்சத்து இருபத்து ஆறு - -CARDINAL ௧௦௦௦௦௨௭ பத்து இலட்சத்து இருபத்து ஏழு - -CARDINAL ௧௦௦௦௦௨௮ பத்து இலட்சத்து இருபத்து எட்டு - -CARDINAL ௧௦௦௦௦௨௯ பத்து இலட்சத்து இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௩௦ பத்து இலட்சத்து முப்பது - -CARDINAL ௧௦௦௦௦௩௧ பத்து இலட்சத்து முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௩௨ பத்து இலட்சத்து முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௩௩ பத்து இலட்சத்து முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௩௪ பத்து இலட்சத்து முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௩௫ பத்து இலட்சத்து முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௩௬ பத்து இலட்சத்து முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௩௭ பத்து இலட்சத்து முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௩௮ பத்து இலட்சத்து முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௩௯ பத்து இலட்சத்து முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௪௦ பத்து இலட்சத்து நாற்பது - -CARDINAL ௧௦௦௦௦௪௧ பத்து இலட்சத்து நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௪௨ பத்து இலட்சத்து நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௪௩ பத்து இலட்சத்து நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௪௪ பத்து இலட்சத்து நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௪௫ பத்து இலட்சத்து நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௪௬ பத்து இலட்சத்து நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௪௭ பத்து இலட்சத்து நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௪௮ பத்து இலட்சத்து நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௪௯ பத்து இலட்சத்து நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௫௦ பத்து இலட்சத்து ஐம்பது - -CARDINAL ௧௦௦௦௦௬௧ பத்து இலட்சத்து அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௭௫ பத்து இலட்சத்து எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௮௧ பத்து இலட்சத்து எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௯௦ பத்து இலட்சத்து தொண்ணூறு - -CARDINAL ௧௦௦௦௦௯௯ பத்து இலட்சத்து தொண்ணூற்று ஒன்பது - -CARDINAL ௧௦௦௦௦௦௦௧ ஒன்று கோடியே ஒன்று - -CARDINAL ௧௦௦௦௦௦௦௨ ஒன்று கோடியே இரண்டு - -CARDINAL ௧௦௦௦௦௦௦௩ ஒன்று கோடியே மூன்று - -CARDINAL ௧௦௦௦௦௦௦௪ ஒன்று கோடியே நான்கு - -CARDINAL ௧௦௦௦௦௦௦௫ ஒன்று கோடியே ஐந்து - -CARDINAL ௧௦௦௦௦௦௦௬ ஒன்று கோடியே ஆறு - -CARDINAL ௧௦௦௦௦௦௦௭ ஒன்று கோடியே ஏழு - -CARDINAL ௧௦௦௦௦௦௦௮ ஒன்று கோடியே எட்டு - -CARDINAL ௧௦௦௦௦௦௦௯ ஒன்று கோடியே ஒன்பது - -CARDINAL ௧௦௦௦௦௦௧௦ ஒன்று கோடியே பத்து - -CARDINAL ௧௦௦௦௦௦௧௧ ஒன்று கோடியே பதினொன்று - -CARDINAL ௧௦௦௦௦௦௧௨ ஒன்று கோடியே பன்னிரண்டு - -CARDINAL ௧௦௦௦௦௦௧௩ ஒன்று கோடியே பதிமூன்று - -CARDINAL ௧௦௦௦௦௦௧௪ ஒன்று கோடியே பதினான்கு - -CARDINAL ௧௦௦௦௦௦௧௫ ஒன்று கோடியே பதினைந்து - -CARDINAL ௧௦௦௦௦௦௧௬ ஒன்று கோடியே பதினாறு - -CARDINAL ௧௦௦௦௦௦௧௭ ஒன்று கோடியே பதினேழு - -CARDINAL ௧௦௦௦௦௦௧௮ ஒன்று கோடியே பதினெட்டு - -CARDINAL ௧௦௦௦௦௦௧௯ ஒன்று கோடியே பத்தொன்பது - -CARDINAL ௧௦௦௦௦௦௨௦ ஒன்று கோடியே இருபது - -CARDINAL ௧௦௦௦௦௦௨௧ ஒன்று கோடியே இருபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௨௨ ஒன்று கோடியே இருபத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௨௩ ஒன்று கோடியே இருபத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௨௪ ஒன்று கோடியே இருபத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௨௫ ஒன்று கோடியே இருபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௨௬ ஒன்று கோடியே இருபத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௨௭ ஒன்று கோடியே இருபத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௨௮ ஒன்று கோடியே இருபத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௨௯ ஒன்று கோடியே இருபத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௩௦ ஒன்று கோடியே முப்பது - -CARDINAL ௧௦௦௦௦௦௩௧ ஒன்று கோடியே முப்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௩௨ ஒன்று கோடியே முப்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௩௩ ஒன்று கோடியே முப்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௩௪ ஒன்று கோடியே முப்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௩௫ ஒன்று கோடியே முப்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௩௬ ஒன்று கோடியே முப்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௩௭ ஒன்று கோடியே முப்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௩௮ ஒன்று கோடியே முப்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௩௯ ஒன்று கோடியே முப்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௪௦ ஒன்று கோடியே நாற்பது - -CARDINAL ௧௦௦௦௦௦௪௧ ஒன்று கோடியே நாற்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௪௨ ஒன்று கோடியே நாற்பத்து இரண்டு - -CARDINAL ௧௦௦௦௦௦௪௩ ஒன்று கோடியே நாற்பத்து மூன்று - -CARDINAL ௧௦௦௦௦௦௪௪ ஒன்று கோடியே நாற்பத்து நான்கு - -CARDINAL ௧௦௦௦௦௦௪௫ ஒன்று கோடியே நாற்பத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௪௬ ஒன்று கோடியே நாற்பத்து ஆறு - -CARDINAL ௧௦௦௦௦௦௪௭ ஒன்று கோடியே நாற்பத்து ஏழு - -CARDINAL ௧௦௦௦௦௦௪௮ ஒன்று கோடியே நாற்பத்து எட்டு - -CARDINAL ௧௦௦௦௦௦௪௯ ஒன்று கோடியே நாற்பத்து ஒன்பது - -CARDINAL ௧௦௦௦௦௦௫௦ ஒன்று கோடியே ஐம்பது - -CARDINAL ௧௦௦௦௦௦௬௧ ஒன்று கோடியே அறுபத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௭௫ ஒன்று கோடியே எழுபத்து ஐந்து - -CARDINAL ௧௦௦௦௦௦௮௧ ஒன்று கோடியே எண்பத்து ஒன்று - -CARDINAL ௧௦௦௦௦௦௯௦ ஒன்று கோடியே தொண்ணூறு - -CARDINAL ௧௦௦௦௦௦௯௯ ஒன்று கோடியே தொண்ணூற்று ஒன்பது - -CARDINAL ௧௩௨௩ ஆயிரத்து முந்நூற்று இருபத்து மூன்று - -CARDINAL ௧௩௪௫ ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து - -CARDINAL ௧௩௪௫௬ பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௧௨௩௪௬ பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு - -CARDINAL ௧௨௩௪௫௬ ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு - -CARDINAL ௮௭௨௯௮௭ எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு - -CARDINAL ௯௮௭௬௦௯ ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது - -CARDINAL ௯௮௭௬௭௮௯ தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது - -CARDINAL ௨௩௪௫௫௬௭ இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௨௩௪௫௫௬௭ ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௨௧௨௧௨௧௨௨ பன்னிரண்டு கோடியே பன்னிரண்டு இலட்சத்து பன்னிரண்டுஆயிரத்து நூற்று இருபத்து இரண்டு - -CARDINAL ௧௦௦௨௩௪௫௫௬௭ ஒன்று அரபு இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௧௨௨௩௪௫௫௬௭ ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௦௨௨௩௪௫௫௬௭ ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௧௧௦௨௨௩௪௫௫௬௭ பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - -CARDINAL ௫௧௦௨௨௩௪௫௫௬௭ ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு - diff --git "a/eval \"$(ssh-agent -s)\" " "b/eval \"$(ssh-agent -s)\" " deleted file mode 100644 index b14c82405..000000000 --- "a/eval \"$(ssh-agent -s)\" " +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACCBMyvfUYcSi2sN3FiNKP92mA4jqEmXAt9Mz/oDhT/pJwAAAJieiaaMnomm -jAAAAAtzc2gtZWQyNTUxOQAAACCBMyvfUYcSi2sN3FiNKP92mA4jqEmXAt9Mz/oDhT/pJw -AAAED1t2yISojEhh/YjRHWLfYQOZzCun70VF+ZVvMWjWh3I4EzK99RhxKLaw3cWI0o/3aY -DiOoSZcC30zP+gOFP+knAAAAFXN1cmVuZHJhbnNAbnZpZGlhLmNvbQ== ------END OPENSSH PRIVATE KEY----- diff --git "a/eval \"$(ssh-agent -s)\" .pub" "b/eval \"$(ssh-agent -s)\" .pub" deleted file mode 100644 index 90b5c176a..000000000 --- "a/eval \"$(ssh-agent -s)\" .pub" +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIEzK99RhxKLaw3cWI0o/3aYDiOoSZcC30zP+gOFP+kn surendrans@nvidia.com diff --git a/run_cardinal_tests.py b/run_cardinal_tests.py deleted file mode 100644 index 35d36567d..000000000 --- a/run_cardinal_tests.py +++ /dev/null @@ -1,46 +0,0 @@ -# run_cardinal_tests.py -- simple checker for the Cardinal exercise. -# Usage (from the repo root, inside your conda env): -# python run_cardinal_tests.py -# Example: -# python run_cardinal_tests.py LANGCODE DIRECTION test_cases_cardinal.txt -import importlib -import sys - -import pynini - - -def apply_fst(fst, text): - lattice = text @ fst - if lattice.num_states() == 0: - return None # input was rejected by the grammar - out = pynini.shortestpath(lattice) - return out.string() if out.num_states() else None - - -def main(): - lang, direction, path = sys.argv[1], sys.argv[2], sys.argv[3] - base = "text_normalization" if direction == "tn" else "inverse_text_normalization" - tagger = importlib.import_module(f"nemo_text_processing.{base}.{lang}.taggers.cardinal").CardinalFst().fst - verbalizer = importlib.import_module(f"nemo_text_processing.{base}.{lang}.verbalizers.cardinal").CardinalFst().fst - - passed = failed = 0 - with open(path, encoding="utf-8") as f: - for line in f: - line = line.rstrip("\n") - if not line.strip() or "~" not in line: - continue - inp, expected = [s.strip() for s in line.split("~", 1)] - tagged = apply_fst(tagger, inp) - result = apply_fst(verbalizer, tagged) if tagged is not None else None - if result == expected: - passed += 1 - else: - failed += 1 - print(f"FAIL: {inp!r} -> got {result!r}, expected {expected!r}") - - print(f"\n{passed} passed, {failed} failed.") - sys.exit(1 if failed else 0) - - -if __name__ == "__main__": - main() From a0cd9099b736f297db51ecc7503f52d04a6b9d9d Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 8 Jul 2026 11:04:08 +0530 Subject: [PATCH 12/29] Updated Cardinal Signed-off-by: surendran-246 --- .../text_normalization/ta/taggers/cardinal.py | 809 ++++++++---------- 1 file changed, 371 insertions(+), 438 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index df8ecabb5..bc4eb1806 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -1,3 +1,5 @@ + + # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,445 +16,376 @@ import pynini from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import ( - NEMO_ALL_DIGIT, - NEMO_ALL_ZERO, - GraphFst, - insert_space, + NEMO_ALL_DIGIT, + NEMO_ALL_ZERO, + GraphFst, + insert_space, ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path - class CardinalFst(GraphFst): - """ - Finite state transducer for classifying cardinals, e.g. - -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } - Args: - deterministic: if True will provide a single transduction option, - for False multiple transduction are generated (used for audio-based normalization) - """ - - def __init__(self, deterministic: bool = True, lm: bool = False): - super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) - zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) - hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) - teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) - teens_ties = pynini.union(teens_ties_hi, teens_ties_en) - teens_and_ties = pynutil.add_weight(teens_ties, -0.1) - self.digit = digit - self.zero = zero - self.hundred_ta = hundred_ta - self.teens_and_ties = teens_and_ties - # single_digit early — covers ASCII + Tamil digits + zero - single_digit = digit | zero - # Single digit graph for digit-by-digit reading - single_digit_graph = digit | zero - self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) - zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - - def create_graph_suffix(digit_graph, suffix, zeros_counts): - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix - return digit_graph + (z**zeros_counts) + suffix - - def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): - ins = pynutil.insert(" ") - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix + ins + sub_graph - return digit_graph + suffix + (z**zeros_counts) + ins + sub_graph - - # HUNDREDS GRAPH - # Use hundred_ta.tsv for fused exact hundreds (நூற்று, இருநூற்று, ... - # எட்டுநூற்று, எழுநூற்று, நானூற்று etc.) - # For 101-199: நூற்று + space + remainder - # For 201-999: fused prefix (no space) + space + remainder - # Fused hundred prefix for composites (201-999 non-exact) - fused_hundred_prefix = pynini.union( - pynini.cross("2", "இருநூற்று"), - pynini.cross("3", "முந்நூற்று"), - pynini.cross("4", "நானூற்று"), - pynini.cross("5", "ஐந்நூற்று"), - pynini.cross("6", "அறுநூற்று"), - pynini.cross("7", "எழுநூற்று"), - pynini.cross("8", "எட்டுநூற்று"), - pynini.cross("9", "ஒன்பதுநூற்று"), - pynini.cross("௨", "இருநூற்று"), - pynini.cross("௩", "முந்நூற்று"), - pynini.cross("௪", "நானூற்று"), - pynini.cross("௫", "ஐந்நூற்று"), - pynini.cross("௬", "அறுநூற்று"), - pynini.cross("௭", "எழுநூற்று"), - pynini.cross("௮", "எட்டுநூற்று"), - pynini.cross("௯", "ஒன்பதுநூற்று"), - ).optimize() - # Start with fused exact forms from hundred_ta.tsv - exact_hundred = pynutil.add_weight( - pynini.union( - pynini.cross("100", "நூறு"), - pynini.cross("௧௦௦", "நூறு"), - ).optimize(), - -1.0, - ) - graph_hundreds = hundred_ta - # 101-109 (ASCII and Tamil digits) - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + zero_delete - + pynutil.insert(" ") - + single_digit - ) - # 110-119 - graph_hundreds |= (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + pynutil.insert(" ") + teens_ties - # 201-209, 301-309 ... 901-909 - graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit - # 210-219 ... 910-919 - graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties - # 220-299 ... 920-999 (two-digit tie/tens tail already in teens_ties) - # teens_ties handles 20,21,...99 so this covers the remaining composites - graph_hundreds = graph_hundreds.optimize() - self.graph_hundreds = graph_hundreds - # THOUSANDS GRAPH - # 1000 → ஆயிரம் (exact, no leading ஒன்று) - # 1001-1099 → ஆயிரத்து + space + remainder - # 1100-1999 → ஆயிரத்து + space + graph_hundreds - # 2000-9000 → fused exact (இரண்டாயிரம், மூன்றாயிரம் ...) - # 2001-9999 → fused prefix (ஐந்தாயிரத்து ...) + space + remainder - one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") - one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") - fused_thousands_exact = pynini.union( - pynini.cross("2", "இரண்டாயிரம்"), - pynini.cross("3", "மூன்றாயிரம்"), - pynini.cross("4", "நான்காயிரம்"), - pynini.cross("5", "ஐந்தாயிரம்"), - pynini.cross("6", "ஆறாயிரம்"), - pynini.cross("7", "ஏழாயிரம்"), - pynini.cross("8", "எட்டாயிரம்"), - pynini.cross("9", "ஒன்பதாயிரம்"), - pynini.cross("௨", "இரண்டாயிரம்"), - pynini.cross("௩", "மூன்றாயிரம்"), - pynini.cross("௪", "நான்காயிரம்"), - pynini.cross("௫", "ஐந்தாயிரம்"), - pynini.cross("௬", "ஆறாயிரம்"), - pynini.cross("௭", "ஏழாயிரம்"), - pynini.cross("௮", "எட்டாயிரம்"), - pynini.cross("௯", "ஒன்பதாயிரம்"), - ).optimize() - fused_thousands_prefix = pynini.union( - pynini.cross("2", "இரண்டாயிரத்து"), - pynini.cross("3", "மூன்றாயிரத்து"), - pynini.cross("4", "நான்காயிரத்து"), - pynini.cross("5", "ஐந்தாயிரத்து"), - pynini.cross("6", "ஆறாயிரத்து"), - pynini.cross("7", "ஏழாயிரத்து"), - pynini.cross("8", "எட்டாயிரத்து"), - pynini.cross("9", "ஒன்பதாயிரத்து"), - pynini.cross("௨", "இரண்டாயிரத்து"), - pynini.cross("௩", "மூன்றாயிரத்து"), - pynini.cross("௪", "நான்காயிரத்து"), - pynini.cross("௫", "ஐந்தாயிரத்து"), - pynini.cross("௬", "ஆறாயிரத்து"), - pynini.cross("௭", "ஏழாயிரத்து"), - pynini.cross("௮", "எட்டாயிரத்து"), - pynini.cross("௯", "ஒன்பதாயிரத்து"), - ).optimize() - # 1000 exact - graph_thousands = one_k_exact + (zero_delete**3) - # 1001-1009 - graph_thousands |= one_k_tail + (zero_delete**2) + pynutil.insert(" ") + single_digit - # 1010-1099 - graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties - # 1100-1999 - graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds - # 2000-9000 exact - graph_thousands |= fused_thousands_exact + (zero_delete**3) - # 2001-9009 - graph_thousands |= fused_thousands_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit - # 2010-9099 - graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties - # 2100-9999 - graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds - graph_thousands = graph_thousands.optimize() - self.graph_thousands = graph_thousands - # TEN-THOUSANDS GRAPH - # e.g. 55000 → ஐம்பத்தைந்தாயிரம், 55199 → ஐம்பத்தைந்தாயிரத்து ... - # teens_and_ties already covers 10-99; we fuse them with ஆயிரம்/ஆயிரத்து - suffix_ten_k_exact = pynutil.insert("ஆயிரம்") - suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") - # exact ten-thousands (X0000 where X is a two-digit teens/ties) - graph_ten_thousands = create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) - # +single digit tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) - # +teens tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) - # +hundreds tail - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) - graph_ten_thousands = graph_ten_thousands.optimize() - self.graph_ten_thousands = graph_ten_thousands - - # LAKHS — இலட்சம் / இலட்சத்து - suffix_lakhs = pynutil.insert(" இலட்சம்") - suffix_lakhs_tail = pynutil.insert(" இலட்சத்து") - digit_one_as_oru = pynini.union( - pynini.cross("1", "ஒன்று"), - pynini.cross("௧", "ஒன்று"), - pynini.cross("2", "இரண்டு"), - pynini.cross("3", "மூன்று"), - pynini.cross("4", "நான்கு"), - pynini.cross("5", "ஐந்து"), - pynini.cross("6", "ஆறு"), - pynini.cross("7", "ஏழு"), - pynini.cross("8", "எட்டு"), - pynini.cross("9", "ஒன்பது"), - pynini.cross("௨", "இரண்டு"), - pynini.cross("௩", "மூன்று"), - pynini.cross("௪", "நான்கு"), - pynini.cross("௫", "ஐந்து"), - pynini.cross("௬", "ஆறு"), - pynini.cross("௭", "ஏழு"), - pynini.cross("௮", "எட்டு"), - pynini.cross("௯", "ஒன்பது"), - ).optimize() - graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_lakhs = graph_lakhs.optimize() - self.graph_lakhs = graph_lakhs - graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_ten_lakhs.optimize() - self.graph_ten_lakhs = graph_ten_lakhs - - # CRORES — கோடி / கோடியே - suffix_crores = pynutil.insert(" கோடி") - suffix_crores_tail = pynutil.insert(" கோடியே") - graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores = graph_crores.optimize() - graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_crores.optimize() - - # ARABS - suffix_arabs = pynutil.insert(" அரபு") - graph_arabs = create_graph_suffix(digit_one_as_oru, suffix_arabs, 9) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 8, single_digit) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 7, teens_ties) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 6, graph_hundreds) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 5, graph_thousands) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 4, graph_ten_thousands) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 3, graph_lakhs) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 2, graph_ten_lakhs) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 1, graph_crores) - graph_arabs |= create_larger_number_graph(digit_one_as_oru, suffix_arabs, 0, graph_ten_crores) - graph_arabs.optimize() - graph_ten_arabs = create_graph_suffix(teens_and_ties, suffix_arabs, 9) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 8, single_digit) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 7, teens_ties) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 6, graph_hundreds) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 5, graph_thousands) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 4, graph_ten_thousands) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 3, graph_lakhs) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 2, graph_ten_lakhs) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 1, graph_crores) - graph_ten_arabs |= create_larger_number_graph(teens_and_ties, suffix_arabs, 0, graph_ten_crores) - graph_ten_arabs.optimize() - - # KHARABS - suffix_kharabs = pynutil.insert(" கரபு") - graph_kharabs = create_graph_suffix(digit_one_as_oru, suffix_kharabs, 11) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 10, single_digit) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 9, teens_ties) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 8, graph_hundreds) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 7, graph_thousands) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 6, graph_ten_thousands) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 5, graph_lakhs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 4, graph_ten_lakhs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 3, graph_crores) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 2, graph_ten_crores) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 1, graph_arabs) - graph_kharabs |= create_larger_number_graph(digit_one_as_oru, suffix_kharabs, 0, graph_ten_arabs) - graph_kharabs.optimize() - graph_ten_kharabs = create_graph_suffix(teens_and_ties, suffix_kharabs, 11) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 10, single_digit) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 9, teens_ties) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 8, graph_hundreds) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 7, graph_thousands) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 6, graph_ten_thousands) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 5, graph_lakhs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 4, graph_ten_lakhs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 3, graph_crores) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 2, graph_ten_crores) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 1, graph_arabs) - graph_ten_kharabs |= create_larger_number_graph(teens_and_ties, suffix_kharabs, 0, graph_ten_arabs) - graph_ten_kharabs.optimize() - - # NILS - suffix_nils = pynutil.insert(" நீல்") - graph_nils = create_graph_suffix(digit_one_as_oru, suffix_nils, 13) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 12, single_digit) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 11, teens_ties) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 10, graph_hundreds) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 9, graph_thousands) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 8, graph_ten_thousands) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 7, graph_lakhs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 6, graph_ten_lakhs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 5, graph_crores) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 4, graph_ten_crores) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 3, graph_arabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 2, graph_ten_arabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 1, graph_kharabs) - graph_nils |= create_larger_number_graph(digit_one_as_oru, suffix_nils, 0, graph_ten_kharabs) - graph_nils.optimize() - graph_ten_nils = create_graph_suffix(teens_and_ties, suffix_nils, 13) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 12, single_digit) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 11, teens_ties) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 10, graph_hundreds) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 9, graph_thousands) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 8, graph_ten_thousands) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 7, graph_lakhs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 6, graph_ten_lakhs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 5, graph_crores) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 4, graph_ten_crores) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 3, graph_arabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 2, graph_ten_arabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 1, graph_kharabs) - graph_ten_nils |= create_larger_number_graph(teens_and_ties, suffix_nils, 0, graph_ten_kharabs) - graph_ten_nils.optimize() - - # PADMAS - suffix_padmas = pynutil.insert(" பத்மம்") - graph_padmas = create_graph_suffix(digit_one_as_oru, suffix_padmas, 15) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 14, single_digit) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 13, teens_ties) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 12, graph_hundreds) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 11, graph_thousands) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 10, graph_ten_thousands) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 9, graph_lakhs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 8, graph_ten_lakhs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 7, graph_crores) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 6, graph_ten_crores) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 5, graph_arabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 4, graph_ten_arabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 3, graph_kharabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 2, graph_ten_kharabs) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 1, graph_nils) - graph_padmas |= create_larger_number_graph(digit_one_as_oru, suffix_padmas, 0, graph_ten_nils) - graph_padmas.optimize() - graph_ten_padmas = create_graph_suffix(teens_and_ties, suffix_padmas, 15) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 14, single_digit) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 13, teens_ties) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 12, graph_hundreds) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 11, graph_thousands) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 10, graph_ten_thousands) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 9, graph_lakhs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 8, graph_ten_lakhs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 7, graph_crores) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 6, graph_ten_crores) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 5, graph_arabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 4, graph_ten_arabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 3, graph_kharabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 2, graph_ten_kharabs) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 1, graph_nils) - graph_ten_padmas |= create_larger_number_graph(teens_and_ties, suffix_padmas, 0, graph_ten_nils) - graph_ten_padmas.optimize() - - # SHANKHS - suffix_shankhs = pynutil.insert(" சங்கம்") - graph_shankhs = create_graph_suffix(digit_one_as_oru, suffix_shankhs, 17) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 16, single_digit) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 15, teens_ties) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 14, graph_hundreds) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 13, graph_thousands) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 12, graph_ten_thousands) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 11, graph_lakhs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 10, graph_ten_lakhs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 9, graph_crores) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 8, graph_ten_crores) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 7, graph_arabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 6, graph_ten_arabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 5, graph_kharabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 4, graph_ten_kharabs) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 3, graph_nils) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 2, graph_ten_nils) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 1, graph_padmas) - graph_shankhs |= create_larger_number_graph(digit_one_as_oru, suffix_shankhs, 0, graph_ten_padmas) - graph_shankhs.optimize() - graph_ten_shankhs = create_graph_suffix(teens_and_ties, suffix_shankhs, 17) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 16, single_digit) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 15, teens_ties) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 14, graph_hundreds) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 13, graph_thousands) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 12, graph_ten_thousands) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 11, graph_lakhs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 10, graph_ten_lakhs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 9, graph_crores) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 8, graph_ten_crores) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 7, graph_arabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 6, graph_ten_arabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 5, graph_kharabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 4, graph_ten_kharabs) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 3, graph_nils) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 2, graph_ten_nils) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 1, graph_padmas) - graph_ten_shankhs |= create_larger_number_graph(teens_and_ties, suffix_shankhs, 0, graph_ten_padmas) - graph_ten_shankhs.optimize() - - # LEADING ZERO and FINAL GRAPH - graph_leading_zero = zero + insert_space + single_digit - graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) - graph_without_leading_zeros = ( - digit - | zero - | teens_and_ties - | exact_hundred - | graph_hundreds - | graph_thousands - | graph_ten_thousands - | graph_lakhs - | graph_ten_lakhs - | graph_crores - | graph_ten_crores - | graph_arabs - | graph_ten_arabs - | graph_kharabs - | graph_ten_kharabs - | graph_nils - | graph_ten_nils - | graph_padmas - | graph_ten_padmas - | graph_shankhs - | graph_ten_shankhs - ) - self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() - cardinal_with_leading_zeros = pynini.compose( - NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph - ) - cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) - final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros - optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) - self.final_graph = final_graph.optimize() - final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") - final_graph = self.add_tokens(final_graph) - self.fst = final_graph + """ + Finite state transducer for classifying cardinals, e.g. + -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } + The highest unit used is கோடி. + """ + def __init__(self, deterministic: bool = True, lm: bool = False): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) + teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) + teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) + teens_ties = pynini.union(teens_ties_hi, teens_ties_en) + teens_and_ties = pynutil.add_weight(teens_ties, -0.1) + self.digit = digit + self.zero = zero + self.hundred_ta = hundred_ta + self.teens_and_ties = teens_and_ties + + single_digit = digit | zero + single_digit_graph = digit | zero + self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) + zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + + def create_graph_suffix(digit_graph, suffix, zeros_counts): + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + return digit_graph + (z ** zeros_counts) + suffix + + def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): + ins = pynutil.insert(" ") + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + ins + sub_graph + return digit_graph + suffix + (z ** zeros_counts) + ins + sub_graph + + # HUNDREDS GRAPH (100-999) + + # exact 100 → நூறு + exact_hundred = pynutil.add_weight(pynini.union( + pynini.cross("100", "நூறு"), + pynini.cross("௧௦௦", "நூறு"), + ).optimize(), -1.0) + + # hundred prefixes: 200-900 + fused_hundred_prefix = pynini.union( + pynini.cross("2", "இருநூற்று"), + pynini.cross("3", "முந்நூற்று"), + pynini.cross("4", "நானூற்று"), + pynini.cross("5", "ஐநூற்று"), + pynini.cross("6", "அறுநூற்று"), + pynini.cross("7", "எழுநூற்று"), + pynini.cross("8", "எட்டுநூற்று"), + pynini.cross("9", "ஒன்பதுநூற்று"), + pynini.cross("௨", "இருநூற்று"), + pynini.cross("௩", "முந்நூற்று"), + pynini.cross("௪", "நானூற்று"), + pynini.cross("௫", "ஐநூற்று"), + pynini.cross("௬", "அறுநூற்று"), + pynini.cross("௭", "எழுநூற்று"), + pynini.cross("௮", "எட்டுநூற்று"), + pynini.cross("௯", "ஒன்பதுநூற்று"), + ).optimize() + + graph_hundreds = hundred_ta + # 101-109 + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + zero_delete + pynutil.insert(" ") + single_digit + ) + # 110-199 + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + pynutil.insert(" ") + teens_ties + ) + # 201-209 ... 901-909 + graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit + # 210-999 + graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties + graph_hundreds = graph_hundreds.optimize() + self.graph_hundreds = graph_hundreds + + # THOUSANDS GRAPH (1000-9999) + # 1000-1999 → ஆயிரம்/ஆயிரத்து + one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") + one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") + # 2000-9000 + fused_thousands_exact = pynini.union( + pynini.cross("2", "இரண்டாயிரம்"), + pynini.cross("3", "மூவாயிரம்"), + pynini.cross("4", "நான்காயிரம்"), + pynini.cross("5", "ஐந்தாயிரம்"), + pynini.cross("6", "ஆறாயிரம்"), + pynini.cross("7", "ஏழாயிரம்"), + pynini.cross("8", "எட்டாயிரம்"), + pynini.cross("9", "ஒன்பதாயிரம்"), + pynini.cross("௨", "இரண்டாயிரம்"), + pynini.cross("௩", "மூவாயிரம்"), + pynini.cross("௪", "நான்காயிரம்"), + pynini.cross("௫", "ஐந்தாயிரம்"), + pynini.cross("௬", "ஆறாயிரம்"), + pynini.cross("௭", "ஏழாயிரம்"), + pynini.cross("௮", "எட்டாயிரம்"), + pynini.cross("௯", "ஒன்பதாயிரம்"), + ).optimize() + + fused_thousands_prefix = pynini.union( + pynini.cross("2", "இரண்டாயிரத்து"), + pynini.cross("3", "மூவாயிரத்து"), + pynini.cross("4", "நான்காயிரத்து"), + pynini.cross("5", "ஐந்தாயிரத்து"), + pynini.cross("6", "ஆறாயிரத்து"), + pynini.cross("7", "ஏழாயிரத்து"), + pynini.cross("8", "எட்டாயிரத்து"), + pynini.cross("9", "ஒன்பதாயிரத்து"), + pynini.cross("௨", "இரண்டாயிரத்து"), + pynini.cross("௩", "மூவாயிரத்து"), + pynini.cross("௪", "நான்காயிரத்து"), + pynini.cross("௫", "ஐந்தாயிரத்து"), + pynini.cross("௬", "ஆறாயிரத்து"), + pynini.cross("௭", "ஏழாயிரத்து"), + pynini.cross("௮", "எட்டாயிரத்து"), + pynini.cross("௯", "ஒன்பதாயிரத்து"), + ).optimize() + + graph_thousands = one_k_exact + (zero_delete ** 3) + graph_thousands |= one_k_tail + (zero_delete ** 2) + pynutil.insert(" ") + single_digit + graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties + graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds + graph_thousands |= fused_thousands_exact + (zero_delete ** 3) + graph_thousands |= fused_thousands_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit + graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties + graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds + graph_thousands = graph_thousands.optimize() + self.graph_thousands = graph_thousands + + # TEN-THOUSANDS GRAPH (10000-99999) + # 10000-19999 + fused_ten_k_exact = pynini.union( + pynini.cross("௧௩", "பதிமூன்றுஆயிரம்"), + pynini.cross("௧௨", "பன்னிரண்டுஆயிரம்"), + pynini.cross("௧௧", "பதினொன்றுஆயிரம்"), + pynini.cross("௪௫", "நாற்பத்தைந்தாயிரம்"), + pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரம்"), + ).optimize() + + fused_ten_k_prefix = pynini.union( + pynini.cross("௧௩", "பதிமூன்றுஆயிரத்து"), + pynini.cross("௧௨", "பன்னிரண்டுஆயிரத்து"), + pynini.cross("௧௧", "பதினொன்றுஆயிரத்து"), + pynini.cross("௪௫", "நாற்பத்தைந்தாயிரத்து"), + pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரத்து"), + ).optimize() + + suffix_ten_k_exact = pynutil.insert("ஆயிரம்") + suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") + + graph_ten_thousands = fused_ten_k_exact + (zero_delete ** 3) + graph_ten_thousands |= fused_ten_k_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit + graph_ten_thousands |= fused_ten_k_prefix + zero_delete + pynutil.insert(" ") + teens_ties + graph_ten_thousands |= fused_ten_k_prefix + pynutil.insert(" ") + graph_hundreds + graph_ten_thousands |= create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) + graph_ten_thousands = graph_ten_thousands.optimize() + self.graph_ten_thousands = graph_ten_thousands + + # LAKHS GRAPH (100000-9999999) + # 1 lakh → ஒரு லட்சம் + suffix_lakhs = pynutil.insert(" லட்சம்") + suffix_lakhs_tail = pynutil.insert(" லட்சத்து") + + digit_one_as_oru = pynini.union( + pynini.cross("1", "ஒரு"), + pynini.cross("௧", "ஒரு"), + pynini.cross("2", "இரண்டு"), + pynini.cross("3", "மூன்று"), + pynini.cross("4", "நான்கு"), + pynini.cross("5", "ஐந்து"), + pynini.cross("6", "ஆறு"), + pynini.cross("7", "ஏழு"), + pynini.cross("8", "எட்டு"), + pynini.cross("9", "ஒன்பது"), + pynini.cross("௨", "இரண்டு"), + pynini.cross("௩", "மூன்று"), + pynini.cross("௪", "நான்கு"), + pynini.cross("௫", "ஐந்து"), + pynini.cross("௬", "ஆறு"), + pynini.cross("௭", "ஏழு"), + pynini.cross("௮", "எட்டு"), + pynini.cross("௯", "ஒன்பது"), + ).optimize() + + graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_lakhs = graph_lakhs.optimize() + self.graph_lakhs = graph_lakhs + + graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_ten_lakhs = graph_ten_lakhs.optimize() + self.graph_ten_lakhs = graph_ten_lakhs + + # CRORES GRAPH — கோடி + # 1 crore → ஒரு கோடி / ஒரு கோடியே + suffix_crores = pynutil.insert(" கோடி") + suffix_crores_tail = pynutil.insert(" கோடியே") + + graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores = graph_crores.optimize() + + graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_crores = graph_ten_crores.optimize() + + # hundreds of crores: 100-999 கோடி + graph_hundreds_of_crores = create_graph_suffix(exact_hundred, suffix_crores, 7) + graph_hundreds_of_crores |= create_graph_suffix(graph_hundreds, suffix_crores, 7) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 6, single_digit) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 5, teens_ties) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 4, graph_hundreds) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 3, graph_thousands) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 2, graph_ten_thousands) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 1, graph_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 0, graph_ten_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 6, single_digit) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 5, teens_ties) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 4, graph_hundreds) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 3, graph_thousands) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 2, graph_ten_thousands) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 1, graph_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 0, graph_ten_lakhs) + graph_hundreds_of_crores = graph_hundreds_of_crores.optimize() + + # thousands of crores: 1000-9999 கோடி + graph_thousands_of_crores = create_graph_suffix(graph_thousands, suffix_crores, 7) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 6, single_digit) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 5, teens_ties) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 4, graph_hundreds) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 3, graph_thousands) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 2, graph_ten_thousands) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 1, graph_lakhs) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 0, graph_ten_lakhs) + graph_thousands_of_crores = graph_thousands_of_crores.optimize() + + # ten-thousands of crores + graph_ten_thousands_of_crores = create_graph_suffix(graph_ten_thousands, suffix_crores, 7) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 6, single_digit) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 5, teens_ties) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 4, graph_hundreds) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 3, graph_thousands) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 1, graph_lakhs) + graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_thousands_of_crores = graph_ten_thousands_of_crores.optimize() + + # lakhs of crores + graph_lakhs_of_crores = create_graph_suffix(graph_lakhs, suffix_crores, 7) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 6, single_digit) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 5, teens_ties) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 4, graph_hundreds) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 3, graph_thousands) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 2, graph_ten_thousands) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 1, graph_lakhs) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) + graph_lakhs_of_crores = graph_lakhs_of_crores.optimize() + + graph_ten_lakhs_of_crores = create_graph_suffix(graph_ten_lakhs, suffix_crores, 7) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 6, single_digit) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 5, teens_ties) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 4, graph_hundreds) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 3, graph_thousands) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 1, graph_lakhs) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_lakhs_of_crores = graph_ten_lakhs_of_crores.optimize() + + # crores of crores + graph_crores_of_crores = create_graph_suffix(graph_crores, suffix_crores, 7) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 6, single_digit) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 5, teens_ties) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 4, graph_hundreds) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 3, graph_thousands) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 1, graph_lakhs) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores_of_crores = graph_crores_of_crores.optimize() + + graph_ten_crores_of_crores = create_graph_suffix(graph_ten_crores, suffix_crores, 7) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 6, single_digit) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 5, teens_ties) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 4, graph_hundreds) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 3, graph_thousands) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_crores_of_crores = graph_ten_crores_of_crores.optimize() + + # LEADING ZERO and FINAL GRAPH + graph_leading_zero = zero + insert_space + single_digit + graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) + + graph_without_leading_zeros = ( + digit + | zero + | teens_and_ties + | exact_hundred + | graph_hundreds + | graph_thousands + | graph_ten_thousands + | graph_lakhs + | graph_ten_lakhs + | graph_crores + | graph_ten_crores + | graph_hundreds_of_crores + | graph_thousands_of_crores + | graph_ten_thousands_of_crores + | graph_lakhs_of_crores + | graph_ten_lakhs_of_crores + | graph_crores_of_crores + | graph_ten_crores_of_crores + ) + self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() + + cardinal_with_leading_zeros = pynini.compose( + NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph + ) + cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) + + final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros + optional_minus_graph = pynini.closure( + pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1 + ) + self.final_graph = final_graph.optimize() + final_graph = ( + optional_minus_graph + + pynutil.insert("integer: \"") + + self.final_graph + + pynutil.insert("\"") + ) + final_graph = self.add_tokens(final_graph) + self.fst = final_graph From 4761e6754da300b10da385093a3d1d3a8badcf18 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 8 Jul 2026 11:42:11 +0530 Subject: [PATCH 13/29] Added Cardinal Signed-off-by: surendran-246 --- .../test_cases_cardinal.txt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt index 0ab12369a..81fa9b10a 100644 --- a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt +++ b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt @@ -5,7 +5,7 @@ ௪ ஓவரில் ௧௭ ரன்கள்~நான்கு ஓவரில் பதினேழு ரன்கள் ௫ சாக்லெட்டுகள் ௯ டாஃபிகள்~ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள் ௧௦௦௯௯~பத்துஆயிரத்து தொண்ணூற்று ஒன்பது -௧௦௦௦௦௧~ஒன்று இலட்சத்து ஒன்று +௧௦௦௦௦௧~ஒரு லட்சத்து ஒன்று ௪ சிக்ஸர்கள் ௧௪ நான்குகள்~நான்கு சிக்ஸர்கள் பதினான்கு நான்குகள் ௬ ரன்கள் எடுத்தார்~ஆறு ரன்கள் எடுத்தார் ௩ கோல்கள் அடித்தார்~மூன்று கோல்கள் அடித்தார் @@ -16,7 +16,7 @@ ௫ கோல்கள் அடி~ஐந்து கோல்கள் அடி ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள்~மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் ௫ தோல்வி ௧ டிரா ௧௭ வெற்றி~ஐந்து தோல்வி ஒன்று டிரா பதினேழு வெற்றி -௫௧௦௨௨௩௪௫௫௬௭~ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு பாடம் ௧௦ ஸ்லோகம் ௨~பாடம் பத்து ஸ்லோகம் இரண்டு ௧௦௧~நூற்று ஒன்று ௧௦௨~நூற்று இரண்டு @@ -76,8 +76,8 @@ ௧௯௯~நூற்று தொண்ணூற்று ஒன்பது ௧௦௦௧~ஆயிரத்து ஒன்று ௧௦௯௯~ஆயிரத்து தொண்ணூற்று ஒன்பது -௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐந்நூற்று ஐம்பத்து ஒன்று வாழைப்பழங்கள் -௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்து ஐந்துஆயிரத்து ஐந்நூற்று ஐம்பத்து இரண்டு ஆப்பிள்கள் +௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐநூற்று ஐம்பத்து ஒன்று வாழைப்பழங்கள் +௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்து ஐந்துஆயிரத்து ஐநூற்று ஐம்பத்து இரண்டு ஆப்பிள்கள் ௫௩~ஐம்பத்து மூன்று ௫௪~ஐம்பத்து நான்கு ௫௫~ஐம்பத்து ஐந்து @@ -129,17 +129,17 @@ ௧௩௪௫~ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து ௧௩௪௫௬~பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு ௧௨௩௪௬~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு -௧௨௩௪௫௬~ஒன்று இலட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு -௮௭௨௯௮௭~எட்டு இலட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு -௯௮௭௬௦௯~ஒன்பது இலட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது -௯௮௭௬௭௮௯~தொண்ணூற்று எட்டு இலட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது -௨௩௪௫௫௬௭~இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு -௧௨௩௪௫௫௬௭~ஒன்று கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு -௧௨௧௨௧௨௧௨~ஒன்று கோடியே இருபத்து ஒன்று இலட்சத்து இருபத்து ஒன்றுஆயிரத்து இருநூற்று பன்னிரண்டு -௧௧௨௨௩௪௫௫௬௭~ஒன்று அரபு பன்னிரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு -௧௦௨௨௩௪௫௫௬௭~ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு -௧௧௦௨௨௩௪௫௫௬௭~பதினொன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு -௫௧௦௨௨௩௪௫௫௬௭~ஐம்பத்து ஒன்று அரபு இரண்டு கோடியே இருபத்து மூன்று இலட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐந்நூற்று அறுபத்து ஏழு +௧௨௩௪௫௬~ஒரு லட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு +௮௭௨௯௮௭~எட்டு லட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு +௯௮௭௬௦௯~ஒன்பது லட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது +௯௮௭௬௭௮௯~தொண்ணூற்று எட்டு லட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது +௨௩௪௫௫௬௭~இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௧௨௩௪௫௫௬௭~ஒரு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௧௨௧௨௧௨௧௨~ஒரு கோடியே இருபத்து ஒன்று லட்சத்து இருபத்து ஒன்றுஆயிரத்து இருநூற்று பன்னிரண்டு +௧௧௨௨௩௪௫௫௬௭~நூற்று பன்னிரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௧௦௨௨௩௪௫௫௬௭~நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௧௧௦௨௨௩௪௫௫௬௭~ஆயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு ௨ புள்ளிகள் ௧௨ கோல்கள்~இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் ௦௫~சுழியம் ஐந்து ௦௧~சுழியம் ஒன்று From 301db6f9eec2b78a59cf7f8f6a91cda9490c43bc Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 8 Jul 2026 11:48:36 +0530 Subject: [PATCH 14/29] Ta cardinal Signed-off-by: surendran-246 --- .../ta/data/numbers/teens_and_ties.tsv | 144 +++++++++--------- .../ta/data/numbers/teens_and_ties_en.tsv | 144 +++++++++--------- .../test_cases_cardinal.txt | 2 +- 3 files changed, 145 insertions(+), 145 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv index 4b1c3686c..058253fa1 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties.tsv @@ -9,82 +9,82 @@ ௧௮ பதினெட்டு ௧௯ பத்தொன்பது ௨௦ இருபது -௨௧ இருபத்து ஒன்று -௨௨ இருபத்து இரண்டு -௨௩ இருபத்து மூன்று -௨௪ இருபத்து நான்கு -௨௫ இருபத்து ஐந்து -௨௬ இருபத்து ஆறு -௨௭ இருபத்து ஏழு -௨௮ இருபத்து எட்டு -௨௯ இருபத்து ஒன்பது +௨௧ இருபத்தொன்று +௨௨ இருபத்திரண்டு +௨௩ இருபத்திமூன்று +௨௪ இருபத்திநான்கு +௨௫ இருபத்திஐந்து +௨௬ இருபத்திஆறு +௨௭ இருபத்திஏழு +௨௮ இருபத்திஎட்டு +௨௯ இருபத்திஒன்பது ௩௦ முப்பது -௩௧ முப்பத்து ஒன்று -௩௨ முப்பத்து இரண்டு -௩௩ முப்பத்து மூன்று -௩௪ முப்பத்து நான்கு -௩௫ முப்பத்து ஐந்து -௩௬ முப்பத்து ஆறு -௩௭ முப்பத்து ஏழு -௩௮ முப்பத்து எட்டு -௩௯ முப்பத்து ஒன்பது +௩௧ முப்பத்தொன்று +௩௨ முப்பத்திரண்டு +௩௩ முப்பத்திமூன்று +௩௪ முப்பத்திநான்கு +௩௫ முப்பத்திஐந்து +௩௬ முப்பத்திஆறு +௩௭ முப்பத்திஏழு +௩௮ முப்பத்திஎட்டு +௩௯ முப்பத்திஒன்பது ௪௦ நாற்பது -௪௧ நாற்பத்து ஒன்று -௪௨ நாற்பத்து இரண்டு -௪௩ நாற்பத்து மூன்று -௪௪ நாற்பத்து நான்கு -௪௫ நாற்பத்து ஐந்து -௪௬ நாற்பத்து ஆறு -௪௭ நாற்பத்து ஏழு -௪௮ நாற்பத்து எட்டு -௪௯ நாற்பத்து ஒன்பது +௪௧ நாற்பத்தொன்று +௪௨ நாற்பத்திரண்டு +௪௩ நாற்பத்திமூன்று +௪௪ நாற்பத்திநான்கு +௪௫ நாற்பத்திஐந்து +௪௬ நாற்பத்திஆறு +௪௭ நாற்பத்திஏழு +௪௮ நாற்பத்திஎட்டு +௪௯ நாற்பத்திஒன்பது ௫௦ ஐம்பது -௫௧ ஐம்பத்து ஒன்று -௫௨ ஐம்பத்து இரண்டு -௫௩ ஐம்பத்து மூன்று -௫௪ ஐம்பத்து நான்கு -௫௫ ஐம்பத்து ஐந்து -௫௬ ஐம்பத்து ஆறு -௫௭ ஐம்பத்து ஏழு -௫௮ ஐம்பத்து எட்டு -௫௯ ஐம்பத்து ஒன்பது +௫௧ ஐம்பத்தொன்று +௫௨ ஐம்பத்திரண்டு +௫௩ ஐம்பத்திமூன்று +௫௪ ஐம்பத்திநான்கு +௫௫ ஐம்பத்திஐந்து +௫௬ ஐம்பத்திஆறு +௫௭ ஐம்பத்திஏழு +௫௮ ஐம்பத்திஎட்டு +௫௯ ஐம்பத்திஒன்பது ௬௦ அறுபது -௬௧ அறுபத்து ஒன்று -௬௨ அறுபத்து இரண்டு -௬௩ அறுபத்து மூன்று -௬௪ அறுபத்து நான்கு -௬௫ அறுபத்து ஐந்து -௬௬ அறுபத்து ஆறு -௬௭ அறுபத்து ஏழு -௬௮ அறுபத்து எட்டு -௬௯ அறுபத்து ஒன்பது +௬௧ அறுபத்தொன்று +௬௨ அறுபத்திரண்டு +௬௩ அறுபத்திமூன்று +௬௪ அறுபத்திநான்கு +௬௫ அறுபத்திஐந்து +௬௬ அறுபத்திஆறு +௬௭ அறுபத்திஏழு +௬௮ அறுபத்திஎட்டு +௬௯ அறுபத்திஒன்பது ௭௦ எழுபது -௭௧ எழுபத்து ஒன்று -௭௨ எழுபத்து இரண்டு -௭௩ எழுபத்து மூன்று -௭௪ எழுபத்து நான்கு -௭௫ எழுபத்து ஐந்து -௭௬ எழுபத்து ஆறு -௭௭ எழுபத்து ஏழு -௭௮ எழுபத்து எட்டு -௭௯ எழுபத்து ஒன்பது +௭௧ எழுபத்தொன்று +௭௨ எழுபத்திரண்டு +௭௩ எழுபத்திமூன்று +௭௪ எழுபத்திநான்கு +௭௫ எழுபத்திஐந்து +௭௬ எழுபத்திஆறு +௭௭ எழுபத்திஏழு +௭௮ எழுபத்திஎட்டு +௭௯ எழுபத்திஒன்பது ௮௦ எண்பது -௮௧ எண்பத்து ஒன்று -௮௨ எண்பத்து இரண்டு -௮௩ எண்பத்து மூன்று -௮௪ எண்பத்து நான்கு -௮௫ எண்பத்து ஐந்து -௮௬ எண்பத்து ஆறு -௮௭ எண்பத்து ஏழு -௮௮ எண்பத்து எட்டு -௮௯ எண்பத்து ஒன்பது +௮௧ எண்பத்தொன்று +௮௨ எண்பத்திரண்டு +௮௩ எண்பத்திமூன்று +௮௪ எண்பத்திநான்கு +௮௫ எண்பத்திஐந்து +௮௬ எண்பத்திஆறு +௮௭ எண்பத்திஏழு +௮௮ எண்பத்திஎட்டு +௮௯ எண்பத்திஒன்பது ௯௦ தொண்ணூறு -௯௧ தொண்ணூற்று ஒன்று -௯௨ தொண்ணூற்று இரண்டு -௯௩ தொண்ணூற்று மூன்று -௯௪ தொண்ணூற்று நான்கு -௯௫ தொண்ணூற்று ஐந்து -௯௬ தொண்ணூற்று ஆறு -௯௭ தொண்ணூற்று ஏழு -௯௮ தொண்ணூற்று எட்டு -௯௯ தொண்ணூற்று ஒன்பது \ No newline at end of file +௯௧ தொண்ணூற்றொன்று +௯௨ தொண்ணூற்றிரண்டு +௯௩ தொண்ணூற்றிமூன்று +௯௪ தொண்ணூற்றிநான்கு +௯௫ தொண்ணூற்றிஐந்து +௯௬ தொண்ணூற்றிஆறு +௯௭ தொண்ணூற்றிஏழு +௯௮ தொண்ணூற்றிஎட்டு +௯௯ தொண்ணூற்றிஒன்பது \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv index 5e4e47be4..b796a9028 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/teens_and_ties_en.tsv @@ -9,82 +9,82 @@ 18 பதினெட்டு 19 பத்தொன்பது 20 இருபது -21 இருபத்து ஒன்று -22 இருபத்து இரண்டு -23 இருபத்து மூன்று -24 இருபத்து நான்கு -25 இருபத்து ஐந்து -26 இருபத்து ஆறு -27 இருபத்து ஏழு -28 இருபத்து எட்டு -29 இருபத்து ஒன்பது +21 இருபத்தொன்று +22 இருபத்திரண்டு +23 இருபத்திமூன்று +24 இருபத்திநான்கு +25 இருபத்திஐந்து +26 இருபத்திஆறு +27 இருபத்திஏழு +28 இருபத்திஎட்டு +29 இருபத்திஒன்பது 30 முப்பது -31 முப்பத்து ஒன்று -32 முப்பத்து இரண்டு -33 முப்பத்து மூன்று -34 முப்பத்து நான்கு -35 முப்பத்து ஐந்து -36 முப்பத்து ஆறு -37 முப்பத்து ஏழு -38 முப்பத்து எட்டு -39 முப்பத்து ஒன்பது +31 முப்பத்தொன்று +32 முப்பத்திரண்டு +33 முப்பத்திமூன்று +34 முப்பத்திநான்கு +35 முப்பத்திஐந்து +36 முப்பத்திஆறு +37 முப்பத்திஏழு +38 முப்பத்திஎட்டு +39 முப்பத்திஒன்பது 40 நாற்பது -41 நாற்பத்து ஒன்று -42 நாற்பத்து இரண்டு -43 நாற்பத்து மூன்று -44 நாற்பத்து நான்கு -45 நாற்பத்து ஐந்து -46 நாற்பத்து ஆறு -47 நாற்பத்து ஏழு -48 நாற்பத்து எட்டு -49 நாற்பத்து ஒன்பது +41 நாற்பத்தொன்று +42 நாற்பத்திரண்டு +43 நாற்பத்திமூன்று +44 நாற்பத்திநான்கு +45 நாற்பத்திஐந்து +46 நாற்பத்திஆறு +47 நாற்பத்திஏழு +48 நாற்பத்திஎட்டு +49 நாற்பத்திஒன்பது 50 ஐம்பது -51 ஐம்பத்து ஒன்று -52 ஐம்பத்து இரண்டு -53 ஐம்பத்து மூன்று -54 ஐம்பத்து நான்கு -55 ஐம்பத்து ஐந்து -56 ஐம்பத்து ஆறு -57 ஐம்பத்து ஏழு -58 ஐம்பத்து எட்டு -59 ஐம்பத்து ஒன்பது +51 ஐம்பத்தொன்று +52 ஐம்பத்திரண்டு +53 ஐம்பத்திமூன்று +54 ஐம்பத்திநான்கு +55 ஐம்பத்திஐந்து +56 ஐம்பத்திஆறு +57 ஐம்பத்திஏழு +58 ஐம்பத்திஎட்டு +59 ஐம்பத்திஒன்பது 60 அறுபது -61 அறுபத்து ஒன்று -62 அறுபத்து இரண்டு -63 அறுபத்து மூன்று -64 அறுபத்து நான்கு -65 அறுபத்து ஐந்து -66 அறுபத்து ஆறு -67 அறுபத்து ஏழு -68 அறுபத்து எட்டு -69 அறுபத்து ஒன்பது +61 அறுபத்தொன்று +62 அறுபத்திரண்டு +63 அறுபத்திமூன்று +64 அறுபத்திநான்கு +65 அறுபத்திஐந்து +66 அறுபத்திஆறு +67 அறுபத்திஏழு +68 அறுபத்திஎட்டு +69 அறுபத்திஒன்பது 70 எழுபது -71 எழுபத்து ஒன்று -72 எழுபத்து இரண்டு -73 எழுபத்து மூன்று -74 எழுபத்து நான்கு -75 எழுபத்து ஐந்து -76 எழுபத்து ஆறு -77 எழுபத்து ஏழு -78 எழுபத்து எட்டு -79 எழுபத்து ஒன்பது +71 எழுபத்தொன்று +72 எழுபத்திரண்டு +73 எழுபத்திமூன்று +74 எழுபத்திநான்கு +75 எழுபத்திஐந்து +76 எழுபத்திஆறு +77 எழுபத்திஏழு +78 எழுபத்திஎட்டு +79 எழுபத்திஒன்பது 80 எண்பது -81 எண்பத்து ஒன்று -82 எண்பத்து இரண்டு -83 எண்பத்து மூன்று -84 எண்பத்து நான்கு -85 எண்பத்து ஐந்து -86 எண்பத்து ஆறு -87 எண்பத்து ஏழு -88 எண்பத்து எட்டு -89 எண்பத்து ஒன்பது +81 எண்பத்தொன்று +82 எண்பத்திரண்டு +83 எண்பத்திமூன்று +84 எண்பத்திநான்கு +85 எண்பத்திஐந்து +86 எண்பத்திஆறு +87 எண்பத்திஏழு +88 எண்பத்திஎட்டு +89 எண்பத்திஒன்பது 90 தொண்ணூறு -91 தொண்ணூற்று ஒன்று -92 தொண்ணூற்று இரண்டு -93 தொண்ணூற்று மூன்று -94 தொண்ணூற்று நான்கு -95 தொண்ணூற்று ஐந்து -96 தொண்ணூற்று ஆறு -97 தொண்ணூற்று ஏழு -98 தொண்ணூற்று எட்டு -99 தொண்ணூற்று ஒன்பது \ No newline at end of file +91 தொண்ணூற்றொன்று +92 தொண்ணூற்றிரண்டு +93 தொண்ணூற்றிமூன்று +94 தொண்ணூற்றிநான்கு +95 தொண்ணூற்றிஐந்து +96 தொண்ணூற்றிஆறு +97 தொண்ணூற்றிஏழு +98 தொண்ணூற்றிஎட்டு +99 தொண்ணூற்றிஒன்பது \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt index 81fa9b10a..e4fe2019e 100644 --- a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt +++ b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt @@ -145,4 +145,4 @@ ௦௧~சுழியம் ஒன்று ௦௭௩~சுழியம் ஏழு மூன்று ௦௦௦௧~சுழியம் சுழியம் சுழியம் ஒன்று -௦௦௦~சுழியம் சுழியம் சுழியம் +௦௦௦~சுழியம் சுழியம் சுழியம் \ No newline at end of file From 60b9d586d0e581f3235417665155531436ef8b9f Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 8 Jul 2026 11:51:25 +0530 Subject: [PATCH 15/29] Added Cardinal file Signed-off-by: surendran-246 --- .../test_cases_cardinal.txt | 190 +++++++++--------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt index e4fe2019e..143acc686 100644 --- a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt +++ b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt @@ -4,7 +4,7 @@ ௫ சார்ஜர்கள்~ஐந்து சார்ஜர்கள் ௪ ஓவரில் ௧௭ ரன்கள்~நான்கு ஓவரில் பதினேழு ரன்கள் ௫ சாக்லெட்டுகள் ௯ டாஃபிகள்~ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள் -௧௦௦௯௯~பத்துஆயிரத்து தொண்ணூற்று ஒன்பது +௧௦௦௯௯~பத்துஆயிரத்து தொண்ணூற்றிஒன்பது ௧௦௦௦௦௧~ஒரு லட்சத்து ஒன்று ௪ சிக்ஸர்கள் ௧௪ நான்குகள்~நான்கு சிக்ஸர்கள் பதினான்கு நான்குகள் ௬ ரன்கள் எடுத்தார்~ஆறு ரன்கள் எடுத்தார் @@ -16,7 +16,7 @@ ௫ கோல்கள் அடி~ஐந்து கோல்கள் அடி ௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள்~மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் ௫ தோல்வி ௧ டிரா ௧௭ வெற்றி~ஐந்து தோல்வி ஒன்று டிரா பதினேழு வெற்றி -௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு பாடம் ௧௦ ஸ்லோகம் ௨~பாடம் பத்து ஸ்லோகம் இரண்டு ௧௦௧~நூற்று ஒன்று ௧௦௨~நூற்று இரண்டு @@ -38,108 +38,108 @@ ௮௧௮~எட்டுநூற்று பதினெட்டு ௮௧௯~எட்டுநூற்று பத்தொன்பது ௮௨௦~எட்டுநூற்று இருபது -௮௨௧~எட்டுநூற்று இருபத்து ஒன்று -௮௨௨~எட்டுநூற்று இருபத்து இரண்டு -௮௨௩~எட்டுநூற்று இருபத்து மூன்று -௮௨௪~எட்டுநூற்று இருபத்து நான்கு -௮௨௫~எட்டுநூற்று இருபத்து ஐந்து -௮௨௬~எட்டுநூற்று இருபத்து ஆறு -௮௨௭~எட்டுநூற்று இருபத்து ஏழு -௮௨௮~எட்டுநூற்று இருபத்து எட்டு -௮௨௯~எட்டுநூற்று இருபத்து ஒன்பது +௮௨௧~எட்டுநூற்று இருபத்தொன்று +௮௨௨~எட்டுநூற்று இருபத்திரண்டு +௮௨௩~எட்டுநூற்று இருபத்திமூன்று +௮௨௪~எட்டுநூற்று இருபத்திநான்கு +௮௨௫~எட்டுநூற்று இருபத்திஐந்து +௮௨௬~எட்டுநூற்று இருபத்திஆறு +௮௨௭~எட்டுநூற்று இருபத்திஏழு +௮௨௮~எட்டுநூற்று இருபத்திஎட்டு +௮௨௯~எட்டுநூற்று இருபத்திஒன்பது ௮௩௦~எட்டுநூற்று முப்பது -௮௩௧~எட்டுநூற்று முப்பத்து ஒன்று -௮௩௨~எட்டுநூற்று முப்பத்து இரண்டு -௮௩௩~எட்டுநூற்று முப்பத்து மூன்று -௮௩௪~எட்டுநூற்று முப்பத்து நான்கு -௮௩௫~எட்டுநூற்று முப்பத்து ஐந்து -௮௩௬~எட்டுநூற்று முப்பத்து ஆறு -௭௩௭~எழுநூற்று முப்பத்து ஏழு -௭௩௮~எழுநூற்று முப்பத்து எட்டு -௭௩௯~எழுநூற்று முப்பத்து ஒன்பது +௮௩௧~எட்டுநூற்று முப்பத்தொன்று +௮௩௨~எட்டுநூற்று முப்பத்திரண்டு +௮௩௩~எட்டுநூற்று முப்பத்திமூன்று +௮௩௪~எட்டுநூற்று முப்பத்திநான்கு +௮௩௫~எட்டுநூற்று முப்பத்திஐந்து +௮௩௬~எட்டுநூற்று முப்பத்திஆறு +௭௩௭~எழுநூற்று முப்பத்திஏழு +௭௩௮~எழுநூற்று முப்பத்திஎட்டு +௭௩௯~எழுநூற்று முப்பத்திஒன்பது ௭௪௦~எழுநூற்று நாற்பது -௭௪௧~எழுநூற்று நாற்பத்து ஒன்று -௭௪௨~எழுநூற்று நாற்பத்து இரண்டு -௭௪௩~எழுநூற்று நாற்பத்து மூன்று -௭௪௪~எழுநூற்று நாற்பத்து நான்கு -௭௪௫~எழுநூற்று நாற்பத்து ஐந்து -௪௪௬~நானூற்று நாற்பத்து ஆறு -௪௪௭~நானூற்று நாற்பத்து ஏழு -௪௪௮~நானூற்று நாற்பத்து எட்டு -௪௪௯~நானூற்று நாற்பத்து ஒன்பது +௭௪௧~எழுநூற்று நாற்பத்தொன்று +௭௪௨~எழுநூற்று நாற்பத்திரண்டு +௭௪௩~எழுநூற்று நாற்பத்திமூன்று +௭௪௪~எழுநூற்று நாற்பத்திநான்கு +௭௪௫~எழுநூற்று நாற்பத்திஐந்து +௪௪௬~நானூற்று நாற்பத்திஆறு +௪௪௭~நானூற்று நாற்பத்திஏழு +௪௪௮~நானூற்று நாற்பத்திஎட்டு +௪௪௯~நானூற்று நாற்பத்திஒன்பது ௪௫௦~நானூற்று ஐம்பது -௪௬௧~நானூற்று அறுபத்து ஒன்று -௧௭௫~நூற்று எழுபத்து ஐந்து -௧௮௧~நூற்று எண்பத்து ஒன்று +௪௬௧~நானூற்று அறுபத்தொன்று +௧௭௫~நூற்று எழுபத்திஐந்து +௧௮௧~நூற்று எண்பத்தொன்று ௧௯௦~நூற்று தொண்ணூறு -௧௯௧~நூற்று தொண்ணூற்று ஒன்று -௧௯௯~நூற்று தொண்ணூற்று ஒன்பது +௧௯௧~நூற்று தொண்ணூற்றொன்று +௧௯௯~நூற்று தொண்ணூற்றிஒன்பது ௧௦௦௧~ஆயிரத்து ஒன்று -௧௦௯௯~ஆயிரத்து தொண்ணூற்று ஒன்பது -௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐநூற்று ஐம்பத்து ஒன்று வாழைப்பழங்கள் -௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்து ஐந்துஆயிரத்து ஐநூற்று ஐம்பத்து இரண்டு ஆப்பிள்கள் -௫௩~ஐம்பத்து மூன்று -௫௪~ஐம்பத்து நான்கு -௫௫~ஐம்பத்து ஐந்து -௫௬~ஐம்பத்து ஆறு -௫௭~ஐம்பத்து ஏழு -௫௮~ஐம்பத்து எட்டு -௫௯~ஐம்பத்து ஒன்பது +௧௦௯௯~ஆயிரத்து தொண்ணூற்றிஒன்பது +௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐநூற்று ஐம்பத்தொன்று வாழைப்பழங்கள் +௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்திஐந்துஆயிரத்து ஐநூற்று ஐம்பத்திரண்டு ஆப்பிள்கள் +௫௩~ஐம்பத்திமூன்று +௫௪~ஐம்பத்திநான்கு +௫௫~ஐம்பத்திஐந்து +௫௬~ஐம்பத்திஆறு +௫௭~ஐம்பத்திஏழு +௫௮~ஐம்பத்திஎட்டு +௫௯~ஐம்பத்திஒன்பது ௬௦~அறுபது -௬௧~அறுபத்து ஒன்று -௬௨~அறுபத்து இரண்டு -௬௩~அறுபத்து மூன்று -௬௪~அறுபத்து நான்கு -௬௫~அறுபத்து ஐந்து -௬௬~அறுபத்து ஆறு -௬௭~அறுபத்து ஏழு -௬௮~அறுபத்து எட்டு -௬௯~அறுபத்து ஒன்பது +௬௧~அறுபத்தொன்று +௬௨~அறுபத்திரண்டு +௬௩~அறுபத்திமூன்று +௬௪~அறுபத்திநான்கு +௬௫~அறுபத்திஐந்து +௬௬~அறுபத்திஆறு +௬௭~அறுபத்திஏழு +௬௮~அறுபத்திஎட்டு +௬௯~அறுபத்திஒன்பது ௭௦~எழுபது -௭௧~எழுபத்து ஒன்று -௭௨~எழுபத்து இரண்டு -௭௩~எழுபத்து மூன்று -௭௪~எழுபத்து நான்கு -௭௫~எழுபத்து ஐந்து -௭௬~எழுபத்து ஆறு -௭௭~எழுபத்து ஏழு -௭௮~எழுபத்து எட்டு -௭௯~எழுபத்து ஒன்பது +௭௧~எழுபத்தொன்று +௭௨~எழுபத்திரண்டு +௭௩~எழுபத்திமூன்று +௭௪~எழுபத்திநான்கு +௭௫~எழுபத்திஐந்து +௭௬~எழுபத்திஆறு +௭௭~எழுபத்திஏழு +௭௮~எழுபத்திஎட்டு +௭௯~எழுபத்திஒன்பது ௮௦~எண்பது -௮௧~எண்பத்து ஒன்று -௮௨~எண்பத்து இரண்டு -௮௩~எண்பத்து மூன்று -௮௪~எண்பத்து நான்கு -௮௫~எண்பத்து ஐந்து -௮௬~எண்பத்து ஆறு -௮௭~எண்பத்து ஏழு -௮௮~எண்பத்து எட்டு -௮௯~எண்பத்து ஒன்பது +௮௧~எண்பத்தொன்று +௮௨~எண்பத்திரண்டு +௮௩~எண்பத்திமூன்று +௮௪~எண்பத்திநான்கு +௮௫~எண்பத்திஐந்து +௮௬~எண்பத்திஆறு +௮௭~எண்பத்திஏழு +௮௮~எண்பத்திஎட்டு +௮௯~எண்பத்திஒன்பது ௯௦~தொண்ணூறு -௯௧~தொண்ணூற்று ஒன்று -௯௨~தொண்ணூற்று இரண்டு -௯௩~தொண்ணூற்று மூன்று -௯௪~தொண்ணூற்று நான்கு -௯௫~தொண்ணூற்று ஐந்து -௯௬~தொண்ணூற்று ஆறு -௯௭~தொண்ணூற்று ஏழு -௯௮~தொண்ணூற்று எட்டு -௯௯~தொண்ணூற்று ஒன்பது -௧௩௨௩~ஆயிரத்து முந்நூற்று இருபத்து மூன்று -௧௩௪௫~ஆயிரத்து முந்நூற்று நாற்பத்து ஐந்து -௧௩௪௫௬~பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு -௧௨௩௪௬~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்து ஆறு -௧௨௩௪௫௬~ஒரு லட்சத்து இருபத்து மூன்றுஆயிரத்து நானூற்று ஐம்பத்து ஆறு -௮௭௨௯௮௭~எட்டு லட்சத்து எழுபத்து இரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்து ஏழு -௯௮௭௬௦௯~ஒன்பது லட்சத்து எண்பத்து ஏழுஆயிரத்து அறுநூற்று ஒன்பது -௯௮௭௬௭௮௯~தொண்ணூற்று எட்டு லட்சத்து எழுபத்து ஆறுஆயிரத்து எழுநூற்று எண்பத்து ஒன்பது -௨௩௪௫௫௬௭~இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு -௧௨௩௪௫௫௬௭~ஒரு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு -௧௨௧௨௧௨௧௨~ஒரு கோடியே இருபத்து ஒன்று லட்சத்து இருபத்து ஒன்றுஆயிரத்து இருநூற்று பன்னிரண்டு -௧௧௨௨௩௪௫௫௬௭~நூற்று பன்னிரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு -௧௦௨௨௩௪௫௫௬௭~நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு -௧௧௦௨௨௩௪௫௫௬௭~ஆயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு -௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்து மூன்று லட்சத்து நாற்பத்து ஐந்துஆயிரத்து ஐநூற்று அறுபத்து ஏழு +௯௧~தொண்ணூற்றொன்று +௯௨~தொண்ணூற்றிரண்டு +௯௩~தொண்ணூற்றிமூன்று +௯௪~தொண்ணூற்றிநான்கு +௯௫~தொண்ணூற்றிஐந்து +௯௬~தொண்ணூற்றிஆறு +௯௭~தொண்ணூற்றிஏழு +௯௮~தொண்ணூற்றிஎட்டு +௯௯~தொண்ணூற்றிஒன்பது +௧௩௨௩~ஆயிரத்து முந்நூற்று இருபத்திமூன்று +௧௩௪௫~ஆயிரத்து முந்நூற்று நாற்பத்திஐந்து +௧௩௪௫௬~பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்திஆறு +௧௨௩௪௬~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்திஆறு +௧௨௩௪௫௬~ஒரு லட்சத்து இருபத்திமூன்றுஆயிரத்து நானூற்று ஐம்பத்திஆறு +௮௭௨௯௮௭~எட்டு லட்சத்து எழுபத்திரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்திஏழு +௯௮௭௬௦௯~ஒன்பது லட்சத்து எண்பத்திஏழுஆயிரத்து அறுநூற்று ஒன்பது +௯௮௭௬௭௮௯~தொண்ணூற்றிஎட்டு லட்சத்து எழுபத்திஆறுஆயிரத்து எழுநூற்று எண்பத்திஒன்பது +௨௩௪௫௫௬௭~இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +௧௨௩௪௫௫௬௭~ஒரு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +௧௨௧௨௧௨௧௨~ஒரு கோடியே இருபத்தொன்று லட்சத்து இருபத்தொன்றுஆயிரத்து இருநூற்று பன்னிரண்டு +௧௧௨௨௩௪௫௫௬௭~நூற்று பன்னிரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +௧௦௨௨௩௪௫௫௬௭~நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +௧௧௦௨௨௩௪௫௫௬௭~ஆயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு ௨ புள்ளிகள் ௧௨ கோல்கள்~இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் ௦௫~சுழியம் ஐந்து ௦௧~சுழியம் ஒன்று From fe805eb587bac6a07f7af320c89235ba1e73bedd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 06:24:23 +0000 Subject: [PATCH 16/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../text_normalization/ta/taggers/cardinal.py | 775 +++++++++--------- 1 file changed, 404 insertions(+), 371 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index bc4eb1806..78080c548 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -1,5 +1,3 @@ - - # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,376 +14,411 @@ import pynini from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import ( - NEMO_ALL_DIGIT, - NEMO_ALL_ZERO, - GraphFst, - insert_space, + NEMO_ALL_DIGIT, + NEMO_ALL_ZERO, + GraphFst, + insert_space, ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path + class CardinalFst(GraphFst): - """ - Finite state transducer for classifying cardinals, e.g. - -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } - The highest unit used is கோடி. - """ - def __init__(self, deterministic: bool = True, lm: bool = False): - super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) - zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) - hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) - teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) - teens_ties = pynini.union(teens_ties_hi, teens_ties_en) - teens_and_ties = pynutil.add_weight(teens_ties, -0.1) - self.digit = digit - self.zero = zero - self.hundred_ta = hundred_ta - self.teens_and_ties = teens_and_ties - - single_digit = digit | zero - single_digit_graph = digit | zero - self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) - zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - - def create_graph_suffix(digit_graph, suffix, zeros_counts): - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix - return digit_graph + (z ** zeros_counts) + suffix - - def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): - ins = pynutil.insert(" ") - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix + ins + sub_graph - return digit_graph + suffix + (z ** zeros_counts) + ins + sub_graph - - # HUNDREDS GRAPH (100-999) - - # exact 100 → நூறு - exact_hundred = pynutil.add_weight(pynini.union( - pynini.cross("100", "நூறு"), - pynini.cross("௧௦௦", "நூறு"), - ).optimize(), -1.0) - - # hundred prefixes: 200-900 - fused_hundred_prefix = pynini.union( - pynini.cross("2", "இருநூற்று"), - pynini.cross("3", "முந்நூற்று"), - pynini.cross("4", "நானூற்று"), - pynini.cross("5", "ஐநூற்று"), - pynini.cross("6", "அறுநூற்று"), - pynini.cross("7", "எழுநூற்று"), - pynini.cross("8", "எட்டுநூற்று"), - pynini.cross("9", "ஒன்பதுநூற்று"), - pynini.cross("௨", "இருநூற்று"), - pynini.cross("௩", "முந்நூற்று"), - pynini.cross("௪", "நானூற்று"), - pynini.cross("௫", "ஐநூற்று"), - pynini.cross("௬", "அறுநூற்று"), - pynini.cross("௭", "எழுநூற்று"), - pynini.cross("௮", "எட்டுநூற்று"), - pynini.cross("௯", "ஒன்பதுநூற்று"), - ).optimize() - - graph_hundreds = hundred_ta - # 101-109 - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + zero_delete + pynutil.insert(" ") + single_digit - ) - # 110-199 - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + pynutil.insert(" ") + teens_ties - ) - # 201-209 ... 901-909 - graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit - # 210-999 - graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties - graph_hundreds = graph_hundreds.optimize() - self.graph_hundreds = graph_hundreds - - # THOUSANDS GRAPH (1000-9999) - # 1000-1999 → ஆயிரம்/ஆயிரத்து - one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") - one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") - # 2000-9000 - fused_thousands_exact = pynini.union( - pynini.cross("2", "இரண்டாயிரம்"), - pynini.cross("3", "மூவாயிரம்"), - pynini.cross("4", "நான்காயிரம்"), - pynini.cross("5", "ஐந்தாயிரம்"), - pynini.cross("6", "ஆறாயிரம்"), - pynini.cross("7", "ஏழாயிரம்"), - pynini.cross("8", "எட்டாயிரம்"), - pynini.cross("9", "ஒன்பதாயிரம்"), - pynini.cross("௨", "இரண்டாயிரம்"), - pynini.cross("௩", "மூவாயிரம்"), - pynini.cross("௪", "நான்காயிரம்"), - pynini.cross("௫", "ஐந்தாயிரம்"), - pynini.cross("௬", "ஆறாயிரம்"), - pynini.cross("௭", "ஏழாயிரம்"), - pynini.cross("௮", "எட்டாயிரம்"), - pynini.cross("௯", "ஒன்பதாயிரம்"), - ).optimize() - - fused_thousands_prefix = pynini.union( - pynini.cross("2", "இரண்டாயிரத்து"), - pynini.cross("3", "மூவாயிரத்து"), - pynini.cross("4", "நான்காயிரத்து"), - pynini.cross("5", "ஐந்தாயிரத்து"), - pynini.cross("6", "ஆறாயிரத்து"), - pynini.cross("7", "ஏழாயிரத்து"), - pynini.cross("8", "எட்டாயிரத்து"), - pynini.cross("9", "ஒன்பதாயிரத்து"), - pynini.cross("௨", "இரண்டாயிரத்து"), - pynini.cross("௩", "மூவாயிரத்து"), - pynini.cross("௪", "நான்காயிரத்து"), - pynini.cross("௫", "ஐந்தாயிரத்து"), - pynini.cross("௬", "ஆறாயிரத்து"), - pynini.cross("௭", "ஏழாயிரத்து"), - pynini.cross("௮", "எட்டாயிரத்து"), - pynini.cross("௯", "ஒன்பதாயிரத்து"), - ).optimize() - - graph_thousands = one_k_exact + (zero_delete ** 3) - graph_thousands |= one_k_tail + (zero_delete ** 2) + pynutil.insert(" ") + single_digit - graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties - graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds - graph_thousands |= fused_thousands_exact + (zero_delete ** 3) - graph_thousands |= fused_thousands_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit - graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties - graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds - graph_thousands = graph_thousands.optimize() - self.graph_thousands = graph_thousands - - # TEN-THOUSANDS GRAPH (10000-99999) - # 10000-19999 - fused_ten_k_exact = pynini.union( - pynini.cross("௧௩", "பதிமூன்றுஆயிரம்"), - pynini.cross("௧௨", "பன்னிரண்டுஆயிரம்"), - pynini.cross("௧௧", "பதினொன்றுஆயிரம்"), - pynini.cross("௪௫", "நாற்பத்தைந்தாயிரம்"), - pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரம்"), - ).optimize() - - fused_ten_k_prefix = pynini.union( - pynini.cross("௧௩", "பதிமூன்றுஆயிரத்து"), - pynini.cross("௧௨", "பன்னிரண்டுஆயிரத்து"), - pynini.cross("௧௧", "பதினொன்றுஆயிரத்து"), - pynini.cross("௪௫", "நாற்பத்தைந்தாயிரத்து"), - pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரத்து"), - ).optimize() - - suffix_ten_k_exact = pynutil.insert("ஆயிரம்") - suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") - - graph_ten_thousands = fused_ten_k_exact + (zero_delete ** 3) - graph_ten_thousands |= fused_ten_k_prefix + (zero_delete ** 2) + pynutil.insert(" ") + single_digit - graph_ten_thousands |= fused_ten_k_prefix + zero_delete + pynutil.insert(" ") + teens_ties - graph_ten_thousands |= fused_ten_k_prefix + pynutil.insert(" ") + graph_hundreds - graph_ten_thousands |= create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) - graph_ten_thousands = graph_ten_thousands.optimize() - self.graph_ten_thousands = graph_ten_thousands - - # LAKHS GRAPH (100000-9999999) - # 1 lakh → ஒரு லட்சம் - suffix_lakhs = pynutil.insert(" லட்சம்") - suffix_lakhs_tail = pynutil.insert(" லட்சத்து") - - digit_one_as_oru = pynini.union( - pynini.cross("1", "ஒரு"), - pynini.cross("௧", "ஒரு"), - pynini.cross("2", "இரண்டு"), - pynini.cross("3", "மூன்று"), - pynini.cross("4", "நான்கு"), - pynini.cross("5", "ஐந்து"), - pynini.cross("6", "ஆறு"), - pynini.cross("7", "ஏழு"), - pynini.cross("8", "எட்டு"), - pynini.cross("9", "ஒன்பது"), - pynini.cross("௨", "இரண்டு"), - pynini.cross("௩", "மூன்று"), - pynini.cross("௪", "நான்கு"), - pynini.cross("௫", "ஐந்து"), - pynini.cross("௬", "ஆறு"), - pynini.cross("௭", "ஏழு"), - pynini.cross("௮", "எட்டு"), - pynini.cross("௯", "ஒன்பது"), - ).optimize() - - graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_lakhs = graph_lakhs.optimize() - self.graph_lakhs = graph_lakhs - - graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_ten_lakhs = graph_ten_lakhs.optimize() - self.graph_ten_lakhs = graph_ten_lakhs - - # CRORES GRAPH — கோடி - # 1 crore → ஒரு கோடி / ஒரு கோடியே - suffix_crores = pynutil.insert(" கோடி") - suffix_crores_tail = pynutil.insert(" கோடியே") - - graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores = graph_crores.optimize() - - graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_crores = graph_ten_crores.optimize() - - # hundreds of crores: 100-999 கோடி - graph_hundreds_of_crores = create_graph_suffix(exact_hundred, suffix_crores, 7) - graph_hundreds_of_crores |= create_graph_suffix(graph_hundreds, suffix_crores, 7) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 6, single_digit) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 5, teens_ties) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 4, graph_hundreds) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 3, graph_thousands) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 2, graph_ten_thousands) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 1, graph_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 0, graph_ten_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 6, single_digit) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 5, teens_ties) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 4, graph_hundreds) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 3, graph_thousands) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 2, graph_ten_thousands) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 1, graph_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 0, graph_ten_lakhs) - graph_hundreds_of_crores = graph_hundreds_of_crores.optimize() - - # thousands of crores: 1000-9999 கோடி - graph_thousands_of_crores = create_graph_suffix(graph_thousands, suffix_crores, 7) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 6, single_digit) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 5, teens_ties) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 4, graph_hundreds) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 3, graph_thousands) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 2, graph_ten_thousands) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 1, graph_lakhs) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 0, graph_ten_lakhs) - graph_thousands_of_crores = graph_thousands_of_crores.optimize() - - # ten-thousands of crores - graph_ten_thousands_of_crores = create_graph_suffix(graph_ten_thousands, suffix_crores, 7) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 6, single_digit) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 5, teens_ties) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 4, graph_hundreds) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 3, graph_thousands) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 1, graph_lakhs) - graph_ten_thousands_of_crores |= create_larger_number_graph(graph_ten_thousands, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_thousands_of_crores = graph_ten_thousands_of_crores.optimize() - - # lakhs of crores - graph_lakhs_of_crores = create_graph_suffix(graph_lakhs, suffix_crores, 7) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 6, single_digit) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 5, teens_ties) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 4, graph_hundreds) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 3, graph_thousands) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 2, graph_ten_thousands) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 1, graph_lakhs) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) - graph_lakhs_of_crores = graph_lakhs_of_crores.optimize() - - graph_ten_lakhs_of_crores = create_graph_suffix(graph_ten_lakhs, suffix_crores, 7) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 6, single_digit) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 5, teens_ties) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 4, graph_hundreds) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 3, graph_thousands) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 1, graph_lakhs) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_lakhs_of_crores = graph_ten_lakhs_of_crores.optimize() - - # crores of crores - graph_crores_of_crores = create_graph_suffix(graph_crores, suffix_crores, 7) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 6, single_digit) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 5, teens_ties) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 4, graph_hundreds) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 3, graph_thousands) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 1, graph_lakhs) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores_of_crores = graph_crores_of_crores.optimize() - - graph_ten_crores_of_crores = create_graph_suffix(graph_ten_crores, suffix_crores, 7) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 6, single_digit) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 5, teens_ties) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 4, graph_hundreds) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 3, graph_thousands) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_crores_of_crores = graph_ten_crores_of_crores.optimize() - - # LEADING ZERO and FINAL GRAPH - graph_leading_zero = zero + insert_space + single_digit - graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) - - graph_without_leading_zeros = ( - digit - | zero - | teens_and_ties - | exact_hundred - | graph_hundreds - | graph_thousands - | graph_ten_thousands - | graph_lakhs - | graph_ten_lakhs - | graph_crores - | graph_ten_crores - | graph_hundreds_of_crores - | graph_thousands_of_crores - | graph_ten_thousands_of_crores - | graph_lakhs_of_crores - | graph_ten_lakhs_of_crores - | graph_crores_of_crores - | graph_ten_crores_of_crores - ) - self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() - - cardinal_with_leading_zeros = pynini.compose( - NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph - ) - cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) - - final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros - optional_minus_graph = pynini.closure( - pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1 - ) - self.final_graph = final_graph.optimize() - final_graph = ( - optional_minus_graph - + pynutil.insert("integer: \"") - + self.final_graph - + pynutil.insert("\"") - ) - final_graph = self.add_tokens(final_graph) - self.fst = final_graph + """ + Finite state transducer for classifying cardinals, e.g. + -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } + The highest unit used is கோடி. + """ + + def __init__(self, deterministic: bool = True, lm: bool = False): + super().__init__(name="cardinal", kind="classify", deterministic=deterministic) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) + teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) + teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) + teens_ties = pynini.union(teens_ties_hi, teens_ties_en) + teens_and_ties = pynutil.add_weight(teens_ties, -0.1) + self.digit = digit + self.zero = zero + self.hundred_ta = hundred_ta + self.teens_and_ties = teens_and_ties + + single_digit = digit | zero + single_digit_graph = digit | zero + self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) + zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + + def create_graph_suffix(digit_graph, suffix, zeros_counts): + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + return digit_graph + (z**zeros_counts) + suffix + + def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): + ins = pynutil.insert(" ") + z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + if zeros_counts == 0: + return digit_graph + suffix + ins + sub_graph + return digit_graph + suffix + (z**zeros_counts) + ins + sub_graph + + # HUNDREDS GRAPH (100-999) + + # exact 100 → நூறு + exact_hundred = pynutil.add_weight( + pynini.union( + pynini.cross("100", "நூறு"), + pynini.cross("௧௦௦", "நூறு"), + ).optimize(), + -1.0, + ) + + # hundred prefixes: 200-900 + fused_hundred_prefix = pynini.union( + pynini.cross("2", "இருநூற்று"), + pynini.cross("3", "முந்நூற்று"), + pynini.cross("4", "நானூற்று"), + pynini.cross("5", "ஐநூற்று"), + pynini.cross("6", "அறுநூற்று"), + pynini.cross("7", "எழுநூற்று"), + pynini.cross("8", "எட்டுநூற்று"), + pynini.cross("9", "ஒன்பதுநூற்று"), + pynini.cross("௨", "இருநூற்று"), + pynini.cross("௩", "முந்நூற்று"), + pynini.cross("௪", "நானூற்று"), + pynini.cross("௫", "ஐநூற்று"), + pynini.cross("௬", "அறுநூற்று"), + pynini.cross("௭", "எழுநூற்று"), + pynini.cross("௮", "எட்டுநூற்று"), + pynini.cross("௯", "ஒன்பதுநூற்று"), + ).optimize() + + graph_hundreds = hundred_ta + # 101-109 + graph_hundreds |= ( + (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + + zero_delete + + pynutil.insert(" ") + + single_digit + ) + # 110-199 + graph_hundreds |= (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + pynutil.insert(" ") + teens_ties + # 201-209 ... 901-909 + graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit + # 210-999 + graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties + graph_hundreds = graph_hundreds.optimize() + self.graph_hundreds = graph_hundreds + + # THOUSANDS GRAPH (1000-9999) + # 1000-1999 → ஆயிரம்/ஆயிரத்து + one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") + one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") + # 2000-9000 + fused_thousands_exact = pynini.union( + pynini.cross("2", "இரண்டாயிரம்"), + pynini.cross("3", "மூவாயிரம்"), + pynini.cross("4", "நான்காயிரம்"), + pynini.cross("5", "ஐந்தாயிரம்"), + pynini.cross("6", "ஆறாயிரம்"), + pynini.cross("7", "ஏழாயிரம்"), + pynini.cross("8", "எட்டாயிரம்"), + pynini.cross("9", "ஒன்பதாயிரம்"), + pynini.cross("௨", "இரண்டாயிரம்"), + pynini.cross("௩", "மூவாயிரம்"), + pynini.cross("௪", "நான்காயிரம்"), + pynini.cross("௫", "ஐந்தாயிரம்"), + pynini.cross("௬", "ஆறாயிரம்"), + pynini.cross("௭", "ஏழாயிரம்"), + pynini.cross("௮", "எட்டாயிரம்"), + pynini.cross("௯", "ஒன்பதாயிரம்"), + ).optimize() + + fused_thousands_prefix = pynini.union( + pynini.cross("2", "இரண்டாயிரத்து"), + pynini.cross("3", "மூவாயிரத்து"), + pynini.cross("4", "நான்காயிரத்து"), + pynini.cross("5", "ஐந்தாயிரத்து"), + pynini.cross("6", "ஆறாயிரத்து"), + pynini.cross("7", "ஏழாயிரத்து"), + pynini.cross("8", "எட்டாயிரத்து"), + pynini.cross("9", "ஒன்பதாயிரத்து"), + pynini.cross("௨", "இரண்டாயிரத்து"), + pynini.cross("௩", "மூவாயிரத்து"), + pynini.cross("௪", "நான்காயிரத்து"), + pynini.cross("௫", "ஐந்தாயிரத்து"), + pynini.cross("௬", "ஆறாயிரத்து"), + pynini.cross("௭", "ஏழாயிரத்து"), + pynini.cross("௮", "எட்டாயிரத்து"), + pynini.cross("௯", "ஒன்பதாயிரத்து"), + ).optimize() + + graph_thousands = one_k_exact + (zero_delete**3) + graph_thousands |= one_k_tail + (zero_delete**2) + pynutil.insert(" ") + single_digit + graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties + graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds + graph_thousands |= fused_thousands_exact + (zero_delete**3) + graph_thousands |= fused_thousands_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit + graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties + graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds + graph_thousands = graph_thousands.optimize() + self.graph_thousands = graph_thousands + + # TEN-THOUSANDS GRAPH (10000-99999) + # 10000-19999 + fused_ten_k_exact = pynini.union( + pynini.cross("௧௩", "பதிமூன்றுஆயிரம்"), + pynini.cross("௧௨", "பன்னிரண்டுஆயிரம்"), + pynini.cross("௧௧", "பதினொன்றுஆயிரம்"), + pynini.cross("௪௫", "நாற்பத்தைந்தாயிரம்"), + pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரம்"), + ).optimize() + + fused_ten_k_prefix = pynini.union( + pynini.cross("௧௩", "பதிமூன்றுஆயிரத்து"), + pynini.cross("௧௨", "பன்னிரண்டுஆயிரத்து"), + pynini.cross("௧௧", "பதினொன்றுஆயிரத்து"), + pynini.cross("௪௫", "நாற்பத்தைந்தாயிரத்து"), + pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரத்து"), + ).optimize() + + suffix_ten_k_exact = pynutil.insert("ஆயிரம்") + suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") + + graph_ten_thousands = fused_ten_k_exact + (zero_delete**3) + graph_ten_thousands |= fused_ten_k_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit + graph_ten_thousands |= fused_ten_k_prefix + zero_delete + pynutil.insert(" ") + teens_ties + graph_ten_thousands |= fused_ten_k_prefix + pynutil.insert(" ") + graph_hundreds + graph_ten_thousands |= create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) + graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) + graph_ten_thousands = graph_ten_thousands.optimize() + self.graph_ten_thousands = graph_ten_thousands + + # LAKHS GRAPH (100000-9999999) + # 1 lakh → ஒரு லட்சம் + suffix_lakhs = pynutil.insert(" லட்சம்") + suffix_lakhs_tail = pynutil.insert(" லட்சத்து") + + digit_one_as_oru = pynini.union( + pynini.cross("1", "ஒரு"), + pynini.cross("௧", "ஒரு"), + pynini.cross("2", "இரண்டு"), + pynini.cross("3", "மூன்று"), + pynini.cross("4", "நான்கு"), + pynini.cross("5", "ஐந்து"), + pynini.cross("6", "ஆறு"), + pynini.cross("7", "ஏழு"), + pynini.cross("8", "எட்டு"), + pynini.cross("9", "ஒன்பது"), + pynini.cross("௨", "இரண்டு"), + pynini.cross("௩", "மூன்று"), + pynini.cross("௪", "நான்கு"), + pynini.cross("௫", "ஐந்து"), + pynini.cross("௬", "ஆறு"), + pynini.cross("௭", "ஏழு"), + pynini.cross("௮", "எட்டு"), + pynini.cross("௯", "ஒன்பது"), + ).optimize() + + graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) + graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_lakhs = graph_lakhs.optimize() + self.graph_lakhs = graph_lakhs + + graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) + graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) + graph_ten_lakhs = graph_ten_lakhs.optimize() + self.graph_ten_lakhs = graph_ten_lakhs + + # CRORES GRAPH — கோடி + # 1 crore → ஒரு கோடி / ஒரு கோடியே + suffix_crores = pynutil.insert(" கோடி") + suffix_crores_tail = pynutil.insert(" கோடியே") + + graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) + graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores = graph_crores.optimize() + + graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) + graph_ten_crores = graph_ten_crores.optimize() + + # hundreds of crores: 100-999 கோடி + graph_hundreds_of_crores = create_graph_suffix(exact_hundred, suffix_crores, 7) + graph_hundreds_of_crores |= create_graph_suffix(graph_hundreds, suffix_crores, 7) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 6, single_digit) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 5, teens_ties) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 4, graph_hundreds) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 3, graph_thousands) + graph_hundreds_of_crores |= create_larger_number_graph( + exact_hundred, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 1, graph_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 0, graph_ten_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 6, single_digit) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 5, teens_ties) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 4, graph_hundreds) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 3, graph_thousands) + graph_hundreds_of_crores |= create_larger_number_graph( + graph_hundreds, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 1, graph_lakhs) + graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 0, graph_ten_lakhs) + graph_hundreds_of_crores = graph_hundreds_of_crores.optimize() + + # thousands of crores: 1000-9999 கோடி + graph_thousands_of_crores = create_graph_suffix(graph_thousands, suffix_crores, 7) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 6, single_digit) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 5, teens_ties) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 4, graph_hundreds) + graph_thousands_of_crores |= create_larger_number_graph( + graph_thousands, suffix_crores_tail, 3, graph_thousands + ) + graph_thousands_of_crores |= create_larger_number_graph( + graph_thousands, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 1, graph_lakhs) + graph_thousands_of_crores |= create_larger_number_graph( + graph_thousands, suffix_crores_tail, 0, graph_ten_lakhs + ) + graph_thousands_of_crores = graph_thousands_of_crores.optimize() + + # ten-thousands of crores + graph_ten_thousands_of_crores = create_graph_suffix(graph_ten_thousands, suffix_crores, 7) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 6, single_digit + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 5, teens_ties + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 4, graph_hundreds + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 3, graph_thousands + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 1, graph_lakhs + ) + graph_ten_thousands_of_crores |= create_larger_number_graph( + graph_ten_thousands, suffix_crores_tail, 0, graph_ten_lakhs + ) + graph_ten_thousands_of_crores = graph_ten_thousands_of_crores.optimize() + + # lakhs of crores + graph_lakhs_of_crores = create_graph_suffix(graph_lakhs, suffix_crores, 7) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 6, single_digit) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 5, teens_ties) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 4, graph_hundreds) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 3, graph_thousands) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 2, graph_ten_thousands) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 1, graph_lakhs) + graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) + graph_lakhs_of_crores = graph_lakhs_of_crores.optimize() + + graph_ten_lakhs_of_crores = create_graph_suffix(graph_ten_lakhs, suffix_crores, 7) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 6, single_digit) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 5, teens_ties) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 4, graph_hundreds) + graph_ten_lakhs_of_crores |= create_larger_number_graph( + graph_ten_lakhs, suffix_crores_tail, 3, graph_thousands + ) + graph_ten_lakhs_of_crores |= create_larger_number_graph( + graph_ten_lakhs, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 1, graph_lakhs) + graph_ten_lakhs_of_crores |= create_larger_number_graph( + graph_ten_lakhs, suffix_crores_tail, 0, graph_ten_lakhs + ) + graph_ten_lakhs_of_crores = graph_ten_lakhs_of_crores.optimize() + + # crores of crores + graph_crores_of_crores = create_graph_suffix(graph_crores, suffix_crores, 7) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 6, single_digit) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 5, teens_ties) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 4, graph_hundreds) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 3, graph_thousands) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 2, graph_ten_thousands) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 1, graph_lakhs) + graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 0, graph_ten_lakhs) + graph_crores_of_crores = graph_crores_of_crores.optimize() + + graph_ten_crores_of_crores = create_graph_suffix(graph_ten_crores, suffix_crores, 7) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 6, single_digit) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 5, teens_ties) + graph_ten_crores_of_crores |= create_larger_number_graph( + graph_ten_crores, suffix_crores_tail, 4, graph_hundreds + ) + graph_ten_crores_of_crores |= create_larger_number_graph( + graph_ten_crores, suffix_crores_tail, 3, graph_thousands + ) + graph_ten_crores_of_crores |= create_larger_number_graph( + graph_ten_crores, suffix_crores_tail, 2, graph_ten_thousands + ) + graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 1, graph_lakhs) + graph_ten_crores_of_crores |= create_larger_number_graph( + graph_ten_crores, suffix_crores_tail, 0, graph_ten_lakhs + ) + graph_ten_crores_of_crores = graph_ten_crores_of_crores.optimize() + + # LEADING ZERO and FINAL GRAPH + graph_leading_zero = zero + insert_space + single_digit + graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) + + graph_without_leading_zeros = ( + digit + | zero + | teens_and_ties + | exact_hundred + | graph_hundreds + | graph_thousands + | graph_ten_thousands + | graph_lakhs + | graph_ten_lakhs + | graph_crores + | graph_ten_crores + | graph_hundreds_of_crores + | graph_thousands_of_crores + | graph_ten_thousands_of_crores + | graph_lakhs_of_crores + | graph_ten_lakhs_of_crores + | graph_crores_of_crores + | graph_ten_crores_of_crores + ) + self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() + + cardinal_with_leading_zeros = pynini.compose( + NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph + ) + cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) + + final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros + optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) + self.final_graph = final_graph.optimize() + final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") + final_graph = self.add_tokens(final_graph) + self.fst = final_graph From e2e79964ea595daef34038374917ccd434e3199f Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 8 Jul 2026 11:58:32 +0530 Subject: [PATCH 17/29] Updated Cardinal file Signed-off-by: surendran-246 --- .../text_normalization/ta/data/numbers/thousands.tsv | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv index 31515f0f6..5c6838935 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv @@ -1,8 +1,3 @@ ௧௦௦௦ ஆயிரம் ௧௦௦௦௦௦ லட்சம் ௧௦௦௦௦௦௦௦ கோடி -௧௦௦௦௦௦௦௦௦௦ அரபு -௧௦௦௦௦௦௦௦௦௦௦௦ கரபு -௧௦௦௦௦௦௦௦௦௦௦௦௦௦ நீல் -௧௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦ பத்மம் -௧௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦௦ சங்கம் From 290774472792662080f2d70d08079bdd0b424bc5 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Thu, 23 Jul 2026 18:03:37 +0530 Subject: [PATCH 18/29] Updated TA Cardinal Signed-off-by: surendran-246 --- Jenkinsfile | 25 + .../ta/data/numbers/hundred_ta.tsv | 50 +- .../ta/data/numbers/thousand.tsv | 18 + .../ta/data/numbers/thousands.tsv | 3 - .../text_normalization/ta/graph_utils.py | 86 +--- .../text_normalization/ta/taggers/cardinal.py | 461 ++++-------------- .../ta/taggers/tokenize_and_classify.py | 55 +-- .../text_normalization/ta/utils.py | 49 +- .../ta/verbalizers/cardinal.py | 2 +- .../ta/verbalizers/post_processing.py | 3 +- .../ta/verbalizers/verbalize.py | 12 - .../ta/verbalizers/verbalize_final.py | 2 +- .../text_normalization/ta/verbalizers/word.py | 2 - .../test_cases_cardinal.txt | 167 ++----- .../nemo_text_processing/ta/test_cardinal.py | 16 +- .../ta/test_sparrowhawk_normalization.sh | 41 ++ .../pynini_export.py | 13 +- 17 files changed, 266 insertions(+), 739 deletions(-) create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv delete mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv create mode 100644 tests/nemo_text_processing/ta/test_sparrowhawk_normalization.sh diff --git a/Jenkinsfile b/Jenkinsfile index 23c99d3ad..5eac7f1dc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,6 +29,7 @@ pipeline { JA_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/10-17-24-1' KO_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/04-23-26-0' HI_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/04-23-26-0' + TA_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/07-21-26-0' DEFAULT_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-08-23-0' } stages { @@ -108,6 +109,25 @@ pipeline { } } + stage('L0: Create TA TN Grammars') { + when { + anyOf { + branch 'main' + branch 'staging/**' + branch 'staging_*' + changeRequest target: 'main' + } + } + failFast true + parallel { + stage('L0: Ta TN grammars') { + steps { + sh 'CUDA_VISIBLE_DEVICES="" python nemo_text_processing/text_normalization/normalize.py --lang=ta --text="௧" --cache_dir ${TA_TN_CACHE}' + } + } + + } + } stage('L0: Create DE/ES TN/ITN Grammars') { when { anyOf { @@ -404,6 +424,11 @@ pipeline { sh 'CUDA_VISIBLE_DEVICES="" pytest tests/nemo_text_processing/hi/ -m "not pleasefixme" --cpu --tn_cache_dir ${HI_TN_CACHE}' } } + stage('L1: Run all TA TN tests (restore grammars from cache)') { + steps { + sh 'CUDA_VISIBLE_DEVICES="" pytest tests/nemo_text_processing/ta/ -m "not pleasefixme" --cpu --tn_cache_dir ${TA_TN_CACHE}' + } + } stage('L1: Run all Codeswitched ES/EN TN/ITN tests (restore grammars from cache)') { steps { sh 'CUDA_VISIBLE_DEVICES="" pytest tests/nemo_text_processing/es_en/ -m "not pleasefixme" --cpu --tn_cache_dir ${ES_EN_TN_CACHE}' diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv index 29621c1a9..873a94569 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/hundred_ta.tsv @@ -1,18 +1,36 @@ 100 நூறு -200 இருநூற்று -300 முந்நூற்று -400 நானூற்று -500 ஐந்நூற்று -600 அறுநூற்று -700 எழுநூற்று -800 எட்டுநூற்று -900 ஒன்பதுநூற்று +200 இருநூறு +300 முந்நூறு +400 நானூறு +500 ஐந்நூறு +600 அறுநூறு +700 எழுநூறு +800 எட்டுநூறு +900 ஒன்பதுநூறு ௧௦௦ நூறு -௨௦௦ இருநூற்று -௩௦௦ முந்நூற்று -௪௦௦ நானூற்று -௫௦௦ ஐந்நூற்று -௬௦௦ அறுநூற்று -௭௦௦ எழுநூற்று -௮௦௦ எட்டுநூற்று -௯௦௦ ஒன்பதுநூற்று \ No newline at end of file +௨௦௦ இருநூறு +௩௦௦ முந்நூறு +௪௦௦ நானூறு +௫௦௦ ஐந்நூறு +௬௦௦ அறுநூறு +௭௦௦ எழுநூறு +௮௦௦ எட்டுநூறு +௯௦௦ ஒன்பதுநூறு +1 நூற்று +2 இருநூற்று +3 முந்நூற்று +4 நானூற்று +5 ஐநூற்று +6 அறுநூற்று +7 எழுநூற்று +8 எட்டுநூற்று +9 ஒன்பதுநூற்று +௧ நூற்று +௨ இருநூற்று +௩ முந்நூற்று +௪ நானூற்று +௫ ஐநூற்று +௬ அறுநூற்று +௭ எழுநூற்று +௮ எட்டுநூற்று +௯ ஒன்பதுநூற்று \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv new file mode 100644 index 000000000..001a7719f --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv @@ -0,0 +1,18 @@ +1 ஆயிர +2 இரண்டாயிர +3 மூவாயிர +4 நான்காயிர +5 ஐந்தாயிர +6 ஆறாயிர +7 ஏழாயிர +8 எட்டாயிர +9 ஒன்பதாயிர +௧ ஆயிர +௨ இரண்டாயிர +௩ மூவாயிர +௪ நான்காயிர +௫ ஐந்தாயிர +௬ ஆறாயிர +௭ ஏழாயிர +௮ எட்டாயிர +௯ ஒன்பதாயிர diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv deleted file mode 100644 index 5c6838935..000000000 --- a/nemo_text_processing/text_normalization/ta/data/numbers/thousands.tsv +++ /dev/null @@ -1,3 +0,0 @@ -௧௦௦௦ ஆயிரம் -௧௦௦௦௦௦ லட்சம் -௧௦௦௦௦௦௦௦ கோடி diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index ee097e256..5d7ef5c8b 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -14,7 +14,6 @@ import logging import os -import string from pathlib import Path from typing import Dict @@ -27,104 +26,22 @@ NEMO_DIGIT = byte.DIGIT NEMO_TA_DIGIT = pynini.union("௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯").optimize() -NEMO_TA_NON_ZERO = pynini.union("௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯").optimize() -NEMO_TA_ZERO = "௦" # Combined TAMIL and Arabic digits for graphs that need to accept both NEMO_ALL_DIGIT = pynini.union(NEMO_TA_DIGIT, NEMO_DIGIT).optimize() NEMO_ALL_ZERO = pynini.union("௦", "0").optimize() -NEMO_ALL_NON_ZERO = pynini.union(NEMO_TA_NON_ZERO, "1", "2", "3", "4", "5", "6", "7", "8", "9").optimize() - -TA_ONRARAI = "ஒன்றரை" # 1.5 -TA_IRANDARAI = "இரண்டரை" # 2.5 -TA_ONRUKAAL = "ஒன்றுகால்" # quarter more (1.25) -TA_ARAI = "அரை" # half more (X.5) -TA_MUKKAAL = "முக்கால்" # quarter less (0.75) - -# Tamil decimal representations -TA_POINT_FIVE = ".௫" # .5 -TA_ONE_POINT_FIVE = "௧.௫" # 1.5 -TA_TWO_POINT_FIVE = "௨.௫" # 2.5 -TA_DECIMAL_25 = ".௨௫" # .25 -TA_DECIMAL_75 = ".௭௫" # .75 - -# Arabic/English decimal representations -EN_POINT_FIVE = ".5" -EN_ONE_POINT_FIVE = "1.5" -EN_TWO_POINT_FIVE = "2.5" -EN_DECIMAL_25 = ".25" -EN_DECIMAL_75 = ".75" - -# Combined Tamil and English decimal patterns -POINT_FIVE = pynini.union(TA_POINT_FIVE, EN_POINT_FIVE).optimize() -ONE_POINT_FIVE = pynini.union(TA_ONE_POINT_FIVE, EN_ONE_POINT_FIVE).optimize() -TWO_POINT_FIVE = pynini.union(TA_TWO_POINT_FIVE, EN_TWO_POINT_FIVE).optimize() -DECIMAL_25 = pynini.union(TA_DECIMAL_25, EN_DECIMAL_25).optimize() -DECIMAL_75 = pynini.union(TA_DECIMAL_75, EN_DECIMAL_75).optimize() - -# Symbol constants -TA_BY = "வகுத்தல்" -LOWERCASE_X = "x" -UPPERCASE_X = "X" -ASTERISK = "*" -HYPHEN = "-" -SLASH = "/" -COMMA = "," -PERIOD = "." -TA_PERIOD = "।" - -NEMO_LOWER = pynini.union(*string.ascii_lowercase).optimize() -NEMO_UPPER = pynini.union(*string.ascii_uppercase).optimize() -NEMO_ALPHA = pynini.union(NEMO_LOWER, NEMO_UPPER).optimize() -NEMO_HEX = pynini.union(*string.hexdigits).optimize() + NEMO_NON_BREAKING_SPACE = u"\u00a0" NEMO_SPACE = " " NEMO_WHITE_SPACE = pynini.union(" ", "\t", "\n", "\r", u"\u00a0").optimize() NEMO_NOT_SPACE = pynini.difference(NEMO_CHAR, NEMO_WHITE_SPACE).optimize() NEMO_NOT_QUOTE = pynini.difference(NEMO_CHAR, r'"').optimize() -TO_LOWER = pynini.union(*[pynini.cross(x, y) for x, y in zip(string.ascii_uppercase, string.ascii_lowercase)]) -TO_UPPER = pynini.invert(TO_LOWER) NEMO_SIGMA = pynini.closure(NEMO_CHAR) - delete_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE)) -delete_zero_or_one_space = pynutil.delete(pynini.closure(NEMO_WHITE_SPACE, 0, 1)) insert_space = pynutil.insert(" ") delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") -delete_preserve_order = pynini.closure( - pynutil.delete(" preserve_order: true") - | (pynutil.delete(" field_order: \"") + NEMO_NOT_QUOTE + pynutil.delete("\"")) -) - MIN_NEG_WEIGHT = -0.0001 -MIN_POS_WEIGHT = 0.0001 -INPUT_CASED = "cased" -INPUT_LOWER_CASED = "lower_cased" -MINUS = pynini.union(" எதிர்மறை ", " எதிர்மறை ").optimize() - - -def capitalized_input_graph( - graph: 'pynini.FstLike', original_graph_weight: float = None, capitalized_graph_weight: float = None -) -> 'pynini.FstLike': - """ - Allow graph input to be capitalized, e.g. for ITN) - - Args: - graph: FstGraph - original_graph_weight: weight to add to the original `graph` - capitalized_graph_weight: weight to add to the capitalized graph - """ - capitalized_graph = pynini.compose(TO_LOWER + NEMO_SIGMA, graph).optimize() - - if original_graph_weight is not None: - graph = pynutil.add_weight(graph, weight=original_graph_weight) - - if capitalized_graph_weight is not None: - capitalized_graph = pynutil.add_weight(capitalized_graph, weight=capitalized_graph_weight) - - graph |= capitalized_graph - return graph - def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): """ @@ -154,7 +71,6 @@ def convert_space(fst) -> 'pynini.FstLike': """ return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) - class GraphFst: """ Base class for all grammar fsts. diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 78080c548..0eb93c960 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -13,6 +13,7 @@ # limitations under the License. import pynini from pynini.lib import pynutil + from nemo_text_processing.text_normalization.ta.graph_utils import ( NEMO_ALL_DIGIT, NEMO_ALL_ZERO, @@ -31,394 +32,118 @@ class CardinalFst(GraphFst): def __init__(self, deterministic: bool = True, lm: bool = False): super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) - zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) - hundred_ta = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) - teens_ties_hi = pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")) - teens_ties_en = pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")) - teens_ties = pynini.union(teens_ties_hi, teens_ties_en) - teens_and_ties = pynutil.add_weight(teens_ties, -0.1) - self.digit = digit - self.zero = zero - self.hundred_ta = hundred_ta - self.teens_and_ties = teens_and_ties - single_digit = digit | zero - single_digit_graph = digit | zero - self.single_digits_graph = single_digit_graph + pynini.closure(insert_space + single_digit_graph) - zero_delete = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) + def sf(name): + return pynini.string_file(get_abs_path(f"data/numbers/{name}.tsv")) - def create_graph_suffix(digit_graph, suffix, zeros_counts): - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix - return digit_graph + (z**zeros_counts) + suffix + digit = sf("digit") + zero = sf("zero") + teens_ties = pynini.union(sf("teens_and_ties"), sf("teens_and_ties_en")) + teens_and_ties = pynutil.add_weight(teens_ties, -0.1) - def create_larger_number_graph(digit_graph, suffix, zeros_counts, sub_graph): - ins = pynutil.insert(" ") - z = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO | pynini.accep("௦")), -0.1) - if zeros_counts == 0: - return digit_graph + suffix + ins + sub_graph - return digit_graph + suffix + (z**zeros_counts) + ins + sub_graph + # digit_oru == digit except "1" takes its prefixing form ஒரு (before scale units) + one_oru = pynini.cross("1", "ஒரு") | pynini.cross("௧", "ஒரு") + digit_oru = (one_oru | pynini.compose(pynini.difference(NEMO_ALL_DIGIT, pynini.union("1", "௧")), digit)).optimize() - # HUNDREDS GRAPH (100-999) + # single hundreds table: absolute forms (நூறு) are keyed by "X00", + # combining forms (நூற்று) by "X"; split them apart by input length. + hundred = sf("hundred_ta") + hundred_ta = pynini.compose(NEMO_ALL_DIGIT ** 3, hundred).optimize() + hundred_prefix = pynini.compose(NEMO_ALL_DIGIT, hundred).optimize() - # exact 100 → நூறு - exact_hundred = pynutil.add_weight( - pynini.union( - pynini.cross("100", "நூறு"), - pynini.cross("௧௦௦", "நூறு"), - ).optimize(), - -1.0, - ) + # ஆயிரம் (exact) and ஆயிரத்து (combining) share the same stem + thousand_stem = sf("thousand") + thousand_exact = thousand_stem + pynutil.insert("ம்") + thousand_prefix = thousand_stem + pynutil.insert("த்து") - # hundred prefixes: 200-900 - fused_hundred_prefix = pynini.union( - pynini.cross("2", "இருநூற்று"), - pynini.cross("3", "முந்நூற்று"), - pynini.cross("4", "நானூற்று"), - pynini.cross("5", "ஐநூற்று"), - pynini.cross("6", "அறுநூற்று"), - pynini.cross("7", "எழுநூற்று"), - pynini.cross("8", "எட்டுநூற்று"), - pynini.cross("9", "ஒன்பதுநூற்று"), - pynini.cross("௨", "இருநூற்று"), - pynini.cross("௩", "முந்நூற்று"), - pynini.cross("௪", "நானூற்று"), - pynini.cross("௫", "ஐநூற்று"), - pynini.cross("௬", "அறுநூற்று"), - pynini.cross("௭", "எழுநூற்று"), - pynini.cross("௮", "எட்டுநூற்று"), - pynini.cross("௯", "ஒன்பதுநூற்று"), - ).optimize() + self.digit = digit + self.zero = zero + self.hundred_ta = hundred_ta + self.teens_and_ties = teens_and_ties - graph_hundreds = hundred_ta - # 101-109 - graph_hundreds |= ( - (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) - + zero_delete - + pynutil.insert(" ") - + single_digit - ) - # 110-199 - graph_hundreds |= (pynini.cross("1", "நூற்று") | pynini.cross("௧", "நூற்று")) + pynutil.insert(" ") + teens_ties - # 201-209 ... 901-909 - graph_hundreds |= fused_hundred_prefix + zero_delete + pynutil.insert(" ") + single_digit - # 210-999 - graph_hundreds |= fused_hundred_prefix + pynutil.insert(" ") + teens_ties - graph_hundreds = graph_hundreds.optimize() + single_digit = digit | zero + self.single_digits_graph = single_digit + pynini.closure(insert_space + single_digit) + zero_del = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO), -0.1) + + def zdel(k): + # NOTE: pynini treats ``fst ** 0`` as Kleene-star, so guard the 0 case. + return zero_del ** k if k > 0 else pynini.accep("") + + def scale(head_exact, head_tail, n, tails): + """One magnitude band: exact multiple + every remainder combination. + + ``head_exact`` consumes the whole exact value; ``head_tail`` consumes only + the leading part and is followed by the deleted trailing zeros, a space and + a smaller sub-number (``tails`` are ordered smallest magnitude first). + """ + graph = head_exact + for i, sub in enumerate(tails): + graph |= head_tail + zdel(n - 1 - i) + insert_space + sub + return graph.optimize() + + def band(base, exact_word, tail_word, n, tails): + """Magnitude band whose head is a number stem plus an inserted unit word.""" + return scale(base + pynutil.insert(exact_word) + zdel(n), base + pynutil.insert(tail_word), n, tails) + + # HUNDREDS (100-999): நூறு / நூற்று forms + graph_hundreds = scale(pynutil.add_weight(hundred_ta, -1.0), hundred_prefix, 2, [single_digit, teens_ties]) self.graph_hundreds = graph_hundreds - # THOUSANDS GRAPH (1000-9999) - # 1000-1999 → ஆயிரம்/ஆயிரத்து - one_k_exact = pynini.cross("1", "ஆயிரம்") | pynini.cross("௧", "ஆயிரம்") - one_k_tail = pynini.cross("1", "ஆயிரத்து") | pynini.cross("௧", "ஆயிரத்து") - # 2000-9000 - fused_thousands_exact = pynini.union( - pynini.cross("2", "இரண்டாயிரம்"), - pynini.cross("3", "மூவாயிரம்"), - pynini.cross("4", "நான்காயிரம்"), - pynini.cross("5", "ஐந்தாயிரம்"), - pynini.cross("6", "ஆறாயிரம்"), - pynini.cross("7", "ஏழாயிரம்"), - pynini.cross("8", "எட்டாயிரம்"), - pynini.cross("9", "ஒன்பதாயிரம்"), - pynini.cross("௨", "இரண்டாயிரம்"), - pynini.cross("௩", "மூவாயிரம்"), - pynini.cross("௪", "நான்காயிரம்"), - pynini.cross("௫", "ஐந்தாயிரம்"), - pynini.cross("௬", "ஆறாயிரம்"), - pynini.cross("௭", "ஏழாயிரம்"), - pynini.cross("௮", "எட்டாயிரம்"), - pynini.cross("௯", "ஒன்பதாயிரம்"), - ).optimize() - - fused_thousands_prefix = pynini.union( - pynini.cross("2", "இரண்டாயிரத்து"), - pynini.cross("3", "மூவாயிரத்து"), - pynini.cross("4", "நான்காயிரத்து"), - pynini.cross("5", "ஐந்தாயிரத்து"), - pynini.cross("6", "ஆறாயிரத்து"), - pynini.cross("7", "ஏழாயிரத்து"), - pynini.cross("8", "எட்டாயிரத்து"), - pynini.cross("9", "ஒன்பதாயிரத்து"), - pynini.cross("௨", "இரண்டாயிரத்து"), - pynini.cross("௩", "மூவாயிரத்து"), - pynini.cross("௪", "நான்காயிரத்து"), - pynini.cross("௫", "ஐந்தாயிரத்து"), - pynini.cross("௬", "ஆறாயிரத்து"), - pynini.cross("௭", "ஏழாயிரத்து"), - pynini.cross("௮", "எட்டாயிரத்து"), - pynini.cross("௯", "ஒன்பதாயிரத்து"), - ).optimize() - - graph_thousands = one_k_exact + (zero_delete**3) - graph_thousands |= one_k_tail + (zero_delete**2) + pynutil.insert(" ") + single_digit - graph_thousands |= one_k_tail + zero_delete + pynutil.insert(" ") + teens_ties - graph_thousands |= one_k_tail + pynutil.insert(" ") + graph_hundreds - graph_thousands |= fused_thousands_exact + (zero_delete**3) - graph_thousands |= fused_thousands_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit - graph_thousands |= fused_thousands_prefix + zero_delete + pynutil.insert(" ") + teens_ties - graph_thousands |= fused_thousands_prefix + pynutil.insert(" ") + graph_hundreds - graph_thousands = graph_thousands.optimize() + # THOUSANDS (1000-9999): ஆயிரம் / ஆயிரத்து forms + graph_thousands = scale(thousand_exact + zdel(3), thousand_prefix, 3, [single_digit, teens_ties, graph_hundreds]) self.graph_thousands = graph_thousands - # TEN-THOUSANDS GRAPH (10000-99999) - # 10000-19999 - fused_ten_k_exact = pynini.union( - pynini.cross("௧௩", "பதிமூன்றுஆயிரம்"), - pynini.cross("௧௨", "பன்னிரண்டுஆயிரம்"), - pynini.cross("௧௧", "பதினொன்றுஆயிரம்"), - pynini.cross("௪௫", "நாற்பத்தைந்தாயிரம்"), - pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரம்"), - ).optimize() - - fused_ten_k_prefix = pynini.union( - pynini.cross("௧௩", "பதிமூன்றுஆயிரத்து"), - pynini.cross("௧௨", "பன்னிரண்டுஆயிரத்து"), - pynini.cross("௧௧", "பதினொன்றுஆயிரத்து"), - pynini.cross("௪௫", "நாற்பத்தைந்தாயிரத்து"), - pynini.cross("௫௫", "ஐம்பத்தைந்தாயிரத்து"), - ).optimize() + # ladder of remainder fillers, smallest magnitude first + tails = [single_digit, teens_ties, graph_hundreds, graph_thousands] - suffix_ten_k_exact = pynutil.insert("ஆயிரம்") - suffix_ten_k_tail = pynutil.insert("ஆயிரத்து") - - graph_ten_thousands = fused_ten_k_exact + (zero_delete**3) - graph_ten_thousands |= fused_ten_k_prefix + (zero_delete**2) + pynutil.insert(" ") + single_digit - graph_ten_thousands |= fused_ten_k_prefix + zero_delete + pynutil.insert(" ") + teens_ties - graph_ten_thousands |= fused_ten_k_prefix + pynutil.insert(" ") + graph_hundreds - graph_ten_thousands |= create_graph_suffix(teens_and_ties, suffix_ten_k_exact, 3) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 2, single_digit) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 1, teens_ties) - graph_ten_thousands |= create_larger_number_graph(teens_and_ties, suffix_ten_k_tail, 0, graph_hundreds) - graph_ten_thousands = graph_ten_thousands.optimize() + # TEN-THOUSANDS (10^4): stem + ஆயிரம் + graph_ten_thousands = band(teens_and_ties, "ஆயிரம்", "ஆயிரத்து", 3, tails[:3]) self.graph_ten_thousands = graph_ten_thousands + tails.append(graph_ten_thousands) - # LAKHS GRAPH (100000-9999999) - # 1 lakh → ஒரு லட்சம் - suffix_lakhs = pynutil.insert(" லட்சம்") - suffix_lakhs_tail = pynutil.insert(" லட்சத்து") - - digit_one_as_oru = pynini.union( - pynini.cross("1", "ஒரு"), - pynini.cross("௧", "ஒரு"), - pynini.cross("2", "இரண்டு"), - pynini.cross("3", "மூன்று"), - pynini.cross("4", "நான்கு"), - pynini.cross("5", "ஐந்து"), - pynini.cross("6", "ஆறு"), - pynini.cross("7", "ஏழு"), - pynini.cross("8", "எட்டு"), - pynini.cross("9", "ஒன்பது"), - pynini.cross("௨", "இரண்டு"), - pynini.cross("௩", "மூன்று"), - pynini.cross("௪", "நான்கு"), - pynini.cross("௫", "ஐந்து"), - pynini.cross("௬", "ஆறு"), - pynini.cross("௭", "ஏழு"), - pynini.cross("௮", "எட்டு"), - pynini.cross("௯", "ஒன்பது"), - ).optimize() - - graph_lakhs = create_graph_suffix(digit_one_as_oru, suffix_lakhs, 5) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 4, single_digit) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 3, teens_ties) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 2, graph_hundreds) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 1, graph_thousands) - graph_lakhs |= create_larger_number_graph(digit_one_as_oru, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_lakhs = graph_lakhs.optimize() + # LAKHS / TEN-LAKHS (10^5, 10^6): stem + லட்சம் + graph_lakhs = band(digit_oru, " லட்சம்", " லட்சத்து", 5, tails[:5]) self.graph_lakhs = graph_lakhs - - graph_ten_lakhs = create_graph_suffix(teens_and_ties, suffix_lakhs, 5) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 4, single_digit) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 3, teens_ties) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 2, graph_hundreds) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 1, graph_thousands) - graph_ten_lakhs |= create_larger_number_graph(teens_and_ties, suffix_lakhs_tail, 0, graph_ten_thousands) - graph_ten_lakhs = graph_ten_lakhs.optimize() + graph_ten_lakhs = band(teens_and_ties, " லட்சம்", " லட்சத்து", 5, tails[:5]) self.graph_ten_lakhs = graph_ten_lakhs - - # CRORES GRAPH — கோடி - # 1 crore → ஒரு கோடி / ஒரு கோடியே - suffix_crores = pynutil.insert(" கோடி") - suffix_crores_tail = pynutil.insert(" கோடியே") - - graph_crores = create_graph_suffix(digit_one_as_oru, suffix_crores, 7) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 6, single_digit) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 5, teens_ties) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 4, graph_hundreds) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 3, graph_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 1, graph_lakhs) - graph_crores |= create_larger_number_graph(digit_one_as_oru, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores = graph_crores.optimize() - - graph_ten_crores = create_graph_suffix(teens_and_ties, suffix_crores, 7) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 6, single_digit) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 5, teens_ties) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 4, graph_hundreds) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 3, graph_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 2, graph_ten_thousands) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores |= create_larger_number_graph(teens_and_ties, suffix_crores_tail, 0, graph_ten_lakhs) - graph_ten_crores = graph_ten_crores.optimize() - - # hundreds of crores: 100-999 கோடி - graph_hundreds_of_crores = create_graph_suffix(exact_hundred, suffix_crores, 7) - graph_hundreds_of_crores |= create_graph_suffix(graph_hundreds, suffix_crores, 7) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 6, single_digit) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 5, teens_ties) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 4, graph_hundreds) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 3, graph_thousands) - graph_hundreds_of_crores |= create_larger_number_graph( - exact_hundred, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 1, graph_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(exact_hundred, suffix_crores_tail, 0, graph_ten_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 6, single_digit) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 5, teens_ties) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 4, graph_hundreds) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 3, graph_thousands) - graph_hundreds_of_crores |= create_larger_number_graph( - graph_hundreds, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 1, graph_lakhs) - graph_hundreds_of_crores |= create_larger_number_graph(graph_hundreds, suffix_crores_tail, 0, graph_ten_lakhs) - graph_hundreds_of_crores = graph_hundreds_of_crores.optimize() - - # thousands of crores: 1000-9999 கோடி - graph_thousands_of_crores = create_graph_suffix(graph_thousands, suffix_crores, 7) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 6, single_digit) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 5, teens_ties) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 4, graph_hundreds) - graph_thousands_of_crores |= create_larger_number_graph( - graph_thousands, suffix_crores_tail, 3, graph_thousands - ) - graph_thousands_of_crores |= create_larger_number_graph( - graph_thousands, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_thousands_of_crores |= create_larger_number_graph(graph_thousands, suffix_crores_tail, 1, graph_lakhs) - graph_thousands_of_crores |= create_larger_number_graph( - graph_thousands, suffix_crores_tail, 0, graph_ten_lakhs - ) - graph_thousands_of_crores = graph_thousands_of_crores.optimize() - - # ten-thousands of crores - graph_ten_thousands_of_crores = create_graph_suffix(graph_ten_thousands, suffix_crores, 7) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 6, single_digit - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 5, teens_ties - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 4, graph_hundreds - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 3, graph_thousands - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 1, graph_lakhs - ) - graph_ten_thousands_of_crores |= create_larger_number_graph( - graph_ten_thousands, suffix_crores_tail, 0, graph_ten_lakhs - ) - graph_ten_thousands_of_crores = graph_ten_thousands_of_crores.optimize() - - # lakhs of crores - graph_lakhs_of_crores = create_graph_suffix(graph_lakhs, suffix_crores, 7) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 6, single_digit) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 5, teens_ties) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 4, graph_hundreds) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 3, graph_thousands) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 2, graph_ten_thousands) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 1, graph_lakhs) - graph_lakhs_of_crores |= create_larger_number_graph(graph_lakhs, suffix_crores_tail, 0, graph_ten_lakhs) - graph_lakhs_of_crores = graph_lakhs_of_crores.optimize() - - graph_ten_lakhs_of_crores = create_graph_suffix(graph_ten_lakhs, suffix_crores, 7) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 6, single_digit) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 5, teens_ties) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 4, graph_hundreds) - graph_ten_lakhs_of_crores |= create_larger_number_graph( - graph_ten_lakhs, suffix_crores_tail, 3, graph_thousands - ) - graph_ten_lakhs_of_crores |= create_larger_number_graph( - graph_ten_lakhs, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_ten_lakhs_of_crores |= create_larger_number_graph(graph_ten_lakhs, suffix_crores_tail, 1, graph_lakhs) - graph_ten_lakhs_of_crores |= create_larger_number_graph( - graph_ten_lakhs, suffix_crores_tail, 0, graph_ten_lakhs - ) - graph_ten_lakhs_of_crores = graph_ten_lakhs_of_crores.optimize() - - # crores of crores - graph_crores_of_crores = create_graph_suffix(graph_crores, suffix_crores, 7) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 6, single_digit) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 5, teens_ties) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 4, graph_hundreds) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 3, graph_thousands) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 2, graph_ten_thousands) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 1, graph_lakhs) - graph_crores_of_crores |= create_larger_number_graph(graph_crores, suffix_crores_tail, 0, graph_ten_lakhs) - graph_crores_of_crores = graph_crores_of_crores.optimize() - - graph_ten_crores_of_crores = create_graph_suffix(graph_ten_crores, suffix_crores, 7) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 6, single_digit) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 5, teens_ties) - graph_ten_crores_of_crores |= create_larger_number_graph( - graph_ten_crores, suffix_crores_tail, 4, graph_hundreds - ) - graph_ten_crores_of_crores |= create_larger_number_graph( - graph_ten_crores, suffix_crores_tail, 3, graph_thousands - ) - graph_ten_crores_of_crores |= create_larger_number_graph( - graph_ten_crores, suffix_crores_tail, 2, graph_ten_thousands - ) - graph_ten_crores_of_crores |= create_larger_number_graph(graph_ten_crores, suffix_crores_tail, 1, graph_lakhs) - graph_ten_crores_of_crores |= create_larger_number_graph( - graph_ten_crores, suffix_crores_tail, 0, graph_ten_lakhs - ) - graph_ten_crores_of_crores = graph_ten_crores_of_crores.optimize() - - # LEADING ZERO and FINAL GRAPH - graph_leading_zero = zero + insert_space + single_digit - graph_leading_zero = pynutil.add_weight(graph_leading_zero, 0.5) - - graph_without_leading_zeros = ( - digit - | zero - | teens_and_ties - | exact_hundred - | graph_hundreds - | graph_thousands - | graph_ten_thousands - | graph_lakhs - | graph_ten_lakhs - | graph_crores - | graph_ten_crores - | graph_hundreds_of_crores - | graph_thousands_of_crores - | graph_ten_thousands_of_crores - | graph_lakhs_of_crores - | graph_ten_lakhs_of_crores - | graph_crores_of_crores - | graph_ten_crores_of_crores + tails += [graph_lakhs, graph_ten_lakhs] + + # CRORES and higher (10^7 .. 10^15): stem + கோடி + crore_bases = [ + digit_oru, # crores + teens_and_ties, # ten-crores + graph_hundreds, # hundreds of crores + graph_thousands, # thousands of crores + graph_ten_thousands, # ten-thousands of crores + graph_lakhs, # lakhs of crores + graph_ten_lakhs, # ten-lakhs of crores + ] + crore_graphs = [band(b, " கோடி", " கோடியே", 7, tails) for b in crore_bases] + graph_crores, graph_ten_crores = crore_graphs[0], crore_graphs[1] + crore_graphs += [ + band(graph_crores, " கோடி", " கோடியே", 7, tails), # crores of crores + band(graph_ten_crores, " கோடி", " கோடியே", 7, tails), # ten-crores of crores + ] + + # FINAL GRAPH + graph_without_leading_zeros = pynini.union( + digit, + zero, + teens_and_ties, + graph_hundreds, + graph_thousands, + graph_ten_thousands, + graph_lakhs, + graph_ten_lakhs, + *crore_graphs, ) self.graph_without_leading_zeros = graph_without_leading_zeros.optimize() - cardinal_with_leading_zeros = pynini.compose( - NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph + cardinal_with_leading_zeros = pynutil.add_weight( + pynini.compose(NEMO_ALL_ZERO + pynini.closure(NEMO_ALL_DIGIT), self.single_digits_graph), 0.5 ) - cardinal_with_leading_zeros = pynutil.add_weight(cardinal_with_leading_zeros, 0.5) + self.final_graph = (self.graph_without_leading_zeros | cardinal_with_leading_zeros).optimize() - final_graph = graph_without_leading_zeros | cardinal_with_leading_zeros optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) - self.final_graph = final_graph.optimize() final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") - final_graph = self.add_tokens(final_graph) - self.fst = final_graph + self.fst = self.add_tokens(final_graph) diff --git a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py index 7d173ff2f..6db4c15a4 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py +++ b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py @@ -27,19 +27,7 @@ generator_main, ) from nemo_text_processing.text_normalization.ta.taggers.cardinal import CardinalFst - -# from nemo_text_processing.text_normalization.hi.taggers.date import DateFst -# from nemo_text_processing.text_normalization.hi.taggers.decimal import DecimalFst -# from nemo_text_processing.text_normalization.hi.taggers.electronic import ElectronicFst -# from nemo_text_processing.text_normalization.hi.taggers.fraction import FractionFst -# from nemo_text_processing.text_normalization.hi.taggers.measure import MeasureFst -# from nemo_text_processing.text_normalization.hi.taggers.money import MoneyFst -# from nemo_text_processing.text_normalization.hi.taggers.ordinal import OrdinalFst from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst - -# from nemo_text_processing.text_normalization.hi.taggers.telephone import TelephoneFst -# from nemo_text_processing.text_normalization.hi.taggers.time import TimeFst -# from nemo_text_processing.text_normalization.hi.taggers.whitelist import WhiteListFst from nemo_text_processing.text_normalization.ta.taggers.word import WordFst @@ -74,7 +62,7 @@ def __init__( whitelist_file = os.path.basename(whitelist) if whitelist else "" far_file = os.path.join( cache_dir, - f"hi_tn_{deterministic}_deterministic_{input_case}_{whitelist_file}_tokenize.far", + f"ta_tn_{deterministic}_deterministic_{input_case}_{whitelist_file}_tokenize.far", ) if not overwrite_cache and far_file and os.path.exists(far_file): self.fst = pynini.Far(far_file, mode="r")["tokenize_and_classify"] @@ -85,52 +73,11 @@ def __init__( cardinal = CardinalFst(deterministic=deterministic) cardinal_graph = cardinal.fst - # decimal = DecimalFst(cardinal=cardinal, deterministic=deterministic) - # decimal_graph = decimal.fst - - # fraction = FractionFst(cardinal=cardinal, deterministic=deterministic) - # fraction_graph = fraction.fst - - # date = DateFst(cardinal=cardinal) - # date_graph = date.fst - - # timefst = TimeFst(cardinal=cardinal) - # time_graph = timefst.fst - - # ordinal = OrdinalFst(cardinal=cardinal, deterministic=deterministic) - # ordinal_graph = ordinal.fst - - # measure = MeasureFst(cardinal=cardinal, decimal=decimal, ordinal=ordinal, input_case=input_case) - # measure_graph = measure.fst - - # money = MoneyFst(cardinal=cardinal) - # money_graph = money.fst - - # whitelist_graph = WhiteListFst( - # input_case=input_case, deterministic=deterministic, input_file=whitelist - # ).fst - punctuation = PunctuationFst(deterministic=deterministic) punct_graph = punctuation.fst - # telephone = TelephoneFst() - # telephone_graph = telephone.fst - - # electronic = ElectronicFst(deterministic=deterministic) - # electronic_graph = electronic.fst - classify = ( - # pynutil.add_weight(whitelist_graph, 1.01)| pynutil.add_weight(cardinal_graph, 1.1) - # | pynutil.add_weight(decimal_graph, 1.1) - # | pynutil.add_weight(fraction_graph, 1.1) - # | pynutil.add_weight(date_graph, 1.1) - # | pynutil.add_weight(time_graph, 1.1) - # | pynutil.add_weight(measure_graph, 1.1) - # | pynutil.add_weight(money_graph, 1.1) - # | pynutil.add_weight(telephone_graph, 1.1) - # | pynutil.add_weight(ordinal_graph, 1.1) - # | pynutil.add_weight(electronic_graph, 1.1) ) word_graph = WordFst(punctuation=punctuation, deterministic=deterministic).fst diff --git a/nemo_text_processing/text_normalization/ta/utils.py b/nemo_text_processing/text_normalization/ta/utils.py index fa0471fb6..c03130ed1 100644 --- a/nemo_text_processing/text_normalization/ta/utils.py +++ b/nemo_text_processing/text_normalization/ta/utils.py @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import csv import os -import pynini def get_abs_path(rel_path): @@ -26,49 +24,4 @@ def get_abs_path(rel_path): Returns absolute path """ - return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path - - -def load_labels(abs_path): - """ - loads relative path file as dictionary - - Args: - abs_path: absolute path - - Returns dictionary of mappings - """ - label_tsv = open(abs_path, encoding="utf-8") - labels = list(csv.reader(label_tsv, delimiter="\t")) - label_tsv.close() - return labels - - -def augment_labels_with_punct_at_end(labels): - """ - augments labels: if key ends on a punctuation that value does not have, add a new label - where the value maintains the punctuation - - Args: - labels : input labels - Returns: - additional labels - """ - res = [] - for label in labels: - if len(label) > 1: - if label[0][-1] == "." and label[1][-1] != ".": - res.append([label[0], label[1] + "."] + label[2:]) - return res - - -def apply_fst(text, fst): - """Given a string input, returns the output string - produced by traversing the path with lowest weight. - If no valid path accepts input string, returns an - error. - """ - try: - print(pynini.shortestpath(text @ fst).string()) - except pynini.FstOpError: - print(f"Error: No valid output with given input: '{text}'") + return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py index 59676b890..9065cf2a5 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/cardinal.py @@ -15,7 +15,7 @@ import pynini from pynini.lib import pynutil -from nemo_text_processing.text_normalization.hi.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space +from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_NOT_QUOTE, GraphFst, delete_space class CardinalFst(GraphFst): diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py index 2d05b7cea..64fe9b1d8 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py @@ -14,7 +14,6 @@ import os - import pynini from pynini.lib import pynutil @@ -69,7 +68,7 @@ def get_punct_postprocess_graph(self): allow_space_before_punct = quotes + dashes + brackets no_space_before_punct = [m for m in punct_marks_all if m not in allow_space_before_punct] - # Add Hindi-specific punctuation + # Add Tamil-specific punctuation no_space_before_punct.extend(["।", ",", ".", ";", ":", "!", "?"]) # Remove duplicates no_space_before_punct = list(set(no_space_before_punct)) diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py index e3012e7bd..329d0211b 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py @@ -15,18 +15,6 @@ from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst from nemo_text_processing.text_normalization.ta.verbalizers.cardinal import CardinalFst -# from nemo_text_processing.text_normalization.ta.verbalizers.date import DateFst -# from nemo_text_processing.text_normalization.hi.verbalizers.decimal import DecimalFst -# from nemo_text_processing.text_normalization.hi.verbalizers.electronic import ElectronicFst -# from nemo_text_processing.text_normalization.hi.verbalizers.fraction import FractionFst -# from nemo_text_processing.text_normalization.hi.verbalizers.measure import MeasureFst -# from nemo_text_processing.text_normalization.hi.verbalizers.money import MoneyFst -# from nemo_text_processing.text_normalization.hi.verbalizers.ordinal import OrdinalFst -# from nemo_text_processing.text_normalization.hi.verbalizers.telephone import TelephoneFst -# from nemo_text_processing.text_normalization.hi.verbalizers.time import TimeFst -# from nemo_text_processing.text_normalization.ta.verbalizers.whitelist import WhiteListFst - - class VerbalizeFst(GraphFst): """ Composes other verbalizer grammars. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py index 5eb01cd97..f0d78ea9e 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize_final.py @@ -46,7 +46,7 @@ def __init__(self, deterministic: bool = True, cache_dir: str = None, overwrite_ far_file = None if cache_dir is not None and cache_dir != "None": os.makedirs(cache_dir, exist_ok=True) - far_file = os.path.join(cache_dir, f"en_tn_{deterministic}_deterministic_verbalizer.far") + far_file = os.path.join(cache_dir, f"ta_tn_{deterministic}_deterministic_verbalizer.far") if not overwrite_cache and far_file and os.path.exists(far_file): self.fst = pynini.Far(far_file, mode="r")["verbalize"] logging.info(f'VerbalizeFinalFst graph was restored from {far_file}.') diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index f9683a102..ccea835ce 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -13,10 +13,8 @@ # limitations under the License. import pynini from pynini.lib import pynutil - from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space - class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. diff --git a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt index 143acc686..299a5754f 100644 --- a/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt +++ b/tests/nemo_text_processing/ta/data_text_normalization/test_cases_cardinal.txt @@ -1,148 +1,53 @@ -௪ ஃபோர்கள்~நான்கு ஃபோர்கள் +4 நான்குகள்~நான்கு நான்குகள் ௬ வீரர்கள் அவுட்~ஆறு வீரர்கள் அவுட் -ஒன்பிளஸ் ௮ ப்ரோ~ஒன்பிளஸ் எட்டு ப்ரோ -௫ சார்ஜர்கள்~ஐந்து சார்ஜர்கள் -௪ ஓவரில் ௧௭ ரன்கள்~நான்கு ஓவரில் பதினேழு ரன்கள் +4 ஓவர்களில் 17 ரன்கள்~நான்கு ஓவர்களில் பதினேழு ரன்கள் ௫ சாக்லெட்டுகள் ௯ டாஃபிகள்~ஐந்து சாக்லெட்டுகள் ஒன்பது டாஃபிகள் -௧௦௦௯௯~பத்துஆயிரத்து தொண்ணூற்றிஒன்பது -௧௦௦௦௦௧~ஒரு லட்சத்து ஒன்று -௪ சிக்ஸர்கள் ௧௪ நான்குகள்~நான்கு சிக்ஸர்கள் பதினான்கு நான்குகள் -௬ ரன்கள் எடுத்தார்~ஆறு ரன்கள் எடுத்தார் -௩ கோல்கள் அடித்தார்~மூன்று கோல்கள் அடித்தார் +10099~பத்துஆயிரத்து தொண்ணூற்றிஒன்பது +100001~ஒரு லட்சத்து ஒன்று ௫ நான்குகள்~ஐந்து நான்குகள் -௨ சிக்ஸர்கள் ௧௨ ரன்கள்~இரண்டு சிக்ஸர்கள் பன்னிரண்டு ரன்கள் -௯ புள்ளிகள்~ஒன்பது புள்ளிகள் -௪ உயிரிழப்பு ௧௮ காயம்~நான்கு உயிரிழப்பு பதினெட்டு காயம் -௫ கோல்கள் அடி~ஐந்து கோல்கள் அடி -௩ பேட்ஸ்மேன்கள் ௧௨ வீரர்கள்~மூன்று பேட்ஸ்மேன்கள் பன்னிரண்டு வீரர்கள் -௫ தோல்வி ௧ டிரா ௧௭ வெற்றி~ஐந்து தோல்வி ஒன்று டிரா பதினேழு வெற்றி -௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு -பாடம் ௧௦ ஸ்லோகம் ௨~பாடம் பத்து ஸ்லோகம் இரண்டு -௧௦௧~நூற்று ஒன்று -௧௦௨~நூற்று இரண்டு -௧௦௩~நூற்று மூன்று -௧௦௪~நூற்று நான்கு +4 பேர் உயிரிழப்பு 18 பேருக்கு காயம்~நான்கு பேர் உயிரிழப்பு பதினெட்டு பேருக்கு காயம் +51022345567~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +அத்தியாயம் ௧௦ ஸ்லோகம் ௨~அத்தியாயம் பத்து ஸ்லோகம் இரண்டு +101~நூற்று ஒன்று +100~நூறு +௧௦௦~நூறு ௧௦௫~நூற்று ஐந்து -௧௦௬~நூற்று ஆறு -௧௦௭~நூற்று ஏழு -௧௦௮~நூற்று எட்டு -௧௦௯~நூற்று ஒன்பது -௧௧௦~நூற்று பத்து -௧௧௧~நூற்று பதினொன்று -௧௧௨~நூற்று பன்னிரண்டு -௧௧௩~நூற்று பதிமூன்று -௧௧௪~நூற்று பதினான்கு -௧௧௫~நூற்று பதினைந்து -௧௧௬~நூற்று பதினாறு -௮௧௭~எட்டுநூற்று பதினேழு -௮௧௮~எட்டுநூற்று பதினெட்டு -௮௧௯~எட்டுநூற்று பத்தொன்பது -௮௨௦~எட்டுநூற்று இருபது -௮௨௧~எட்டுநூற்று இருபத்தொன்று -௮௨௨~எட்டுநூற்று இருபத்திரண்டு -௮௨௩~எட்டுநூற்று இருபத்திமூன்று -௮௨௪~எட்டுநூற்று இருபத்திநான்கு -௮௨௫~எட்டுநூற்று இருபத்திஐந்து -௮௨௬~எட்டுநூற்று இருபத்திஆறு -௮௨௭~எட்டுநூற்று இருபத்திஏழு -௮௨௮~எட்டுநூற்று இருபத்திஎட்டு -௮௨௯~எட்டுநூற்று இருபத்திஒன்பது -௮௩௦~எட்டுநூற்று முப்பது -௮௩௧~எட்டுநூற்று முப்பத்தொன்று -௮௩௨~எட்டுநூற்று முப்பத்திரண்டு -௮௩௩~எட்டுநூற்று முப்பத்திமூன்று -௮௩௪~எட்டுநூற்று முப்பத்திநான்கு -௮௩௫~எட்டுநூற்று முப்பத்திஐந்து -௮௩௬~எட்டுநூற்று முப்பத்திஆறு -௭௩௭~எழுநூற்று முப்பத்திஏழு -௭௩௮~எழுநூற்று முப்பத்திஎட்டு -௭௩௯~எழுநூற்று முப்பத்திஒன்பது -௭௪௦~எழுநூற்று நாற்பது -௭௪௧~எழுநூற்று நாற்பத்தொன்று -௭௪௨~எழுநூற்று நாற்பத்திரண்டு -௭௪௩~எழுநூற்று நாற்பத்திமூன்று -௭௪௪~எழுநூற்று நாற்பத்திநான்கு -௭௪௫~எழுநூற்று நாற்பத்திஐந்து -௪௪௬~நானூற்று நாற்பத்திஆறு -௪௪௭~நானூற்று நாற்பத்திஏழு -௪௪௮~நானூற்று நாற்பத்திஎட்டு -௪௪௯~நானூற்று நாற்பத்திஒன்பது -௪௫௦~நானூற்று ஐம்பது -௪௬௧~நானூற்று அறுபத்தொன்று -௧௭௫~நூற்று எழுபத்திஐந்து -௧௮௧~நூற்று எண்பத்தொன்று -௧௯௦~நூற்று தொண்ணூறு -௧௯௧~நூற்று தொண்ணூற்றொன்று -௧௯௯~நூற்று தொண்ணூற்றிஒன்பது -௧௦௦௧~ஆயிரத்து ஒன்று -௧௦௯௯~ஆயிரத்து தொண்ணூற்றிஒன்பது +200~இருநூறு +௨௦௦~இருநூறு +300~முந்நூறு +௩௦௦~முந்நூறு +203~இருநூற்று மூன்று +௫௦௨~ஐநூற்று இரண்டு +111~நூற்று பதினொன்று +௧௧௯~நூற்று பத்தொன்பது +130~நூற்று முப்பது +௧௫௦~நூற்று ஐம்பது +312~முந்நூற்று பன்னிரண்டு +௫௨௫~ஐநூற்று இருபத்திஐந்து +425~நானூற்று இருபத்திஐந்து +௯௧௫~ஒன்பதுநூற்று பதினைந்து +1001~ஆயிரத்து ஒன்று +5551 வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐநூற்று ஐம்பத்தொன்று வாழைப்பழங்கள் ௫௫௫௧ வாழைப்பழங்கள்~ஐந்தாயிரத்து ஐநூற்று ஐம்பத்தொன்று வாழைப்பழங்கள் -௫௫௫௫௨ ஆப்பிள்கள்~ஐம்பத்திஐந்துஆயிரத்து ஐநூற்று ஐம்பத்திரண்டு ஆப்பிள்கள் -௫௩~ஐம்பத்திமூன்று -௫௪~ஐம்பத்திநான்கு -௫௫~ஐம்பத்திஐந்து -௫௬~ஐம்பத்திஆறு -௫௭~ஐம்பத்திஏழு -௫௮~ஐம்பத்திஎட்டு -௫௯~ஐம்பத்திஒன்பது -௬௦~அறுபது -௬௧~அறுபத்தொன்று -௬௨~அறுபத்திரண்டு -௬௩~அறுபத்திமூன்று -௬௪~அறுபத்திநான்கு -௬௫~அறுபத்திஐந்து -௬௬~அறுபத்திஆறு -௬௭~அறுபத்திஏழு -௬௮~அறுபத்திஎட்டு -௬௯~அறுபத்திஒன்பது -௭௦~எழுபது -௭௧~எழுபத்தொன்று -௭௨~எழுபத்திரண்டு -௭௩~எழுபத்திமூன்று -௭௪~எழுபத்திநான்கு -௭௫~எழுபத்திஐந்து -௭௬~எழுபத்திஆறு -௭௭~எழுபத்திஏழு -௭௮~எழுபத்திஎட்டு -௭௯~எழுபத்திஒன்பது -௮௦~எண்பது -௮௧~எண்பத்தொன்று -௮௨~எண்பத்திரண்டு -௮௩~எண்பத்திமூன்று -௮௪~எண்பத்திநான்கு -௮௫~எண்பத்திஐந்து -௮௬~எண்பத்திஆறு -௮௭~எண்பத்திஏழு -௮௮~எண்பத்திஎட்டு -௮௯~எண்பத்திஒன்பது -௯௦~தொண்ணூறு +85~எண்பத்திஐந்து ௯௧~தொண்ணூற்றொன்று -௯௨~தொண்ணூற்றிரண்டு -௯௩~தொண்ணூற்றிமூன்று -௯௪~தொண்ணூற்றிநான்கு -௯௫~தொண்ணூற்றிஐந்து -௯௬~தொண்ணூற்றிஆறு -௯௭~தொண்ணூற்றிஏழு -௯௮~தொண்ணூற்றிஎட்டு -௯௯~தொண்ணூற்றிஒன்பது ௧௩௨௩~ஆயிரத்து முந்நூற்று இருபத்திமூன்று -௧௩௪௫~ஆயிரத்து முந்நூற்று நாற்பத்திஐந்து +1345~ஆயிரத்து முந்நூற்று நாற்பத்திஐந்து ௧௩௪௫௬~பதிமூன்றுஆயிரத்து நானூற்று ஐம்பத்திஆறு -௧௨௩௪௬~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்திஆறு +12346~பன்னிரண்டுஆயிரத்து முந்நூற்று நாற்பத்திஆறு ௧௨௩௪௫௬~ஒரு லட்சத்து இருபத்திமூன்றுஆயிரத்து நானூற்று ஐம்பத்திஆறு -௮௭௨௯௮௭~எட்டு லட்சத்து எழுபத்திரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்திஏழு +872987~எட்டு லட்சத்து எழுபத்திரண்டுஆயிரத்து ஒன்பதுநூற்று எண்பத்திஏழு ௯௮௭௬௦௯~ஒன்பது லட்சத்து எண்பத்திஏழுஆயிரத்து அறுநூற்று ஒன்பது -௯௮௭௬௭௮௯~தொண்ணூற்றிஎட்டு லட்சத்து எழுபத்திஆறுஆயிரத்து எழுநூற்று எண்பத்திஒன்பது +9876789~தொண்ணூற்றிஎட்டு லட்சத்து எழுபத்திஆறுஆயிரத்து எழுநூற்று எண்பத்திஒன்பது ௨௩௪௫௫௬௭~இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு -௧௨௩௪௫௫௬௭~ஒரு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +12345567~ஒரு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு ௧௨௧௨௧௨௧௨~ஒரு கோடியே இருபத்தொன்று லட்சத்து இருபத்தொன்றுஆயிரத்து இருநூற்று பன்னிரண்டு -௧௧௨௨௩௪௫௫௬௭~நூற்று பன்னிரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +1122345567~நூற்று பன்னிரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு ௧௦௨௨௩௪௫௫௬௭~நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு -௧௧௦௨௨௩௪௫௫௬௭~ஆயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு +11022345567~ஆயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு ௫௧௦௨௨௩௪௫௫௬௭~ஐந்தாயிரத்து நூற்று இரண்டு கோடியே இருபத்திமூன்று லட்சத்து நாற்பத்திஐந்துஆயிரத்து ஐநூற்று அறுபத்திஏழு -௨ புள்ளிகள் ௧௨ கோல்கள்~இரண்டு புள்ளிகள் பன்னிரண்டு கோல்கள் ௦௫~சுழியம் ஐந்து -௦௧~சுழியம் ஒன்று +01~சுழியம் ஒன்று ௦௭௩~சுழியம் ஏழு மூன்று -௦௦௦௧~சுழியம் சுழியம் சுழியம் ஒன்று +0001~சுழியம் சுழியம் சுழியம் ஒன்று ௦௦௦~சுழியம் சுழியம் சுழியம் \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index 4b9ba5cbd..7d7a23eae 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -14,29 +14,17 @@ import pytest from parameterized import parameterized - -from nemo_text_processing.inverse_text_normalization.inverse_normalize import InverseNormalizer from nemo_text_processing.text_normalization.normalize import Normalizer - from ..utils import CACHE_DIR, parse_test_case_file - class TestCardinal: normalizer = Normalizer( input_case='cased', lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False ) - # inverse_normalizer = InverseNormalizer(lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False) - + @parameterized.expand(parse_test_case_file('ta/data_text_normalization/test_cases_cardinal.txt')) @pytest.mark.run_only_on('CPU') @pytest.mark.unit def test_norm(self, test_input, expected): pred = self.normalizer.normalize(test_input, verbose=False) - assert pred.strip() == expected.strip() - - # @parameterized.expand(parse_test_case_file('ta/data_inverse_text_normalization/test_cases_cardinal.txt')) - # @pytest.mark.run_only_on('CPU') - # @pytest.mark.unit - # def test_denorm(self, test_input, expected): - # pred = self.inverse_normalizer.inverse_normalize(test_input, verbose=False) - # assert pred == expected + assert pred.strip() == expected.strip() \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/test_sparrowhawk_normalization.sh b/tests/nemo_text_processing/ta/test_sparrowhawk_normalization.sh new file mode 100644 index 000000000..fca2affec --- /dev/null +++ b/tests/nemo_text_processing/ta/test_sparrowhawk_normalization.sh @@ -0,0 +1,41 @@ +#! /bin/sh + +PROJECT_DIR=/workspace/tests + +runtest () { + input=$1 + cd /workspace/sparrowhawk/documentation/grammars + + # read test file + while IFS= read -r testcase; do + IFS='~' read -r written spoken <<< "$testcase" + + # Escape backslashes and replace non breaking space with breaking space + escaped_written=$(printf '%s' "$written" | sed 's/\\/\\\\/g') + denorm_pred=$(echo "$escaped_written" | normalizer_main --config=sparrowhawk_configuration.ascii_proto 2>&1 | tail -n 1 | sed 's/\xC2\xA0/ /g') + + # trim white space + # spoken="$(echo -e "${spoken}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + # denorm_pred="$(echo -e "${denorm_pred}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + + # trim white space and remove space before punctuation + spoken="$(echo -e "${spoken}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/ \([!?.]\)/\1/g')" + denorm_pred="$(echo -e "${denorm_pred}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/ \([!?.]\)/\1/g')" + + # input expected actual + assertEquals "$written" "$spoken" "$denorm_pred" + done < "$input" +} + +#testTNSpecialText() { +# input=$PROJECT_DIR/ta/data_text_normalization/test_cases_special_text.txt +# runtest $input +#} + +testTNCardinal() { + input=$PROJECT_DIR/ta/data_text_normalization/test_cases_cardinal.txt + runtest $input +} + +# Load shUnit2 +. $PROJECT_DIR/../shunit2/shunit2 \ No newline at end of file diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index d6dfebdde..0bf6149d7 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -103,6 +103,7 @@ def parse_args(): 'es_en', 'he', 'hi', + 'ta', 'hy', 'mr', 'ja', @@ -139,7 +140,7 @@ def parse_args(): if __name__ == '__main__': args = parse_args() - if args.language in ['ru', 'es_en', 'mr'] and args.grammars == 'tn_grammars': + if args.language in ['ru', 'es_en', 'mr', 'ta'] and args.grammars == 'tn_grammars': raise ValueError('Only ITN grammars could be deployed in Sparrowhawk for the selected languages.') TNPostProcessingFst = None ITNPostProcessingFst = None @@ -223,6 +224,14 @@ def parse_args(): PostProcessingFst as TNPostProcessingFst, ) from nemo_text_processing.text_normalization.hi.verbalizers.verbalize import VerbalizeFst as TNVerbalizeFst + elif args.language == 'ta': + from nemo_text_processing.text_normalization.ta.taggers.tokenize_and_classify import ( + ClassifyFst as TNClassifyFst, + ) + from nemo_text_processing.text_normalization.ta.verbalizers.post_processing import ( + PostProcessingFst as TNPostProcessingFst, + ) + from nemo_text_processing.text_normalization.ta.verbalizers.verbalize import VerbalizeFst as TNVerbalizeFst elif args.language == 'hu': from nemo_text_processing.text_normalization.hu.taggers.tokenize_and_classify import ( ClassifyFst as TNClassifyFst, @@ -354,4 +363,4 @@ def parse_args(): overwrite_cache=args.overwrite_cache, whitelist=args.whitelist, ), - ) + ) \ No newline at end of file From 026875cb07e87ce0ad093dd06fe8eaba400097d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 13:14:49 +0000 Subject: [PATCH 19/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../text_normalization/ta/graph_utils.py | 2 ++ .../text_normalization/ta/taggers/cardinal.py | 26 +++++++++++-------- .../ta/taggers/tokenize_and_classify.py | 4 +-- .../text_normalization/ta/utils.py | 2 +- .../ta/verbalizers/verbalize.py | 1 + .../text_normalization/ta/verbalizers/word.py | 1 + .../nemo_text_processing/ta/test_cardinal.py | 5 ++-- .../pynini_export.py | 2 +- 8 files changed, 25 insertions(+), 18 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 5d7ef5c8b..af455ddff 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -43,6 +43,7 @@ MIN_NEG_WEIGHT = -0.0001 + def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): """ Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. @@ -71,6 +72,7 @@ def convert_space(fst) -> 'pynini.FstLike': """ return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) + class GraphFst: """ Base class for all grammar fsts. diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 0eb93c960..88c14dee9 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -43,12 +43,14 @@ def sf(name): # digit_oru == digit except "1" takes its prefixing form ஒரு (before scale units) one_oru = pynini.cross("1", "ஒரு") | pynini.cross("௧", "ஒரு") - digit_oru = (one_oru | pynini.compose(pynini.difference(NEMO_ALL_DIGIT, pynini.union("1", "௧")), digit)).optimize() + digit_oru = ( + one_oru | pynini.compose(pynini.difference(NEMO_ALL_DIGIT, pynini.union("1", "௧")), digit) + ).optimize() # single hundreds table: absolute forms (நூறு) are keyed by "X00", # combining forms (நூற்று) by "X"; split them apart by input length. hundred = sf("hundred_ta") - hundred_ta = pynini.compose(NEMO_ALL_DIGIT ** 3, hundred).optimize() + hundred_ta = pynini.compose(NEMO_ALL_DIGIT**3, hundred).optimize() hundred_prefix = pynini.compose(NEMO_ALL_DIGIT, hundred).optimize() # ஆயிரம் (exact) and ஆயிரத்து (combining) share the same stem @@ -67,7 +69,7 @@ def sf(name): def zdel(k): # NOTE: pynini treats ``fst ** 0`` as Kleene-star, so guard the 0 case. - return zero_del ** k if k > 0 else pynini.accep("") + return zero_del**k if k > 0 else pynini.accep("") def scale(head_exact, head_tail, n, tails): """One magnitude band: exact multiple + every remainder combination. @@ -90,7 +92,9 @@ def band(base, exact_word, tail_word, n, tails): self.graph_hundreds = graph_hundreds # THOUSANDS (1000-9999): ஆயிரம் / ஆயிரத்து forms - graph_thousands = scale(thousand_exact + zdel(3), thousand_prefix, 3, [single_digit, teens_ties, graph_hundreds]) + graph_thousands = scale( + thousand_exact + zdel(3), thousand_prefix, 3, [single_digit, teens_ties, graph_hundreds] + ) self.graph_thousands = graph_thousands # ladder of remainder fillers, smallest magnitude first @@ -110,18 +114,18 @@ def band(base, exact_word, tail_word, n, tails): # CRORES and higher (10^7 .. 10^15): stem + கோடி crore_bases = [ - digit_oru, # crores - teens_and_ties, # ten-crores - graph_hundreds, # hundreds of crores - graph_thousands, # thousands of crores + digit_oru, # crores + teens_and_ties, # ten-crores + graph_hundreds, # hundreds of crores + graph_thousands, # thousands of crores graph_ten_thousands, # ten-thousands of crores - graph_lakhs, # lakhs of crores - graph_ten_lakhs, # ten-lakhs of crores + graph_lakhs, # lakhs of crores + graph_ten_lakhs, # ten-lakhs of crores ] crore_graphs = [band(b, " கோடி", " கோடியே", 7, tails) for b in crore_bases] graph_crores, graph_ten_crores = crore_graphs[0], crore_graphs[1] crore_graphs += [ - band(graph_crores, " கோடி", " கோடியே", 7, tails), # crores of crores + band(graph_crores, " கோடி", " கோடியே", 7, tails), # crores of crores band(graph_ten_crores, " கோடி", " கோடியே", 7, tails), # ten-crores of crores ] diff --git a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py index 6db4c15a4..ad2a18212 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py +++ b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py @@ -76,9 +76,7 @@ def __init__( punctuation = PunctuationFst(deterministic=deterministic) punct_graph = punctuation.fst - classify = ( - pynutil.add_weight(cardinal_graph, 1.1) - ) + classify = pynutil.add_weight(cardinal_graph, 1.1) word_graph = WordFst(punctuation=punctuation, deterministic=deterministic).fst diff --git a/nemo_text_processing/text_normalization/ta/utils.py b/nemo_text_processing/text_normalization/ta/utils.py index c03130ed1..2bcba780d 100644 --- a/nemo_text_processing/text_normalization/ta/utils.py +++ b/nemo_text_processing/text_normalization/ta/utils.py @@ -24,4 +24,4 @@ def get_abs_path(rel_path): Returns absolute path """ - return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path \ No newline at end of file + return os.path.dirname(os.path.abspath(__file__)) + '/' + rel_path diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py index 329d0211b..67c87718b 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/verbalize.py @@ -15,6 +15,7 @@ from nemo_text_processing.text_normalization.ta.graph_utils import GraphFst from nemo_text_processing.text_normalization.ta.verbalizers.cardinal import CardinalFst + class VerbalizeFst(GraphFst): """ Composes other verbalizer grammars. diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index ccea835ce..e7c239c2a 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -15,6 +15,7 @@ from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index 7d7a23eae..8ef20ed72 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -17,14 +17,15 @@ from nemo_text_processing.text_normalization.normalize import Normalizer from ..utils import CACHE_DIR, parse_test_case_file + class TestCardinal: normalizer = Normalizer( input_case='cased', lang='ta', cache_dir=CACHE_DIR, overwrite_cache=False, post_process=False ) - + @parameterized.expand(parse_test_case_file('ta/data_text_normalization/test_cases_cardinal.txt')) @pytest.mark.run_only_on('CPU') @pytest.mark.unit def test_norm(self, test_input, expected): pred = self.normalizer.normalize(test_input, verbose=False) - assert pred.strip() == expected.strip() \ No newline at end of file + assert pred.strip() == expected.strip() diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index 92807b021..a0f3aa3e0 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -372,4 +372,4 @@ def parse_args(): overwrite_cache=args.overwrite_cache, whitelist=args.whitelist, ), - ) \ No newline at end of file + ) From 556141050705cf77874ccd1a59e127792e7e3a1e Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Fri, 24 Jul 2026 09:56:18 +0530 Subject: [PATCH 20/29] Modified Cardinal Signed-off-by: surendran-246 --- Jenkinsfile | 1 + tools/text_processing_deployment/pynini_export.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index e05dd0e9b..825f78044 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -30,6 +30,7 @@ pipeline { JA_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/10-17-24-1' HI_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-04-26-5' KO_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-04-25-6' + TA_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/07-21-26-0' DEFAULT_TN_CACHE='/home/jenkins/TestData/text_norm/ci/grammars/06-08-23-0' } stages { diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index a0f3aa3e0..0f45c4575 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -141,7 +141,7 @@ def parse_args(): if __name__ == '__main__': args = parse_args() - if args.language in ['ru', 'es_en', 'hi_en', 'mr'] and args.grammars == 'tn_grammars': + if args.language in ['ru', 'es_en', 'hi_en', 'mr', 'ta'] and args.grammars == 'tn_grammars': raise ValueError('Only ITN grammars could be deployed in Sparrowhawk for the selected languages.') TNPostProcessingFst = None ITNPostProcessingFst = None From 9bbb0596499492765b19abe3ad61c482996164e0 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Mon, 10 Aug 2026 12:23:18 +0530 Subject: [PATCH 21/29] Update Cardinal class Signed-off-by: surendran-246 --- .../text_normalization/ta/data/numbers/thousand.tsv | 2 +- nemo_text_processing/text_normalization/ta/taggers/cardinal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv index 001a7719f..1a16b1271 100644 --- a/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv +++ b/nemo_text_processing/text_normalization/ta/data/numbers/thousand.tsv @@ -15,4 +15,4 @@ ௬ ஆறாயிர ௭ ஏழாயிர ௮ எட்டாயிர -௯ ஒன்பதாயிர +௯ ஒன்பதாயிர \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 88c14dee9..f2d5bdf3a 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -150,4 +150,4 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") - self.fst = self.add_tokens(final_graph) + self.fst = self.add_tokens(final_graph) \ No newline at end of file From 3982a3d0c538997ae93677d8575d46e3c8001ffb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 06:53:56 +0000 Subject: [PATCH 22/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- nemo_text_processing/text_normalization/ta/taggers/cardinal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index f2d5bdf3a..88c14dee9 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -150,4 +150,4 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") - self.fst = self.add_tokens(final_graph) \ No newline at end of file + self.fst = self.add_tokens(final_graph) From bf509552ca621f3abdc439a6884787ae0bbf6b30 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 18 Aug 2026 12:55:33 +0530 Subject: [PATCH 23/29] Updated Cardinal class based on PR reviews Signed-off-by: surendran-246 --- .../text_normalization/normalize.py | 9 +- .../text_normalization/run_evaluate.py | 4 - .../ta/data/numbers/crore.tsv | 2 + .../text_normalization/ta/graph_utils.py | 15 +-- .../text_normalization/ta/taggers/cardinal.py | 57 ++++++----- .../ta/taggers/tokenize_and_classify.py | 2 +- .../text_normalization/ta/taggers/word.py | 48 +--------- .../ta/verbalizers/post_processing.py | 95 ------------------- .../text_normalization/ta/verbalizers/word.py | 23 ++--- .../nemo_text_processing/ta/test_cardinal.py | 2 +- 10 files changed, 55 insertions(+), 202 deletions(-) create mode 100644 nemo_text_processing/text_normalization/ta/data/numbers/crore.tsv delete mode 100644 nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py diff --git a/nemo_text_processing/text_normalization/normalize.py b/nemo_text_processing/text_normalization/normalize.py index 34834f081..a7e001652 100644 --- a/nemo_text_processing/text_normalization/normalize.py +++ b/nemo_text_processing/text_normalization/normalize.py @@ -194,11 +194,8 @@ def __init__( from nemo_text_processing.text_normalization.ko.verbalizers.verbalize_final import VerbalizeFinalFst elif lang == 'ta': from nemo_text_processing.text_normalization.ta.taggers.tokenize_and_classify import ClassifyFst - from nemo_text_processing.text_normalization.ta.verbalizers.post_processing import PostProcessingFst from nemo_text_processing.text_normalization.ta.verbalizers.verbalize_final import VerbalizeFinalFst - if post_process: - self.post_processor = PostProcessingFst(cache_dir=cache_dir, overwrite_cache=overwrite_cache) else: raise NotImplementedError(f"Language {lang} has not been supported yet.") @@ -399,11 +396,7 @@ def normalize( return text output = SPACE_DUP.sub(' ', output[1:]) - if ( - self.lang in ["en", "hi", "ta", "vi"] - and hasattr(self, 'post_processor') - and self.post_processor is not None - ): + if self.lang in ["en", "hi", "vi"] and hasattr(self, 'post_processor') and self.post_processor is not None: output = self.post_process(output) if punct_post_process: diff --git a/nemo_text_processing/text_normalization/run_evaluate.py b/nemo_text_processing/text_normalization/run_evaluate.py index fd0fac207..cf0b6efb2 100644 --- a/nemo_text_processing/text_normalization/run_evaluate.py +++ b/nemo_text_processing/text_normalization/run_evaluate.py @@ -67,10 +67,6 @@ def parse_args(): to_lower = args.input_case == "lower_cased" training_data = load_files([file_path], to_lower=to_lower) - # print("Loading training data: " + file_path) - # to_lower = True if args.input_case == "lower_cased" else False - # training_data = load_files([file_path], to_lower=to_lower) - if args.filter: training_data = filter_loaded_data(training_data) diff --git a/nemo_text_processing/text_normalization/ta/data/numbers/crore.tsv b/nemo_text_processing/text_normalization/ta/data/numbers/crore.tsv new file mode 100644 index 000000000..2c92d20d7 --- /dev/null +++ b/nemo_text_processing/text_normalization/ta/data/numbers/crore.tsv @@ -0,0 +1,2 @@ +கோடி +கோடியே \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index af455ddff..51cb213f5 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -22,13 +22,16 @@ from pynini.export import export from pynini.lib import byte, pynutil, utf8 +from nemo_text_processing.text_normalization.ta.utils import get_abs_path + NEMO_CHAR = utf8.VALID_UTF8_CHAR -NEMO_DIGIT = byte.DIGIT -NEMO_TA_DIGIT = pynini.union("௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯").optimize() -# Combined TAMIL and Arabic digits for graphs that need to accept both -NEMO_ALL_DIGIT = pynini.union(NEMO_TA_DIGIT, NEMO_DIGIT).optimize() -NEMO_ALL_ZERO = pynini.union("௦", "0").optimize() +ta_digit_map = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) +ta_zero_map = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + +ta_digit_only = pynini.project(ta_digit_map, "input").optimize() +NEMO_ALL_ZERO = pynini.project(ta_zero_map, "input").optimize() +NEMO_ALL_DIGIT = pynini.union(ta_digit_only, NEMO_ALL_ZERO).optimize() NEMO_NON_BREAKING_SPACE = u"\u00a0" NEMO_SPACE = " " @@ -139,4 +142,4 @@ def delete_tokens(self, fst) -> 'pynini.FstLike': + delete_space + pynutil.delete("}") ) - return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 88c14dee9..ca1555eea 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -22,39 +22,39 @@ ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path - class CardinalFst(GraphFst): """ - Finite state transducer for classifying cardinals, e.g. - -23 -> cardinal { negative: "true" integer: "இருபத்து மூன்று" } - The highest unit used is கோடி. + Finite state transducer for classifying cardinals + e.g. 23 -> cardinal { integer: "இருபத்திமூன்று" } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transduction are generated (used for audio-based normalization) """ def __init__(self, deterministic: bool = True, lm: bool = False): super().__init__(name="cardinal", kind="classify", deterministic=deterministic) - def sf(name): - return pynini.string_file(get_abs_path(f"data/numbers/{name}.tsv")) - - digit = sf("digit") - zero = sf("zero") - teens_ties = pynini.union(sf("teens_and_ties"), sf("teens_and_ties_en")) - teens_and_ties = pynutil.add_weight(teens_ties, -0.1) + digit = pynini.string_file(get_abs_path("data/numbers/digit.tsv")) + zero = pynini.string_file(get_abs_path("data/numbers/zero.tsv")) + teens_ties = pynini.union( + pynini.string_file(get_abs_path("data/numbers/teens_and_ties.tsv")), + pynini.string_file(get_abs_path("data/numbers/teens_and_ties_en.tsv")), + ) + teens_and_ties = teens_ties - # digit_oru == digit except "1" takes its prefixing form ஒரு (before scale units) + # digit_oru one_oru = pynini.cross("1", "ஒரு") | pynini.cross("௧", "ஒரு") digit_oru = ( one_oru | pynini.compose(pynini.difference(NEMO_ALL_DIGIT, pynini.union("1", "௧")), digit) ).optimize() - # single hundreds table: absolute forms (நூறு) are keyed by "X00", - # combining forms (நூற்று) by "X"; split them apart by input length. - hundred = sf("hundred_ta") + hundred = pynini.string_file(get_abs_path("data/numbers/hundred_ta.tsv")) hundred_ta = pynini.compose(NEMO_ALL_DIGIT**3, hundred).optimize() hundred_prefix = pynini.compose(NEMO_ALL_DIGIT, hundred).optimize() # ஆயிரம் (exact) and ஆயிரத்து (combining) share the same stem - thousand_stem = sf("thousand") + thousand_stem = pynini.string_file(get_abs_path("data/numbers/thousand.tsv")) thousand_exact = thousand_stem + pynutil.insert("ம்") thousand_prefix = thousand_stem + pynutil.insert("த்து") @@ -68,23 +68,15 @@ def sf(name): zero_del = pynutil.add_weight(pynutil.delete(NEMO_ALL_ZERO), -0.1) def zdel(k): - # NOTE: pynini treats ``fst ** 0`` as Kleene-star, so guard the 0 case. return zero_del**k if k > 0 else pynini.accep("") def scale(head_exact, head_tail, n, tails): - """One magnitude band: exact multiple + every remainder combination. - - ``head_exact`` consumes the whole exact value; ``head_tail`` consumes only - the leading part and is followed by the deleted trailing zeros, a space and - a smaller sub-number (``tails`` are ordered smallest magnitude first). - """ graph = head_exact for i, sub in enumerate(tails): graph |= head_tail + zdel(n - 1 - i) + insert_space + sub return graph.optimize() def band(base, exact_word, tail_word, n, tails): - """Magnitude band whose head is a number stem plus an inserted unit word.""" return scale(base + pynutil.insert(exact_word) + zdel(n), base + pynutil.insert(tail_word), n, tails) # HUNDREDS (100-999): நூறு / நூற்று forms @@ -96,8 +88,6 @@ def band(base, exact_word, tail_word, n, tails): thousand_exact + zdel(3), thousand_prefix, 3, [single_digit, teens_ties, graph_hundreds] ) self.graph_thousands = graph_thousands - - # ladder of remainder fillers, smallest magnitude first tails = [single_digit, teens_ties, graph_hundreds, graph_thousands] # TEN-THOUSANDS (10^4): stem + ஆயிரம் @@ -122,11 +112,15 @@ def band(base, exact_word, tail_word, n, tails): graph_lakhs, # lakhs of crores graph_ten_lakhs, # ten-lakhs of crores ] - crore_graphs = [band(b, " கோடி", " கோடியே", 7, tails) for b in crore_bases] + with open(get_abs_path("data/numbers/crore.tsv"), encoding="utf-8") as f: + crore_exact_raw, crore_prefix_raw = [line.strip() for line in f if line.strip()] + crore_word = " " + crore_exact_raw + crore_prefix_word = " " + crore_prefix_raw + crore_graphs = [band(b, crore_word, crore_prefix_word, 7, tails) for b in crore_bases] graph_crores, graph_ten_crores = crore_graphs[0], crore_graphs[1] crore_graphs += [ - band(graph_crores, " கோடி", " கோடியே", 7, tails), # crores of crores - band(graph_ten_crores, " கோடி", " கோடியே", 7, tails), # ten-crores of crores + band(graph_crores, crore_word, crore_prefix_word, 7, tails), # crores of crores + band(graph_ten_crores, crore_word, crore_prefix_word, 7, tails), # ten-crores of crores ] # FINAL GRAPH @@ -150,4 +144,9 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") +<<<<<<< HEAD self.fst = self.add_tokens(final_graph) +======= + final_graph = self.add_tokens(final_graph) + self.fst = final_graph.optimize() +>>>>>>> fbfaf09 (Updated Cardinal class based on PR reviews) diff --git a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py index ad2a18212..af2adf3ba 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py +++ b/nemo_text_processing/text_normalization/ta/taggers/tokenize_and_classify.py @@ -78,7 +78,7 @@ def __init__( classify = pynutil.add_weight(cardinal_graph, 1.1) - word_graph = WordFst(punctuation=punctuation, deterministic=deterministic).fst + word_graph = WordFst().fst punct = pynutil.insert("tokens { ") + pynutil.add_weight(punct_graph, weight=2.1) + pynutil.insert(" }") punct = pynini.closure( diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index ed2566ade..82beec331 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -11,51 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - import pynini from pynini.lib import pynutil - -from nemo_text_processing.text_normalization.ta.graph_utils import ( - MIN_NEG_WEIGHT, - NEMO_NOT_SPACE, - GraphFst, - convert_space, -) -from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst +from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_NOT_SPACE, GraphFst class WordFst(GraphFst): - """ - Finite state transducer for classifying Tamil words. - e.g. சோனா -> tokens { name: " சோனா" } - - Args: - punctuation: PunctuationFst - deterministic: if True will provide a single transduction option, - for False multiple transductions are generated (used for audio-based normalization) - """ - - def __init__(self, punctuation: PunctuationFst, deterministic: bool = True): - super().__init__(name="word", kind="classify", deterministic=deterministic) - - # Define Tamil characters and symbols using pynini.union - TAMIL_CHAR = pynini.union( - *[chr(i) for i in range(0x0B80, 0x0B83 + 1)], # Tamil vowels and consonants - *[chr(i) for i in range(0x0B85, 0x0BB9 + 1)], # More Tamil characters - *[chr(i) for i in range(0x0BBE, 0x0BCD + 1)], # Tamil diacritics - ).optimize() - - # Include punctuation in the graph - punct = punctuation.graph - default_graph = pynini.closure(pynini.difference(NEMO_NOT_SPACE, punct.project("input")), 1) - symbols_to_exclude = (pynini.union("$", "€", "₩", "£", "¥", "#", "%") | punct).optimize() - - # Use TAMIL_CHAR in the graph - graph = pynini.closure(pynini.difference(TAMIL_CHAR, symbols_to_exclude), 1) - graph = pynutil.add_weight(graph, MIN_NEG_WEIGHT) | default_graph - - # Ensure no spaces around punctuation - graph = pynini.closure(graph + pynini.closure(punct + graph, 0, 1)) - - self.graph = convert_space(graph) - self.fst = (pynutil.insert("name: \"") + self.graph + pynutil.insert("\"")).optimize() + def __init__(self): + super().__init__(name="word", kind="classify") + word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") + self.fst = word.optimize() \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py b/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py deleted file mode 100644 index 64fe9b1d8..000000000 --- a/nemo_text_processing/text_normalization/ta/verbalizers/post_processing.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import os -import pynini -from pynini.lib import pynutil - -from nemo_text_processing.text_normalization.ta.graph_utils import ( - MIN_NEG_WEIGHT, - NEMO_CHAR, - NEMO_SIGMA, - generator_main, -) -from nemo_text_processing.text_normalization.ta.taggers.punctuation import PunctuationFst -from nemo_text_processing.utils.logging import logger - - -class PostProcessingFst: - """ - Finite state transducer that post-processing an entire sentence after verbalization is complete, e.g. - removes extra spaces around punctuation marks " ( one hundred and twenty three ) " -> "(one hundred and twenty three)" - - Args: - cache_dir: path to a dir with .far grammar file. Set to None to avoid using cache. - overwrite_cache: set to True to overwrite .far files - """ - - def __init__(self, cache_dir: str = None, overwrite_cache: bool = False): - - far_file = None - if cache_dir is not None and cache_dir != "None": - os.makedirs(cache_dir, exist_ok=True) - far_file = os.path.join(cache_dir, "ta_tn_post_processing.far") - if not overwrite_cache and far_file and os.path.exists(far_file): - self.fst = pynini.Far(far_file, mode="r")["post_process_graph"] - logger.info(f'Post processing graph was restored from {far_file}.') - else: - self.fst = self.get_punct_postprocess_graph() - - if far_file: - generator_main(far_file, {"post_process_graph": self.fst}) - - def get_punct_postprocess_graph(self): - """ - Returns graph to post process punctuation marks. - - By default, spaces are removed before punctuation marks like comma, period, etc. - """ - punct_marks_all = PunctuationFst().punct_marks - - # Punctuation marks that should NOT have space before them - # (most punctuation except quotes, dashes, and opening brackets) - quotes = ["'", "\"", "«"] - dashes = ["-", "—"] - brackets = ["<", "{", "(", r"\["] - allow_space_before_punct = quotes + dashes + brackets - - no_space_before_punct = [m for m in punct_marks_all if m not in allow_space_before_punct] - # Add Tamil-specific punctuation - no_space_before_punct.extend(["।", ",", ".", ";", ":", "!", "?"]) - # Remove duplicates - no_space_before_punct = list(set(no_space_before_punct)) - no_space_before_punct = pynini.union(*no_space_before_punct) - - delete_space = pynutil.delete(" ") - - # Delete space before no_space_before_punct marks - non_punct = pynini.difference(NEMO_CHAR, no_space_before_punct).optimize() - graph = ( - pynini.closure(non_punct) - + pynini.closure( - no_space_before_punct | pynutil.add_weight(delete_space + no_space_before_punct, MIN_NEG_WEIGHT) - ) - + pynini.closure(non_punct) - ) - graph = pynini.closure(graph).optimize() - - # Remove space after opening brackets - no_space_after_punct = pynini.union(*brackets) - no_space_after_punct = pynini.cdrewrite(delete_space, no_space_after_punct, NEMO_SIGMA, NEMO_SIGMA).optimize() - graph = pynini.compose(graph, no_space_after_punct).optimize() - - return graph diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index e7c239c2a..1291ad33a 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -13,30 +13,23 @@ # limitations under the License. import pynini from pynini.lib import pynutil + from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space - - + + class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. - e.g. tokens { name: " சோனா" } -> சோனா - + e.g. tokens { name: "சின்ன" } -> சின்ன + Args: deterministic: if True will provide a single transduction option, for False multiple transduction are generated (used for audio-based normalization) """ - + def __init__(self, deterministic: bool = True): super().__init__(name="word", kind="verbalize", deterministic=deterministic) chars = pynini.closure(NEMO_CHAR - " ", 1) - punct = pynini.union("!", "?", ".", ",", "-", ":", ";", "।") # Add other punctuation marks as needed char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") - - # Ensure no spaces around punctuation - graph = char + pynini.closure(delete_space + punct, 0, 1) - - # Explicitly remove spaces before punctuation - remove_space_before_punct = pynini.cdrewrite(pynini.cross(" ", ""), "", punct, NEMO_SIGMA) - graph = graph @ remove_space_before_punct - - self.fst = graph.optimize() + + self.fst = char.optimize() \ No newline at end of file diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index 8ef20ed72..e5260ace9 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -28,4 +28,4 @@ class TestCardinal: @pytest.mark.unit def test_norm(self, test_input, expected): pred = self.normalizer.normalize(test_input, verbose=False) - assert pred.strip() == expected.strip() + assert pred == expected \ No newline at end of file From b4c1aebc8abe3cd183d97d2611dd310cfc4e247c Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Tue, 18 Aug 2026 12:56:10 +0530 Subject: [PATCH 24/29] Updated Cardinal class based on PR reviews Signed-off-by: surendran-246 --- .../text_normalization/ta/taggers/cardinal.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index ca1555eea..1c199241c 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -144,9 +144,5 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") -<<<<<<< HEAD - self.fst = self.add_tokens(final_graph) -======= final_graph = self.add_tokens(final_graph) self.fst = final_graph.optimize() ->>>>>>> fbfaf09 (Updated Cardinal class based on PR reviews) From e63ae9c7313adf4424507f758b975f5ba26391f9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2026 07:29:43 +0000 Subject: [PATCH 25/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../text_normalization/ta/graph_utils.py | 2 +- .../text_normalization/ta/taggers/cardinal.py | 3 ++- .../text_normalization/ta/taggers/word.py | 2 +- .../text_normalization/ta/verbalizers/word.py | 14 +++++++------- tests/nemo_text_processing/ta/test_cardinal.py | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 51cb213f5..089d892f1 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -142,4 +142,4 @@ def delete_tokens(self, fst) -> 'pynini.FstLike': + delete_space + pynutil.delete("}") ) - return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) \ No newline at end of file + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 1c199241c..b25ba48f6 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -22,11 +22,12 @@ ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path + class CardinalFst(GraphFst): """ Finite state transducer for classifying cardinals e.g. 23 -> cardinal { integer: "இருபத்திமூன்று" } - + Args: deterministic: if True will provide a single transduction option, for False multiple transduction are generated (used for audio-based normalization) diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index 82beec331..9772e5a9f 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -20,4 +20,4 @@ class WordFst(GraphFst): def __init__(self): super().__init__(name="word", kind="classify") word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") - self.fst = word.optimize() \ No newline at end of file + self.fst = word.optimize() diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index 1291ad33a..4c911029d 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -13,23 +13,23 @@ # limitations under the License. import pynini from pynini.lib import pynutil - + from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space - - + + class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. e.g. tokens { name: "சின்ன" } -> சின்ன - + Args: deterministic: if True will provide a single transduction option, for False multiple transduction are generated (used for audio-based normalization) """ - + def __init__(self, deterministic: bool = True): super().__init__(name="word", kind="verbalize", deterministic=deterministic) chars = pynini.closure(NEMO_CHAR - " ", 1) char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") - - self.fst = char.optimize() \ No newline at end of file + + self.fst = char.optimize() diff --git a/tests/nemo_text_processing/ta/test_cardinal.py b/tests/nemo_text_processing/ta/test_cardinal.py index e5260ace9..f0944c24c 100644 --- a/tests/nemo_text_processing/ta/test_cardinal.py +++ b/tests/nemo_text_processing/ta/test_cardinal.py @@ -28,4 +28,4 @@ class TestCardinal: @pytest.mark.unit def test_norm(self, test_input, expected): pred = self.normalizer.normalize(test_input, verbose=False) - assert pred == expected \ No newline at end of file + assert pred == expected From 388ae35549d02718f148931dd3f042d689e1eed3 Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 19 Aug 2026 12:12:35 +0530 Subject: [PATCH 26/29] Added docstring for taggers/ word file Signed-off-by: surendran-246 --- .../text_normalization/ta/graph_utils.py | 18 ------------------ .../text_normalization/ta/taggers/cardinal.py | 5 ++--- .../text_normalization/ta/taggers/word.py | 10 +++++++++- .../text_normalization/ta/verbalizers/word.py | 4 +--- .../pynini_export.py | 5 +---- 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 089d892f1..2bd5db9d6 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -44,9 +44,6 @@ insert_space = pynutil.insert(" ") delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") -MIN_NEG_WEIGHT = -0.0001 - - def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): """ Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. @@ -61,21 +58,6 @@ def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): exporter.close() logging.info(f'Created {file_name}') - -def convert_space(fst) -> 'pynini.FstLike': - """ - Converts space to nonbreaking space. - Used only in tagger grammars for transducing token values within quotes, e.g. name: "hello kitty" - This is making transducer significantly slower, so only use when there could be potential spaces within quotes, otherwise leave it. - - Args: - fst: input fst - - Returns output fst where breaking spaces are converted to non breaking spaces - """ - return fst @ pynini.cdrewrite(pynini.cross(NEMO_SPACE, NEMO_NON_BREAKING_SPACE), "", "", NEMO_SIGMA) - - class GraphFst: """ Base class for all grammar fsts. diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index b25ba48f6..125181008 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -22,12 +22,11 @@ ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path - class CardinalFst(GraphFst): """ Finite state transducer for classifying cardinals e.g. 23 -> cardinal { integer: "இருபத்திமூன்று" } - + Args: deterministic: if True will provide a single transduction option, for False multiple transduction are generated (used for audio-based normalization) @@ -146,4 +145,4 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") final_graph = self.add_tokens(final_graph) - self.fst = final_graph.optimize() + self.fst = final_graph.optimize() \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index 9772e5a9f..4539f4d11 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -15,8 +15,16 @@ from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_NOT_SPACE, GraphFst - class WordFst(GraphFst): + """ + Finite state transducer for classifying Tamil words. + e.g. சோனா -> tokens { name: "சோனா" } + + Args: + deterministic: if True will provide a single transduction option, + for False multiple transductions are generated (used for audio-based normalization) + + """ def __init__(self): super().__init__(name="word", kind="classify") word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index 4c911029d..1f6566c7a 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -13,10 +13,8 @@ # limitations under the License. import pynini from pynini.lib import pynutil - from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space - class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. @@ -32,4 +30,4 @@ def __init__(self, deterministic: bool = True): chars = pynini.closure(NEMO_CHAR - " ", 1) char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") - self.fst = char.optimize() + self.fst = char.optimize() \ No newline at end of file diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index 0f45c4575..4eab1aa02 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -228,10 +228,7 @@ def parse_args(): elif args.language == 'ta': from nemo_text_processing.text_normalization.ta.taggers.tokenize_and_classify import ( ClassifyFst as TNClassifyFst, - ) - from nemo_text_processing.text_normalization.ta.verbalizers.post_processing import ( - PostProcessingFst as TNPostProcessingFst, - ) + ) from nemo_text_processing.text_normalization.ta.verbalizers.verbalize import VerbalizeFst as TNVerbalizeFst elif args.language == 'hu': from nemo_text_processing.text_normalization.hu.taggers.tokenize_and_classify import ( From 0f657e6c5289c4cdc811a970c8357c4ac432becd Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 19 Aug 2026 12:52:33 +0530 Subject: [PATCH 27/29] Added docstring file in taggers Signed-off-by: surendran-246 --- nemo_text_processing/text_normalization/ta/graph_utils.py | 2 +- nemo_text_processing/text_normalization/ta/taggers/word.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 2bd5db9d6..8ec0b3022 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -124,4 +124,4 @@ def delete_tokens(self, fst) -> 'pynini.FstLike': + delete_space + pynutil.delete("}") ) - return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) \ No newline at end of file diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index 4539f4d11..9e3fdb52d 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -28,4 +28,4 @@ class WordFst(GraphFst): def __init__(self): super().__init__(name="word", kind="classify") word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") - self.fst = word.optimize() + self.fst = word.optimize() \ No newline at end of file From 316e82e8487dac483de186dfd01144ff5234c0cb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 07:23:20 +0000 Subject: [PATCH 28/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- nemo_text_processing/text_normalization/ta/graph_utils.py | 4 +++- .../text_normalization/ta/taggers/cardinal.py | 5 +++-- nemo_text_processing/text_normalization/ta/taggers/word.py | 4 +++- .../text_normalization/ta/verbalizers/word.py | 3 ++- tools/text_processing_deployment/pynini_export.py | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/nemo_text_processing/text_normalization/ta/graph_utils.py b/nemo_text_processing/text_normalization/ta/graph_utils.py index 8ec0b3022..2598f4415 100644 --- a/nemo_text_processing/text_normalization/ta/graph_utils.py +++ b/nemo_text_processing/text_normalization/ta/graph_utils.py @@ -44,6 +44,7 @@ insert_space = pynutil.insert(" ") delete_extra_space = pynini.cross(pynini.closure(NEMO_WHITE_SPACE, 1), " ") + def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): """ Exports graph as OpenFst finite state archive (FAR) file with given file name and rule name. @@ -58,6 +59,7 @@ def generator_main(file_name: str, graphs: Dict[str, 'pynini.FstLike']): exporter.close() logging.info(f'Created {file_name}') + class GraphFst: """ Base class for all grammar fsts. @@ -124,4 +126,4 @@ def delete_tokens(self, fst) -> 'pynini.FstLike': + delete_space + pynutil.delete("}") ) - return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) \ No newline at end of file + return res @ pynini.cdrewrite(pynini.cross(u"\u00a0", " "), "", "", NEMO_SIGMA) diff --git a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py index 125181008..b25ba48f6 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/cardinal.py +++ b/nemo_text_processing/text_normalization/ta/taggers/cardinal.py @@ -22,11 +22,12 @@ ) from nemo_text_processing.text_normalization.ta.utils import get_abs_path + class CardinalFst(GraphFst): """ Finite state transducer for classifying cardinals e.g. 23 -> cardinal { integer: "இருபத்திமூன்று" } - + Args: deterministic: if True will provide a single transduction option, for False multiple transduction are generated (used for audio-based normalization) @@ -145,4 +146,4 @@ def band(base, exact_word, tail_word, n, tails): optional_minus_graph = pynini.closure(pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0, 1) final_graph = optional_minus_graph + pynutil.insert("integer: \"") + self.final_graph + pynutil.insert("\"") final_graph = self.add_tokens(final_graph) - self.fst = final_graph.optimize() \ No newline at end of file + self.fst = final_graph.optimize() diff --git a/nemo_text_processing/text_normalization/ta/taggers/word.py b/nemo_text_processing/text_normalization/ta/taggers/word.py index 9e3fdb52d..c36141a92 100644 --- a/nemo_text_processing/text_normalization/ta/taggers/word.py +++ b/nemo_text_processing/text_normalization/ta/taggers/word.py @@ -15,6 +15,7 @@ from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_NOT_SPACE, GraphFst + class WordFst(GraphFst): """ Finite state transducer for classifying Tamil words. @@ -25,7 +26,8 @@ class WordFst(GraphFst): for False multiple transductions are generated (used for audio-based normalization) """ + def __init__(self): super().__init__(name="word", kind="classify") word = pynutil.insert("name: \"") + pynini.closure(NEMO_NOT_SPACE, 1) + pynutil.insert("\"") - self.fst = word.optimize() \ No newline at end of file + self.fst = word.optimize() diff --git a/nemo_text_processing/text_normalization/ta/verbalizers/word.py b/nemo_text_processing/text_normalization/ta/verbalizers/word.py index 1f6566c7a..054edbdd9 100644 --- a/nemo_text_processing/text_normalization/ta/verbalizers/word.py +++ b/nemo_text_processing/text_normalization/ta/verbalizers/word.py @@ -15,6 +15,7 @@ from pynini.lib import pynutil from nemo_text_processing.text_normalization.ta.graph_utils import NEMO_CHAR, NEMO_SIGMA, GraphFst, delete_space + class WordFst(GraphFst): """ Finite state transducer for verbalizing Tamil words. @@ -30,4 +31,4 @@ def __init__(self, deterministic: bool = True): chars = pynini.closure(NEMO_CHAR - " ", 1) char = pynutil.delete("name:") + delete_space + pynutil.delete("\"") + chars + pynutil.delete("\"") - self.fst = char.optimize() \ No newline at end of file + self.fst = char.optimize() diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index 4eab1aa02..be5742d9c 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -228,7 +228,7 @@ def parse_args(): elif args.language == 'ta': from nemo_text_processing.text_normalization.ta.taggers.tokenize_and_classify import ( ClassifyFst as TNClassifyFst, - ) + ) from nemo_text_processing.text_normalization.ta.verbalizers.verbalize import VerbalizeFst as TNVerbalizeFst elif args.language == 'hu': from nemo_text_processing.text_normalization.hu.taggers.tokenize_and_classify import ( From f64f094ea5897125a36826bb43a7771a64e6a82c Mon Sep 17 00:00:00 2001 From: surendran-246 Date: Wed, 26 Aug 2026 09:55:19 +0530 Subject: [PATCH 29/29] Updated Jenkins file Signed-off-by: surendran-246 --- Jenkinsfile | 20 +++--------------- .../pynini_export.py | 2 +- .../classify/tokenize_and_classify.far | Bin 0 -> 761019 bytes ..._tn_True_deterministic_cased__tokenize.far | Bin 0 -> 761019 bytes .../verbalize/verbalize.far | Bin 0 -> 11016 bytes 5 files changed, 4 insertions(+), 18 deletions(-) create mode 100644 tools/text_processing_deployment/ta_tn_grammars_cased/classify/tokenize_and_classify.far create mode 100644 tools/text_processing_deployment/ta_tn_grammars_cased/ta_tn_True_deterministic_cased__tokenize.far create mode 100644 tools/text_processing_deployment/ta_tn_grammars_cased/verbalize/verbalize.far diff --git a/Jenkinsfile b/Jenkinsfile index 825f78044..d2a1a8de0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -114,23 +114,9 @@ pipeline { } } - stage('L0: Create TA TN Grammars') { - when { - anyOf { - branch 'main' - branch 'staging/**' - branch 'staging_*' - changeRequest target: 'main' - } - } - failFast true - parallel { - stage('L0: Ta TN grammars') { - steps { - sh 'CUDA_VISIBLE_DEVICES="" python nemo_text_processing/text_normalization/normalize.py --lang=ta --text="௧" --cache_dir ${TA_TN_CACHE}' - } - } - + stage('L0: TA TN grammars') { + steps { + sh 'CUDA_VISIBLE_DEVICES="" python nemo_text_processing/text_normalization/normalize.py --lang=ta --text="௧" --cache_dir ${TA_TN_CACHE}' } } stage('L0: Create DE/ES TN/ITN Grammars') { diff --git a/tools/text_processing_deployment/pynini_export.py b/tools/text_processing_deployment/pynini_export.py index be5742d9c..7c100f80a 100644 --- a/tools/text_processing_deployment/pynini_export.py +++ b/tools/text_processing_deployment/pynini_export.py @@ -141,7 +141,7 @@ def parse_args(): if __name__ == '__main__': args = parse_args() - if args.language in ['ru', 'es_en', 'hi_en', 'mr', 'ta'] and args.grammars == 'tn_grammars': + if args.language in ['ru', 'es_en', 'hi_en', 'mr'] and args.grammars == 'tn_grammars': raise ValueError('Only ITN grammars could be deployed in Sparrowhawk for the selected languages.') TNPostProcessingFst = None ITNPostProcessingFst = None diff --git a/tools/text_processing_deployment/ta_tn_grammars_cased/classify/tokenize_and_classify.far b/tools/text_processing_deployment/ta_tn_grammars_cased/classify/tokenize_and_classify.far new file mode 100644 index 0000000000000000000000000000000000000000..a6dedfaaea4ab5e351f95e2cfd61717f68f17a1d GIT binary patch literal 761019 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 z⪻2@DpCa~kU0Lkw zx{}z}bwx4j>i3zXdnRscJBRSe0sfKQ9%y$2+MR)RSD@V;X!iu#rvvRXfp%}8-Ivi) z8{ePNPO6)%>w%0m&}a_^+Czc%aG*UBXrB$V&js3}f%aISJsxPE&uFPVzmU;Vdwwya zrS|+%pnW;ez7l9(4YaQX+Sdc^8-e!CK>JppeLJJ2_WVwueK(_}dAsjrwA9w$543?m z`$3@nFwlM!Xg?0Lp9I=Z1MO#l_VbLE+WHrP_REZx=Iwr!(NbIgI?#R-Xul1#-v!$5 z1MLri_Qyc`Q=t7h(EgIqQd|Euqowoe-!fWi&%X!SKLYKaf%dOJ`*)!IC(!;IX#Wee zt|hu;gU|12+ZV}bsXZ4Bw8b)7TIS+`wnU&U8EDf2ZK*(8I?$F0v}FTrxjJxD$rgQXj=!`Hi5Qnpv?%hmuIvz_I^c18>m{dtLv2+EgeU%3ba=T+G_&s zwSo4!Kzn_ly&=%v7-(+_v^Qt8i<&ljOGZoW`PPh<+VgFJ_Vz$~N1(kk(B2hj?+� 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

bZ@tspseK)z;AC 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 literal 0 HcmV?d00001