diff --git a/inflection/resources/org/unicode/inflection/exemplar/suffix_sr.csv b/inflection/resources/org/unicode/inflection/exemplar/suffix_sr.csv new file mode 100644 index 000000000..83c7dbc2c --- /dev/null +++ b/inflection/resources/org/unicode/inflection/exemplar/suffix_sr.csv @@ -0,0 +1,19 @@ +ак,=,изузетак +њак,=,надвожњак +ац,=,дворац +ник,=,камен +ач,=,брод +ар,=,булевар +бус,=,аутобус +ан,=,Драган +ош,=,Милош +иша,=,Љубиша +а,=,Јелена +ица,=,Љубица +ија,=,Србија +ка,=,мачка +о,=,брдо +бло,=,дебло +е,=,море +сеље,=,насеље +ме,=,име diff --git a/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.cpp b/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.cpp index 11a271bd2..f376bf302 100644 --- a/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.cpp +++ b/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.cpp @@ -22,8 +22,12 @@ #include #include #include +#include #include +static constexpr int32_t MAX_SUFFIX_LEN = 7; +static constexpr int32_t MIN_STEM_LEN = 2; + namespace inflection::grammar::synthesis { SrGrammarSynthesizer_SrDisplayFunction::SrGrammarSynthesizer_SrDisplayFunction(const ::inflection::dialog::SemanticFeatureModel& model) @@ -39,6 +43,7 @@ SrGrammarSynthesizer_SrDisplayFunction::SrGrammarSynthesizer_SrDisplayFunction(c {GrammemeConstants::NUMBER_SINGULAR, GrammemeConstants::NUMBER_PLURAL}, {GrammemeConstants::GENDER_MASCULINE, GrammemeConstants::GENDER_FEMININE, GrammemeConstants::GENDER_NEUTER} }, {}, true) + , suffixToExemplar(inflection::util::ResourceLocator::getRootForLocale(inflection::util::LocaleUtils::SERBIAN()) + u"/exemplar/suffix_" + inflection::util::LocaleUtils::SERBIAN().toString() + u".bist") { } @@ -159,8 +164,37 @@ ::inflection::dialog::DisplayValue *SrGrammarSynthesizer_SrDisplayFunction::getD if (dictionary.isKnownWord(displayString)) { displayString = inflectFromDictionary(constraints, displayString); } else if (enableInflectionGuess) { - // Let's use rule based inflection for nouns. Assume lemma is singular, nominative. - displayString = inflectWithRule(constraints, displayString); + // Primary guess: Rule based inflection for nouns. + ::std::u16string ruleResult = inflectWithRule(constraints, displayString); + if (ruleResult != displayString) { + displayString = ruleResult; + } else { + // Secondary guess: Longest suffix exemplar guessing. + auto countString = GrammarSynthesizerUtil::getFeatureValue(constraints, numberFeature); + auto caseString = GrammarSynthesizerUtil::getFeatureValue(constraints, caseFeature); + auto genderString = GrammarSynthesizerUtil::getFeatureValue(constraints, genderFeature); + std::vector<::std::u16string> constraintsVec; + if (!countString.empty()) constraintsVec.push_back(countString); + if (!caseString.empty() && caseString != GrammemeConstants::CASE_NOMINATIVE) constraintsVec.push_back(caseString); + if (!genderString.empty()) constraintsVec.push_back(genderString); + + for (int32_t suffixLen = std::min(MAX_SUFFIX_LEN, static_cast(displayString.length() - MIN_STEM_LEN)); suffixLen > 0; --suffixLen) { + std::u16string_view suffix = std::u16string_view(displayString).substr(displayString.length() - suffixLen); + auto exemplarResult = suffixToExemplar.findTarget(suffix); + if (exemplarResult.has_value()) { + const auto& exemplar = *exemplarResult; + int64_t exemplarGrammemes = 0; + dictionary.getCombinedBinaryType(&exemplarGrammemes, exemplar); + if (exemplarGrammemes != 0) { + auto guessedResult = dictionaryInflector.inflectExemplar(displayString, exemplar, exemplarGrammemes, constraintsVec, {}); + if (guessedResult.has_value()) { + displayString = *guessedResult; + break; + } + } + } + } + } } return new ::inflection::dialog::DisplayValue(displayString, constraints); } diff --git a/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.hpp b/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.hpp index c8ae8f9fa..2a4b4de46 100644 --- a/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.hpp +++ b/inflection/src/inflection/grammar/synthesis/SrGrammarSynthesizer_SrDisplayFunction.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -40,4 +41,5 @@ class inflection::grammar::synthesis::SrGrammarSynthesizer_SrDisplayFunction const ::inflection::dictionary::Inflector &inflector; const ::std::unique_ptr<::inflection::tokenizer::Tokenizer> tokenizer; ::inflection::dialog::DictionaryLookupInflector dictionaryInflector; + const ::inflection::grammar::BidirectionalStringMap suffixToExemplar; }; diff --git a/inflection/test/resources/inflection/dialog/inflection/sr.xml b/inflection/test/resources/inflection/dialog/inflection/sr.xml index ed1893364..a8cf7a287 100644 --- a/inflection/test/resources/inflection/dialog/inflection/sr.xml +++ b/inflection/test/resources/inflection/dialog/inflection/sr.xml @@ -14,17 +14,34 @@ СрбијаСрбијо становникстановницима плаваплавe - - - - + + уранакуранка + уранакуранку + пашњакпашњака + клинацклинца + ученикученика + играчиграча + пекарпекара + микробусмикробуса + БојанБојана + РадошРадоша + РадишаРадише + кућицакућице + кућицакућици + географијагеографије + паткапатке + огледалоогледала + стаблостабла + уточиштеуточишта + саопштењесаопштења + презимепрезимену ИталијаИталијом авенијаавенијом авенијаавенијама - кадијакадија + кадијакадијо уметницауметнице - птицаптица + птицаптице СтанаСтано ЗораЗоро БожаБожо