இந்த வார பகுதியில் ஒரு வித்தியாசமான சிக்கலைப்பற்றி பேசலாம், முன்னரே எழுதிய பகுதிகளை இங்கு காண்க; அதாவது ஒரு எழுத்துணரியின் வழியாக தயாரிக்கப்பட்ட தமிழ் சொற்றொடரில் சில சமயம் மெய் புள்ளிகள் மறைந்துவிடுகின்றன. இது சற்றி இயந்திர கால சிக்கல் என்றால் அப்போது கல்வெட்டுக்களிலும் நூற்றாண்டின் நாளடைவில் இப்படிப்பட்ட சிக்கல்கள் தோன்றுகின்றன; ஆகவே இது தனிப்பட்ட ஒரு சிக்கல் இல்லை என்பதும் புலப்படுகின்றது. இந்த வலைப்பதிவில் உள்ள அல்கோரிதத்தை இங்கு ஓப்பன் தமிழ் நிரலாக காணலாம்.
1. அறிமுகம்
எனக்கு இந்த சிக்கல் இருப்பதன் காரணம், 1910-இல் ஆர்டன் பாதரியார் இயற்றிய “A progressive grammar of common Tamil,” என்ற நூலின் மறுபதிப்பு பிரதியில் சில/பல சொற்கள் விட்டுப்போயிருந்தன. மறுபதிப்பு செய்யும் நிறுவனமோ, கலிபோர்னியா லாசு ஏஞ்சலஸ் பல்கலைக்கழகத்தில் உள்ள பிரதியினில் இருந்து எப்படியோ (கூகிள் புத்தகங்கள் வழியாகவா?) ஒரு புத்தகத்தின் மின்வடிவத்தை சரிபார்க்காமல் அப்படியே அச்சு செய்து அமேசான் சந்தையில் விற்று அதுவும் என் கைக்கு கிடைத்தது. பல இடங்களில் மெய் புள்ளிகளின் மறைவு – சொற்பிழைப்போல் பாவிக்கும் இந்த பிழைகள் இந்திர வழி செயல்திருத்தத்தால் நுழைக்கப்பட்டவை. நுழககபபடடவை!
மெய் புள்ளிகளின்றி செம்புலப்பொயல்நீரார் கூற்றி சங்க இலக்கியத்தில் இருந்து இப்படியே தோன்றும்,
யாயும ஞாயும யாராகியரோ
எநதையும நுநதையும எமமுறைக கேளிர
…
இதனை எப்படி நாம் சீர் செய்வது? இதுதான் நமது இன்றைய சிக்கல்.
2. அல்கோரிதம்
உள்ளீடு
- சொல் என்பதை எழுத்துச் சரமாக தறப்படுகிறது. இதனை சொ என்ற மாறியில் குறிக்கின்றோம்.
வெளியீடுகள்
- மறைந்த மெய்கள் இருந்தால் அவற்றை மற்றும் திருத்தி புதிய சொல் வெளியீடு செய்வதற்கு.
அல்கோரிதம் முன்-நிபந்தனைகள்
- உள்ளீட்டு சரம் என்பதில் வேறு எந்த சொற்பிழைகளும் இல்லை
- சரம் என்பதின் இடம் ‘இ‘ என்பதில், சரம் எழுத்து சொ[இ] என்ற நிரலாக்கல் குறியீட்டில் சொல்கின்றோம்.
- சரம் எழுத்து சொ[இ], தமிழ் எழுத்தாக இல்லாவிட்டால் அதனை நாம் பொருட்படுத்துவதில்லை
- சரம் எழுத்து சொ[இ], உயிர், மெய், உயிர்மெய் (அகர வரிசை தவிர்த்து), ஆய்த எழுத்து என்றாலும் அவற்றில் எவ்வித செயல்பாடுகளையும் செய்யப்போவதில்லை
- ஆகவே, சரம் எழுத்து சொ[இ] என்பது உயிர்மெய் எழுத்தாக அதுவும் அகரவரிசையில் {க, ச, ட, த, ப, ர, .. } இருந்தால் மட்டும் இதனை செயல்படுத்துகின்றோம்.
அல்கோரிதம் செயல்பாடு
- மேல் சொன்னபடி, நாம் கண்டெடுக்க வேண்டியது உள்ளீட்டு சரத்தில் அகரவரிசை உயிர்மெய்களில் சரியான உயிர்மெய் எழுத்து வருகிறதா அல்லது மெய் புள்ளி மறைந்து வருகிறதா என்பது மட்டுமே!
- இதனை சறியாக செய்தால் அடுத்த கட்டமாக பிழைஉள்ள இடங்களில் புள்ளிகளை சேற்றுக்கொள்ளலாம்
- மேல் உள்ள 1-2 படிகளை அனைத்து சொல்லின் அகரவரிசை உயிமெய்களிலும் சயல்படுத்தினால் நமது தீர்வு கிடைக்கின்றது.
இதன் மேலோட்டமான ஒரு முதற்கண் தீற்வை பார்க்கலாம் (இதனை மேலும் சீர்மை செய்ய வேண்டும்),
அல்கோரிதம் – இதற்கு ஒத்தாசை செய்ய மேலும் கூடிய அல்கோரித செயல்முறைகளான “அகரவரிசை_மெய்”, “புள்ளிகள்_தேவையா” மற்றும் “புள்ளிகள்_சேர்” என்றவற்றையும் நாம் சேரக்க்வேண்டும்.
நிரல்பாகம் மறைந்த_மெய்_புள்ளியிடல்( சொல் ) திருத்தம்_சொல் = "" @(சொல் இல் எழுத்து) ஒவ்வொன்றாக விடை = 0 @( அகரவரிசை_உயிர்மெய்( எழுத்து ) ) ஆனால் விடை = புள்ளிகள்_தேவையா( சொல், எழுத்து ) முடி @( விடை ) ஆனால் திருத்தம்_சொல் += புள்ளிகள்_சேர்( எழுத்து ) இல்லை திருத்தம்_சொல் += எழுத்து முடி முடி பின்கொடு திருத்தம்_சொல் முடி நிரல்பாகம் அகரவரிசை_உயிர்மெய்( எழுத்து ) அகரவரிசை_உயிர்மெய்கள் = 'கசடதபறயரலவழளஞஙனநமண' பின்கொடு அகரவரிசை_உயிர்மெய்கள்.இடம்(எழுத்து) != -1 முடி நிரல்பாகம் புள்ளிகள்_சேர் ( எழுத்து ) அகரவரிசை_உயிர்மெய்கள் = 'கசடதபறயரலவழளஞஙனநமண' அகரவரிசைக்குள்ள_மெய் = ['க்','ச்','ட்','த்','ப்','ற்', 'ய்', 'ர்','ல்','வ்','ழ்','ள்', 'ஞ்', 'ங்', 'ன்','ந்','ம்','ண்'] இடம் = அகரவரிசை_உயிர்மெய்கள்.இடம்( எழுத்து ) பின்க்கொடு அகரவரிசைக்குள்ள_மெய்[ இடம் ] முடி
பொதுவாக நம்மால் புள்ளிகள்_தேவையா என்ற செயல்பாட்டை சரிவர முழு விவரங்களுடன் எழுதமுடயாது. இது கணினிவழி உரைபகுப்பாய்வுக்கு ஒரு தனி கேடு. அதனால் நாம் புள்ளியியல் வழி செயல்படுவது சிறப்பானது/சராசரியாக சரிவர விடையளிக்கக்கூடிய செயல்முறை.
3. மாற்று அல்கோரிதம்
மேல் சொன்னபடி உள்ள கட்டமைப்பில் புள்ளிகள் தேவையா என்பதன் ஓட்ட நேரம் (runtime), கணிமை சிக்கலளவு (computational complexity) பற்றி பார்க்கலாம்.
உதாரணமாக, “கண்னன்” என்று எடுத்துக்கொண்டால் அது அச்சாகுமபொழுது “கணனன” என்று அச்சாகிறது என்றும் கொள்ளலாம். நமது அல்கோரிதத்தின்படி இதில் நான்று இடங்களில், அதாவது அத்துனை எழுத்துக்களுமே அகரவரிசை உயிமெயகளாக அமைகின்றன. இவற்றில் எந்த ஒது எழுத்தும் உயிர்மெய்யாக இருக்கலாம் (அச்சிட்டபடியே), அல்லது மாறியும் புள்ளி மறைந்த மெய்யாகவும் இருக்கலாம்.
அதாவது, “கணனன” என்ற சொல்லை மொத்தம் உள்ள வழிகளாவது இவற்றின் பெருக்கல்:
க என்ற எழுத்தில் இரண்டு வழிகள்
ண என்ற எழுத்தில் இரண்டு வழிகள்
ன என்ற எழுத்தில் இரண்டு வழிகள்
ன என்ற எழுத்தில் இரண்டு வழிகள்
மொத்தம் 2 x 2 x 2 x 2 = 24 = 16 வழிகள் உள்ளன.
இதனை பொதுப்படுத்தி சொன்னால்,
- நீ என்ற எண் நீளம் உள்ள சொல்லில் (அதாவது, நீ = |சொல்|) என்ன நடக்கின்றது என்றால்,
- நீ1 என்ற எண் சொல்லின் உள்ள அகரவரிசை உயிர்மெய்களை குறிக்கும் என்றால்,
- நீ1 ⩽ நீ,
- மொத்தம் நாம் பரிசோதிக்க வேண்டிய வழிகள், 2நீ1
இது விரைவில் பொறிய அளவு வளரும் ஒரு தொகை, இதனை exponentially fast, அதிவேகமாக வளரும் கணிமை என்றும் சொல்லாம். இதற்கு என்ன செய்ய வேண்டும் என்றால் இதனை எளிதாக வழிகள் தோன்றும் படி மட்டும் விடைகள் தேடினால் நமது செயல்பாடு விரைவில் முடியவே முடியாது – இதற்காக branch and bound என்ற செயல்முறைகளை பயன்படுத்தவேண்டும்.
#இந்த நிரல்பாகம், 2நீ1 என்ற ஓட்ட நேரத்தில் இயங்கும் நிரல்பாகம் புள்ளிகள்_தேவையா_உதவியாளர்( முதல்_ஒட்டு, சந்தித்காதவை ) @( நீளம்( சந்தித்காதவை ) == 0 ) பின்கொடு [முதல்_ஒட்டு] முடி விடைகள் = [] எழுத்து = சந்தித்காதவை[0] @( அகரவரிசை_உயிர்மெய்( எழுத்து ) ) ஆனால் #உள்ளபடியே இந்த இடத்தில் மெய் இல்லை என்றவழியில் யுகிக்க விடைகள்1 = புள்ளிகள்_தேவையா_உதவியாளர்(முதல்_ஒட்டு + எழுத்து, சந்தித்காதவை[1:]) விடைகள்.நீட்டிக்க( விடைகள்1 ) #உள்ளபடியே இந்த இடத்தில் மெய் வந்தால் எப்படி இருக்கும் என்ற்வழியில் யுகிக்க மெய்எழுத்து = புள்ளிகள்_சேர்( எழுத்து ) விடைகள்2 = புள்ளிகள்_தேவையா_உதவியாளர்(முதல்_ஒட்டு + மெய்எழுத்து, சந்தித்காதவை[1:]) விடைகள்.நீட்டிக்க( விடைகள்2 ) இல்லை விடைகள்3 = புள்ளிகள்_தேவையா_உதவியாளர்(முதல்_ஒட்டு + எழுத்து, சந்தித்காதவை[1:]) விடைகள்.நீட்டிக்க( விடைகள்3 ) முடி பின்கொடு விடைகள் முடி நிரல்பாகம் மறைந்த_மெய்_புள்ளியிடல்(சொல்) #யுகிப்பு சார்பு என்பது n-gram புள்ளியியல் கொண்டு #சொல்லின் புள்ளிகள் சோர்க்கப்பட்ட மாற்றங்களை மதிப்பிடும். மாற்று_சொற்கள் = புள்ளிகள்_தேவையா_உதவியாளர்( '', list(சொல்) ) மதிப்பீடுகள் = யுகிப்பு_சார்பு( மாற்று_சொற்கள் ) இடம் = அதிக_மதிப்பெண்_இடம்( மதிப்பீடுகள் ) சரியான_மாற்று_சொல் = மாற்று_சொற்கள்[ இடம் ] பின்கொடு சரியான_மாற்று_சொல் முடி
மேல் சொல்லப்பட்டபடி கணினி அல்கோரிதப்படுத்திப்பார்த்தால் ‘கணனன’ என்ற சொல்லிற்கு, 16 மாற்றுகள் கிடைக்கும். அவையாவன,
['கணனன',
'கணனன்',
'கணன்ன',
'கணன்ன்',
'கண்னன',
'கண்னன்',
'கண்ன்ன',
'கண்ன்ன்',
'க்ணனன',
'க்ணனன்',
'க்ணன்ன',
'க்ணன்ன்',
'க்ண்னன',
'க்ண்னன்',
'க்ண்ன்ன',
'க்ண்ன்ன்']
இந்த விடையின் மாற்று சொற்களை unigram அல்லது bigram யுகிப்பு சார்புகளின்படி மதிப்பிட்டால் கீழ்கண்டவாறு கிடைக்கின்றது,
[(‘க்ண்ன்ன்‘, 28.0),
(‘க்ணன்ன்’, 24.83912971793407),
(‘க்ண்னன்’, 24.39197168659185),
(‘க்ண்ன்ன’, 24.0),
(‘கண்ன்ன்’, 23.60384297446045),
(‘க்ணனன்’, 21.231101404525926),
(‘க்ணன்ன’, 20.83912971793407),
(‘கணன்ன்’, 20.44297269239452),
(‘க்ண்னன’, 20.39197168659185),
(‘கண்னன்‘, 19.9958146610523),
(‘கண்ன்ன’, 19.60384297446045),
(‘க்ணனன’, 17.231101404525926),
(‘கணனன்’, 16.834944378986375),
(‘கணன்ன’, 16.44297269239452),
(‘கண்னன’, 15.995814661052302),
(‘கணனன’, 12.834944378986375)]
(‘க்ண்ன்ன்’, -11.553147747485053)]
இந்த சமயம் நமக்கு சரியான விடைகிடைக்கவில்லை; இதனுடன் அகராதிபெயர்கள் அல்லது classification செயற்கைப்பின்னல்களை பயன்படுத்திப்பார்க்கலாம் என்றும் தோன்றுகிறது.
இந்த அல்கோரிதத்தை ஓப்பன்-தமிழ் பைத்தான் நிரலாக எழுதினால் இப்படி:
# -*- coding: utf-8 -*- | |
# (C) 2020, முத்து அண்ணாமலை. | |
# இந்த நிரல் துண்டு MIT உரிமத்தில் வெளியிடப்பட்டது | |
import tamil | |
from pprint import pprint | |
import operator | |
from solthiruthi.scoring import bigram_scores, unigram_score | |
chol = tamil.utf8.get_letters("கணனன") | |
def mean(x): | |
return sum(x)/float(len(x)) | |
def pulligal_helper(prefix,letters): | |
if len(letters) == 0: return [prefix] | |
letter = letters[0] | |
result = [] | |
if letter in tamil.utf8.agaram_letters: | |
result1 = pulligal_helper( prefix + letter, letters[1:]) | |
mei_letter = letter + tamil.utf8.pulli_symbols[0] | |
result2 = pulligal_helper( prefix + mei_letter, letters[1:]) | |
result.extend(result1) | |
result.extend(result2) | |
else: | |
result1 = pulligal_helper( prefix + letter, letters[1:]) | |
result.extend(result1) | |
return result | |
def pulligal_branch_bound(prefix,letters,அகராதி): | |
""" we restrict options if its not a prefix in dictionary """ | |
if len(letters) == 0: return [prefix] | |
letter = letters[0] | |
result = [] | |
prefer = அகராதி.starts_with(prefix) | |
if letter in tamil.utf8.agaram_letters: | |
alternate2 = prefix + mei_letter | |
if அகராதி.starts_with(alternate2) or prefer: | |
mei_letter = letter + tamil.utf8.pulli_symbols[0] | |
result2 = pulligal_branch_bound( alternate2, letters[1:]) | |
result.extend(result2) | |
alternate1 = prefix + letter | |
if அகராதி.starts_with(alternate1) or prefer: | |
result1 = pulligal_branch_bound( alternate1, letters[1:]) | |
result.extend(result1) | |
return result | |
#sort in descending order | |
result_tpl = [("".join(sol),(-1.0*unigram_score(sol))) for sol in pulligal_helper("",chol)] | |
result_tpl = sorted(result_tpl,key=operator.itemgetter(1),reverse=True) | |
pprint(result_tpl) | |
""" | |
['கணனன', | |
'கணனன்', | |
'கணன்ன', | |
'கணன்ன்', | |
'கண்னன', | |
'கண்னன்', | |
'கண்ன்ன', | |
'கண்ன்ன்', | |
'க்ணனன', | |
'க்ணனன்', | |
'க்ணன்ன', | |
'க்ணன்ன்', | |
'க்ண்னன', | |
'க்ண்னன்', | |
'க்ண்ன்ன', | |
'க்ண்ன்ன்'] | |
#bigram score | |
[('கணனன', -12.834944378986375), | |
('கணனன்', -16.834944378986375), | |
('கணன்ன', -16.44297269239452), | |
('கணன்ன்', -20.44297269239452), | |
('கண்னன', -15.995814661052302), | |
('கண்னன்', -19.9958146610523), | |
('கண்ன்ன', -19.60384297446045), | |
('கண்ன்ன்', -23.60384297446045), | |
('க்ணனன', -17.231101404525926), | |
('க்ணனன்', -21.231101404525926), | |
('க்ணன்ன', -20.83912971793407), | |
('க்ணன்ன்', -24.83912971793407), | |
('க்ண்னன', -20.39197168659185), | |
('க்ண்னன்', -24.39197168659185), | |
('க்ண்ன்ன', -24.0), | |
('க்ண்ன்ன்', -28.0)] | |
# unigram score | |
[('கணனன', -7.5531477474850535), | |
('கணனன்', -8.553147747485053), | |
('கணன்ன', -8.553147747485053), | |
('கணன்ன்', -9.553147747485053), | |
('கண்னன', -8.553147747485053), | |
('கண்னன்', -9.553147747485053), | |
('கண்ன்ன', -9.553147747485053), | |
('கண்ன்ன்', -10.553147747485053), | |
('க்ணனன', -8.553147747485053), | |
('க்ணனன்', -9.553147747485053), | |
('க்ணன்ன', -9.553147747485053), | |
('க்ணன்ன்', -10.553147747485053), | |
('க்ண்னன', -9.553147747485053), | |
('க்ண்னன்', -10.553147747485053), | |
('க்ண்ன்ன', -10.553147747485053), | |
('க்ண்ன்ன்', -11.553147747485053)] | |
""" |
மேலும், செம்புலப்பெயல்நீரார் கூற்றை மெய்கள் சேர்த்தால், இப்படி வருகின்றது. இதில் 7-இல் ஆறு சொற்கள் சரியாவருகிறது.
- [(‘யாயும்‘, 20.0), (‘யாயும’, 16.0)]
- [(‘ஞாயும்‘, 20.0), (‘ஞாயும’, 16.0)]
- [(‘யாராகிய்ரோ‘, 36.0), (‘யாராகியரோ‘, 31.94703511524359)]
- [(‘எந்தையும்‘, 32.0),(‘எநதையும்’, 28.83912971793407),(‘எந்தையும’, 28.0),(‘எநதையும’, 24.83912971793407)]
- [(‘நுந்தையும்‘, 36.0),
(‘நுநதையும்’, 32.83912971793407),
(‘நுந்தையும’, 32.0),
(‘நுநதையும’, 28.83912971793407)] - [(‘எம்முறைக்‘, 32.181004231607204),
(‘எமமுறைக்’, 28.543012694821613),
(‘எம்முறைக’, 28.181004231607204),
(‘எமமுறைக’, 24.543012694821613)] - [(‘கேளிர்‘, 20.0), (‘கேளிர’, 16.0)]
மேலும் தொடர்புக்கு உங்கள் விவரங்களை இங்கு சேர்க்கவும்.