// Генерация слов, фонетически близких к заданному word. // Возвращается список вариантов, включая исходное слово, и список их достоверностей. void LexicalAutomat::ProducePhonInv( const lem::UCString &word, int id_language, lem::MCollect<lem::UCString> &res, lem::MCollect<lem::Real1> &rels, LA_RecognitionTrace *trace ) { MCollect<LA_AA_list*> packs; LA_AA_list *list = new LA_AA_list; list->reserve(16); list->push_back(LA_AA_item(word, Real1(100))); // Теперь мутированные варианты. LA_Pack *pack = AlephAuto(id_language, word, 1, trace); for (Container::size_type j = 0; j < pack->size(); j++) { const Solarix::Lexem &ph_lex = *(pack->get(j)); if (res.find(ph_lex) == UNKNOWN) { Real1 r = pack->get(j)->get_Val(); rels.push_back(r); res.push_back(ph_lex); } } return; }
void LemmatizatorStorage_SQLITE::Lemmatize( const lem::UCString &word, lem::MCollect<lem::UCString> &lemmas ) { lemmas.clear(); lem::MemFormatter mem; mem.printf( "SELECT L.lemma" " FROM lexemes_n X, lemmas L" " WHERE X.lexeme='%us' AND L.id=X.id_lemma", to_upper(word).c_str() ); lem::Ptr<LS_ResultSet> rs(cnx->Select(lem::to_utf8(mem.string()))); while( rs->Fetch() ) { lemmas.push_back( rs->GetUCString(0) ); } if( lemmas.empty() ) { lemmas.push_back(word); } return; }
bool LA_PreprocessorRules::Crop( const lem::UCString &word, lem::MCollect<lem::UCString> &results, lem::MCollect<lem::Real1> &rels, LA_RecognitionTrace *trace ) const { bool applied = false; if (!crop_rules.empty()) { // сначала применяем префиксные правила typedef CROP_RULES::const_iterator IT; LA_CropRule::HashType prefix_hash = LA_CropRule::CalcHash(word.c_str(), true, false); std::pair<IT, IT> pp = prefix_crop_rules.equal_range(prefix_hash); lem::UCString result; for (auto it = pp.first; it != pp.second; ++it) { const LA_CropRule *r = it->second; if (r->Apply(word, result)) { applied = true; results.push_back(result); rels.push_back(r->GetRel()); if (trace != nullptr) { trace->CropRuleApplied(word, result, r); } } } // теперь отсекаем аффикс LA_CropRule::HashType affix_hash = LA_CropRule::CalcHash(word.c_str(), false, true); pp = affix_crop_rules.equal_range(affix_hash); for (auto it = pp.first; it != pp.second; ++it) { const LA_CropRule *r = it->second; if (r->Apply(word, result)) { applied = true; results.push_back(result); rels.push_back(r->GetRel()); if (trace != nullptr) { trace->CropRuleApplied(word, result, r); } } } } return applied; }
void LEMM_Compiler::LoadNGram( lem::Iridium::Macro_Parser & txtfile, Dictionary & dict, lem::MCollect<int> & terms, int order ) const { lem::Iridium::BSourceState beg = txtfile.tellp(); while( !txtfile.eof() ) { lem::Iridium::BethToken t = txtfile.read(); if( lem::is_int(t.string()) ) terms.push_back( lem::to_int(t.string()) ); else { txtfile.seekp(t); break; } } if( terms.size() != order+1 ) { dict.GetIO().merr().printf( "%vfDInvalid ngram%vn\n" ); lem::Iridium::Print_Error( beg, txtfile ); throw lem::E_ParserError(); } return; }
void Lemmatizator::Lemmatize( const lem::MCollect<lem::UCString> & words, lem::MCollect<lem::UCString> &lemmas ) { #if defined LEM_THREADS lem::Process::CritSecLocker lock(&cs); #endif if( !model_loaded ) { bin->seekp( model_pos ); model_loaded = true; model_available = bin->read_bool(); if( model_available ) { LoadModel(); } } if( model_available ) { LemmatizeViaModel( words, lemmas ); } else { for( lem::Container::size_type i=0; i<words.size(); ++i ) { lem::UCString lemma; Lemmatize( words[i], lemma ); lemmas.push_back( lemma ); } } return; }
void LexerTextPos::Collect_Right2Left(int count, lem::MCollect<const LexerTextPos*> & inverted_path) const { inverted_path.push_back(this); if (count > 0 && !IsBegin() && previous != nullptr) GetPrev()->Collect_Right2Left(count - 1, inverted_path); return; }
void SynPatternResult::GetExportCoordPairs(lem::MCollect< std::pair<int, int> > & pairs) const { for (auto it = exported_coords.begin(); it != exported_coords.end(); ++it) { pairs.push_back(*it); } return; }
void GeneratorLexer::CollectUsedWords( const LexerTextPos * t, lem::MCollect<int> & indeces ) const { TOKEN2WORD::const_iterator it = token2word.find(t); if( it!=token2word.end() ) indeces.push_back( it->second ); if( !t->IsBegin() && t->GetPrev()!=NULL ) CollectUsedWords( t->GetPrev(), indeces ); return; }
void LexerTextPos::CollectPathToLeft(int count, lem::MCollect<const Word_Form*> & org) const { LEM_CHECKIT_Z(count >= 0); org.push_back(wordform); if (count > 0 && previous != NULL) previous->CollectPathToLeft(count - 1, org); return; }
void LexerTextPos::Collect_Right2Left(const LexerTextPos *left_boundary, lem::MCollect<const LexerTextPos*> & inverted_path) const { LEM_CHECKIT_Z(left_boundary != nullptr); inverted_path.push_back(this); if (this != left_boundary && previous != nullptr) previous->Collect_Right2Left(left_boundary, inverted_path); return; }
void SynPatterns::GetUnresolvedForwardDeclarations( lem::MCollect<lem::UCString> & unresolved_names ) const { typedef std::map< lem::UCString, int >::const_iterator IT; for( IT it=name2id.begin(); it!=name2id.end(); ++it ) { if( id2count.find( it->second )==id2count.end() ) unresolved_names.push_back( it->first ); } return; }
void SyllabContext::GetResultSyllabs(lem::MCollect<lem::UCString> & result_syllabs, bool Normalized) const { for (auto point : points) { if (point->IsLeftBoundary() || point->IsRightBoundary()) continue; result_syllabs.push_back(point->BuildSyllab(Normalized)); } return; }
void SyllabContext::GetResultSyllabs( lem::MCollect<lem::UCString> & result_syllabs, bool Normalized ) const { for( lem::Container::size_type i=0; i<points.size(); ++i ) { const SyllabContextPoint * p = points[i]; if( p->IsLeftBoundary() || p->IsRightBoundary() ) continue; result_syllabs.push_back( p->BuildSyllab(Normalized) ); } return; }
// ************************************************************************************* // Ищем парадигмы, чьи условия подходят для указанной базовой формы, возвращает // список id таких парадигм. // ************************************************************************************* void ParadigmaFinder::Find( int PartOfSpeech, const lem::UCString &entry_name, lem::MCollect<int> &found_ids ) { #if defined LEM_THREADS lem::Process::RWU_ReaderGuard rlock(cs); #endif if( !loaded ) { #if defined LEM_THREADS lem::Process::RWU_WriterGuard wlock(rlock); #endif LoadFromDB(); } if( PartOfSpeech==UNKNOWN || PartOfSpeech==ANY_STATE ) { for( lem::Container::size_type i=0; i<matchers.size(); ++i ) if( matchers[i]->Match(entry_name) ) { found_ids.push_back(ids[i]); } } else { CLASS2DECL::const_iterator it=class2decl.find(PartOfSpeech); if( it!=class2decl.end() ) { for( lem::Container::size_type i=0; i<it->second->size(); ++i ) if( it->second->get(i).second->Match(entry_name) ) { found_ids.push_back( it->second->get(i).first ); } } } return; }
void BasicModel::PullFeatures2( lem::MCollect<lem::CString> & b, const lem::PtrCollect<ModelTokenFeatures> & token_features, int ifocus, int offset1, int offset2 ) const { int iword1 = ifocus + offset1; int iword2 = ifocus + offset2; if( iword1 >= 0 && iword1 < token_features.size() && iword2 >= 0 && iword2 < token_features.size() ) { b.push_back( lem::format_str( "sfx[%d,%d]=%d,%d", offset1, offset2, token_features[iword1]->suffix_id, token_features[iword2]->suffix_id ).c_str() ); // здесь можно вывести и другие свойства слов. // ... TODO } return; }
void BackTraceItem::GetCoordStates( int id_coord, lem::MCollect<int> & states ) const { if( use_export ) { for( lem::Container::size_type i=0; i<export_coords.size(); ++i ) { if( export_coords[i].GetCoord().GetIndex()==id_coord ) states.push_back( export_coords[i].GetState() ); } } else { states = GetWordform()->GetStates( Solarix::GramCoordAdr(id_coord) ); } return; }
void NGramsStorage_SQLITE::SelectInts( const lem::FString &Select, lem::MCollect<int> &list ) { LEM_CHECKIT_Z( !Select.empty() ); sqlite3_stmt *stmt=NULL; int res = sqlite3_prepare_v2( hdb, Select.c_str(), -1, &stmt, NULL ); if( res==SQLITE_OK ) { while( sqlite3_step( stmt ) == SQLITE_ROW ) { int i = sqlite3_column_int(stmt,0); list.push_back(i); } sqlite3_finalize(stmt); } return; }
void SG_DeclensionTable::GenerateForms( const Lexem &entry_name, lem::MCollect<Lexem> & res, lem::PtrCollect<CP_Array> & form_dims, const SynGram &sg, const SG_DeclensionAutomat &dsa ) const { res.reserve(form.size()); for( lem::Container::size_type i=0; i<form.size(); i++ ) { UCString frm( dsa.ProduceForm( entry_name, GetClass(), *form[i], sg ) ); res.push_back( frm); form_dims.push_back( new CP_Array( form[i]->GetDim() ) ); } return; }
void SG_DeclensionTable::GenerateForms( const Lexem &entry_name, lem::MCollect<Lexem> &res, const SynGram &sg, const SG_DeclensionAutomat &dsa ) const { res.reserve(form.size()); for( lem::Container::size_type i=0; i<form.size(); i++ ) { UCString frm( dsa.ProduceForm( entry_name, GetClass(), *form[i], sg ) ); // Без повторов if( std::find( res.begin(), res.end(), frm )==res.end() ) res.push_back( frm ); } return; }
void SynPatternResult::SelectUnique_WithRemoval(lem::MCollect<SynPatternResult*> & results) { lem::MCollect<int> result_hash; lem::PtrCollect<SynPatternResult> unique_result; for (lem::Container::size_type k = 0; k < results.size(); ++k) { SynPatternResult * result_k = results[k]; const int h = result_k->CalcHash(); bool found = false; for (lem::Container::size_type i = 0; i < unique_result.size(); ++i) { if (result_hash[i] == h) { if (SynPatternResult::Equals(result_k, unique_result[i])) { found = true; break; } } } if (!found) { result_hash.push_back(h); unique_result.push_back(result_k); results[k] = nullptr; } } results.clear(); for (lem::Container::size_type i = 0; i < unique_result.size(); ++i) { results.push_back(unique_result[i]); unique_result[i] = nullptr; } return; }
static bool IsHtmlClosed( const lem::UFString &tag ) { if( tags1.empty() ) { const wchar_t* stags[] = { L"br", L"hr", L"link", L"meta", L"img", L"input", NULL }; int i=0; while(stags[i]!=NULL) tags1.push_back( lem::UFString(stags[i++]) ); } for( lem::Container::size_type i=0; i<tags1.size(); ++i ) { const lem::UFString &t = tags1[i]; if( tag.eq_begi(t) && (tag.length()==t.length() || tag[ t.length() ]==L' ' ) ) return true; } return false; }
static bool IsTextDelimiterTag( const UFString &tag ) { if( tags2.empty() ) { const wchar_t* stags[] = { L"p", L"br", L"table", L"td", L"tr", L"th", L"ol", L"ul", L"li", L"dd", L"input", L"frame", L"div", NULL }; int i=0; while(stags[i]!=NULL) tags2.push_back( lem::UFString(stags[i++]) ); } for( lem::Container::size_type i=0; i<tags2.size(); ++i ) { const lem::UFString &t = tags2[i]; if( tag.eq_begi(t) && (tag.length()==t.length() || tag[ t.length() ]==L' ' ) ) return true; } return false; }
void BasicModel::PullFeatures1( lem::MCollect<lem::CString> & b, const lem::PtrCollect<ModelTokenFeatures> & token_features, int ifocus, int offset, bool rich_set, bool emit_Aa_feature ) const { int iword = ifocus + offset; if( iword >= 0 && iword < token_features.size() ) { const ModelTokenFeatures & f = * token_features[iword]; b.push_back( lem::format_str( "sfx[%d]=%d", offset, f.suffix_id ).c_str() ); if( emit_Aa_feature ) b.push_back( lem::format_str( "Aa[%d]=%d", offset, f.Aa ).c_str() ); // здесь можно вывести и другие свойства слова. if( rich_set ) { b.push_back( lem::format_str("pos[%d,N]=%s", offset, f.POS_N.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,A]=%s", offset, f.POS_A.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,V]=%s", offset, f.POS_V.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,IMV]=%s", offset, f.POS_IMV.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,I]=%s", offset, f.POS_I.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,Y]=%s", offset, f.POS_Y.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,VY]=%s", offset, f.POS_VY.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PRN]=%s", offset, f.POS_PRN.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PRN2]=%s", offset, f.POS_PRN2.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,C]=%s", offset, f.POS_C.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,D]=%s", offset, f.POS_D.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,P]=%s", offset, f.POS_P.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PX]=%s", offset, f.POS_PX.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PP]=%s", offset, f.POS_PP.c_str() ).c_str() ); } } return; }
void Lemmatizator::LemmatizeViaModel( const lem::MCollect<lem::UCString> & words, lem::MCollect<lem::UCString> &lemmas ) { // Для каждого слова получим списки альтернативных лемматизаций. lem::Collect< lem::MCollect<lem::UCString> > word2lemmas; word2lemmas.resize( words.size() ); lem::MCollect<int> lemma_scores; lem::MCollect<int> lemma_order; for( lem::Container::size_type i=0; i<words.size(); ++i ) { Lemmatize( words[i], word2lemmas[i] ); for( lem::Container::size_type j=0; j<word2lemmas[i].size(); ++j ) word2lemmas[i][j].to_lower(); lemmas.push_back( word2lemmas[i][0] ); lemma_scores.push_back(0); lemma_order.push_back(1); } const int last_word_index = CastSizeToInt(words.size())-1; const bool use_4grams=true; const bool use_3grams=true; const bool use_2grams=true; for( lem::Container::size_type iword = 0; iword < words.size(); ++iword ) { lem::UCString lemma; int lemma_score = 0; bool lemma_created = false; if( !lemma_created && iword > 2 && use_4grams ) { // ====================== // ИСПОЛЬЗУЕМ ТЕТРАГРАММЫ // ====================== const lem::UCString & word1 = words[iword-3]; const int id_suffix1 = GetTag( word1 ); const lem::UCString & word2 = words[iword-2]; const int id_suffix2 = GetTag( word2 ); const lem::UCString & word3 = words[iword-1]; const int id_suffix3 = GetTag( word3 ); lem::triple<int,int,int> k3( id_suffix1, id_suffix2, id_suffix3 ); std::map< lem::triple<int,int,int>, lem::MCollect<const LEMM_Ngram4*>* >::const_iterator it = tag0_2_ngram4.find( k3 ); if( it!=tag0_2_ngram4.end() ) { const lem::MCollect<const LEMM_Ngram4*> & n4_list = * it->second; std::map<lem::UCString,int> sfx2score; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n4_list.size(); ++j ) { const LEMM_Ngram4 & n4_probe = *n4_list[j]; const int id_suffix4 = n4_probe.tags.fourth; const lem::UCString & suffix4 = GetSuffixById(id_suffix4); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix4); if( it2!=sfx2score.end() ) it2->second += n4_probe.freq; } // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword] < prev_score ) { lemma_scores[iword] = prev_score; lemmas[iword] = prev_lemma; lemma_order[iword] = 4; } } } if( !lemma_created && use_3grams ) { // ====================== // ИСПОЛЬЗУЕМ ТРИГРАММЫ // ====================== // Если текущее слово имеет 1 вариант лемматизации, то можно использовать его для перепроверки предыдущего слова. if( iword>2 && word2lemmas[iword].size() == 1 && word2lemmas[iword - 1].size() == 1 && word2lemmas[iword - 2].size() > 1 && lemma_order[iword-2]<3 ) { // переоцениваем слово в iword-2 const lem::UCString & word1 = words[iword-1]; const int id_suffix1 = GetTag( word1 ); const lem::UCString & word2 = words[iword]; const int id_suffix2 = GetTag( word2 ); std::pair<int,int> k2( id_suffix1, id_suffix2 ); std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag2_2_ngram3.find( k2 ); if( it!=tag2_2_ngram3.end() ) { const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second; std::map<lem::UCString,int> sfx2score; int proj_count = word2lemmas[iword-2].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword-2][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n3_list.size(); ++j ) { const LEMM_Ngram3 & n3_probe = *n3_list[j]; const int id_suffix0 = n3_probe.tags.first; const lem::UCString & suffix0 = GetSuffixById(id_suffix0); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix0); if( it2!=sfx2score.end() ) it2->second += n3_probe.freq; } // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword-2][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword-2] < prev_score ) { lemma_scores[iword-2] = prev_score; lemmas[iword-2] = prev_lemma; lemma_order[iword-2] = 3; } } } else if( iword>1 && word2lemmas[iword].size() == 1 && word2lemmas[iword - 1].size() > 1 && lemma_order[iword-1]<3 ) { // переоцениваем слово в iword-1 const lem::UCString & word0 = words[iword-2]; const int id_suffix0 = GetTag( word0 ); const lem::UCString & word2 = words[iword]; const int id_suffix2 = GetTag( word2 ); std::pair<int,int> k2( id_suffix0, id_suffix2 ); std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag1_2_ngram3.find( k2 ); if( it!=tag1_2_ngram3.end() ) { const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second; std::map<lem::UCString,int> sfx2score; int proj_count = word2lemmas[iword-1].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword-1][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n3_list.size(); ++j ) { const LEMM_Ngram3 & n3_probe = *n3_list[j]; const int id_suffix1 = n3_probe.tags.second; const lem::UCString & suffix1 = GetSuffixById(id_suffix1); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1); if( it2!=sfx2score.end() ) it2->second += n3_probe.freq; } // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword-2][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword-1] < prev_score ) { lemma_scores[iword-1] = prev_score; lemmas[iword-1] = prev_lemma; lemma_order[iword-1] = 3; } } } else if( word2lemmas[iword].size() > 1 ) { std::map<lem::UCString,int> sfx2score; bool needs_resort=false; if( iword>1 ) { // iword-2,iword-1 --> iword const lem::UCString & word1 = words[iword-2]; const int id_suffix1 = GetTag( word1 ); const lem::UCString & word2 = words[iword-1]; const int id_suffix2 = GetTag( word2 ); std::pair<int,int> k2( id_suffix1, id_suffix2 ); std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag0_2_ngram3.find( k2 ); if( it!=tag0_2_ngram3.end() ) { const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second; needs_resort=true; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n3_list.size(); ++j ) { const LEMM_Ngram3 & n3_probe = *n3_list[j]; const int id_suffix3 = n3_probe.tags.third; const lem::UCString & suffix3 = GetSuffixById(id_suffix3); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix3); if( it2!=sfx2score.end() ) it2->second += n3_probe.freq; } } } if( iword>0 && iword<last_word_index ) { // iword-1 --> iword <-- iword+1 const lem::UCString & word0 = words[iword-1]; const int id_suffix0 = GetTag( word0 ); const lem::UCString & word2 = words[iword+1]; const int id_suffix2 = GetTag( word2 ); std::pair<int,int> k2( id_suffix0, id_suffix2 ); std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag1_2_ngram3.find( k2 ); if( it!=tag1_2_ngram3.end() ) { const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second; needs_resort=true; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n3_list.size(); ++j ) { const LEMM_Ngram3 & n3_probe = *n3_list[j]; const int id_suffix1 = n3_probe.tags.second; const lem::UCString & suffix1 = GetSuffixById(id_suffix1); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1); if( it2!=sfx2score.end() ) it2->second += n3_probe.freq; } } } if( iword<last_word_index-1 ) { // iword <-- iword+1,iword+2 const lem::UCString & word1 = words[iword+1]; const int id_suffix1 = GetTag( word1 ); const lem::UCString & word2 = words[iword+2]; const int id_suffix2 = GetTag( word2 ); std::pair<int,int> k2( id_suffix1, id_suffix2 ); std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag2_2_ngram3.find( k2 ); if( it!=tag2_2_ngram3.end() ) { const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second; needs_resort=true; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n3_list.size(); ++j ) { const LEMM_Ngram3 & n3_probe = *n3_list[j]; const int id_suffix0 = n3_probe.tags.first; const lem::UCString & suffix0 = GetSuffixById(id_suffix0); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix0); if( it2!=sfx2score.end() ) it2->second += n3_probe.freq; } } } if( needs_resort ) { // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword] < prev_score ) { lemma_scores[iword] = prev_score; lemmas[iword] = prev_lemma; lemma_order[iword] = 3; } } } } // конец триграм if( !lemma_created && use_2grams ) { // ====================== // ИСПОЛЬЗУЕМ ДИГРАММЫ // ====================== // Если текущее слово имеет 1 вариант лемматизации, то можно использовать его для перепроверки предыдущего слова. if( iword>0 && word2lemmas[iword].size()==1 && word2lemmas[iword-1].size()>1 && lemma_order[iword-1]<2 ) { // ...... [лемматизируемое_слово] [опорное_слово] ....... const lem::UCString & word2 = words[iword]; // опорное слово const int id_suffix2 = GetTag( word2 ); std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag1_2_ngram2.find( id_suffix2 ); if( it!=tag1_2_ngram2.end() ) { const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second; std::map<lem::UCString,int> sfx2score; int proj_count = word2lemmas[iword - 1].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword-1][iproj]; // вариант лемматизации лемматизируемого слова lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n2_list.size(); ++j ) { const LEMM_Ngram2 & n2_probe = *n2_list[j]; const int id_suffix1 = n2_probe.tags.first; const lem::UCString & suffix1 = GetSuffixById(id_suffix1); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1); if( it2!=sfx2score.end() ) it2->second += n2_probe.freq; } // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword - 1].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword - 1][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если предыдущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword-1] < prev_score ) { lemma_scores[iword-1] = prev_score; lemmas[iword-1] = prev_lemma; lemma_order[iword-1] = 2; } } } else if( word2lemmas[iword].size() > 1 && lemma_order[iword]<2 ) { bool needs_resort=false; std::map<lem::UCString,int> sfx2score; if( iword>0 ) { // ...... [опорное_слово] [лемматизируемое_слово] ....... const lem::UCString & word1 = words[iword-1]; const int id_suffix1 = GetTag( word1 ); std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag0_2_ngram2.find( id_suffix1 ); if( it!=tag0_2_ngram2.end() ) { needs_resort=true; const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n2_list.size(); ++j ) { const LEMM_Ngram2 & n2_probe = *n2_list[j]; const int id_suffix2 = n2_probe.tags.second; const lem::UCString & suffix2 = GetSuffixById(id_suffix2); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix2); if( it2!=sfx2score.end() ) it2->second += n2_probe.freq; } } } if( iword<last_word_index ) { // iword <-- iword+1 const lem::UCString & word2 = words[iword+1]; const int id_suffix2 = GetTag( word2 ); std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag1_2_ngram2.find( id_suffix2 ); if( it!=tag1_2_ngram2.end() ) { needs_resort=true; const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second; int proj_count = word2lemmas[iword].size(); for( int iproj = 0; iproj < proj_count; ++iproj ) { const lem::UCString & entry_name = word2lemmas[iword][iproj]; lem::UCString i_sfx = GetSuffix( entry_name ); if( sfx2score.find( i_sfx )==sfx2score.end() ) sfx2score.insert( std::make_pair( i_sfx, 0 ) ); } for( lem::Container::size_type j=0; j<n2_list.size(); ++j ) { const LEMM_Ngram2 & n2_probe = *n2_list[j]; const int id_suffix1 = n2_probe.tags.first; const lem::UCString & suffix1 = GetSuffixById(id_suffix1); std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1); if( it2!=sfx2score.end() ) it2->second += n2_probe.freq; } } } if( needs_resort ) { // теперь надо выбрать самый достоверный вариант. int best_score = 0; lem::UCString prev_lemma; int prev_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj ) { const lem::UCString & ename = word2lemmas[iword][iproj]; lem::UCString proj_suffix = GetSuffix( ename ); std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix); if( it3!=sfx2score.end() ) { const int new_score = it3->second; if( new_score > best_score ) { prev_score = new_score; prev_lemma = ename; } } } // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его. if( lemma_scores[iword] < prev_score ) { lemma_scores[iword] = prev_score; lemmas[iword] = prev_lemma; lemma_order[iword] = 2; } } } } } return; }
void Lemmatizator::Lemmatize( const lem::UCString &word, lem::MCollect<lem::UCString> &lemmas ) { lem::UCString res(word); res.to_upper(); bool rehash=false; for( int i=0; i<res.length(); ++i ) if( res[i]==0x0401 ) { res.set( i, 0x0415 ); rehash=true; } if( rehash ) res.calc_hash(); // Определяем, в какой группе искать. const int igroup = (unsigned)res.GetHash16() & (L_NHASHGROUP-1); const lem::Stream::pos_type pos = group_pos[igroup]; #if defined LEM_THREADS lem::Process::CritSecLocker lock(&cs); #endif // перемещается на начало группы в файле. bin->seekp(pos); // перебираем элементы группы в поисках нашей формы. const int n = bin->read_int(); lem::uint8_t x8[3]; if( char_size==sizeof(wchar_t) ) { lem::UCString form; lem::MCollect<int> inorm; for( int i=0; i<n; ++i ) { inorm.clear(); lem::Load_Packed( &form, *bin ); lem::uint8_t n8 = bin->read_uint8(); inorm.reserve(n8); for( lem::uint8_t i8=0; i8<n8; ++i8 ) { bin->read( x8, 3 ); const int x32 = (0x00ff0000&(x8[0]<<16)) | (0x0000ff00&(x8[1]<<8)) | (0x000000ff&x8[2]); inorm.push_back(x32); } if( form==res ) { // Нашли!!! for( lem::Container::size_type j=0; j<inorm.size(); ++j ) { lemmas.push_back( GetLemma(inorm[j]) ); } return; } } } else if( char_size==1 ) { lem::UCString form; lem::MCollect<int> inorm; for( int i=0; i<n; ++i ) { inorm.clear(); LoadEncodedString( &form, *bin, 1 ); lem::uint8_t n8 = bin->read_uint8(); inorm.reserve(n8); for( lem::uint8_t i8=0; i8<n8; ++i8 ) { bin->read( x8, 3 ); const int x32 = (0x00ff0000&(x8[0]<<16)) | (0x0000ff00&(x8[1]<<8)) | (0x000000ff&x8[2]); inorm.push_back(x32); } if( form==res ) { // Нашли!!! for( lem::Container::size_type j=0; j<inorm.size(); ++j ) { lemmas.push_back( GetLemma(inorm[j]) ); } return; } } } else { LEM_STOPIT; } lemmas.clear(); // Табличной подстановки не нашлось, проверяем замену суффикса. for( lem::Container::size_type i=0; i<suffices.size(); ++i ) { if( res.eq_endi( suffices[i].first ) ) { // Нашли замену суффикса! UCString lemma = lem::left( res, res.length()-suffices[i].first.length() ); lemma += suffices[i].second; lemmas.push_back(lemma); return; } } // Лемматизация не выполнена, возвращаем исходное слово в качестве леммы. lemmas.push_back(res); return; }
void BasicModel::PullFeatures1( lem::MCollect<lem::CString> & b, const lem::PtrCollect<ModelTokenFeatures> & token_features, int ifocus, int offset, bool rich_set, bool emit_Aa_feature ) const { int iword = ifocus + offset; if( iword >= 0 && iword < token_features.size() ) { const ModelTokenFeatures & f = * token_features[iword]; if( codebook->GetMaxSuffixLen() > 0 ) b.push_back( lem::format_str( "sfx[%d]=%d", offset, f.suffix_id ).c_str() ); if( emit_Aa_feature && f.Aa==true && !f.IsBegin && !f.IsEnd ) b.push_back( lem::format_str( "Aa[%d]=True", offset ).c_str() ); // здесь можно вывести и другие свойства слова. if( rich_set && EMIT_POS_TAGS ) { b.push_back( lem::format_str("pos[%d,N]=%s", offset, f.POS_N.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,A]=%s", offset, f.POS_A.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,V]=%s", offset, f.POS_V.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,IMV]=%s", offset, f.POS_IMV.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,I]=%s", offset, f.POS_I.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,Y]=%s", offset, f.POS_Y.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,VY]=%s", offset, f.POS_VY.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PRN]=%s", offset, f.POS_PRN.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PRN2]=%s", offset, f.POS_PRN2.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,C]=%s", offset, f.POS_C.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,D]=%s", offset, f.POS_D.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,P]=%s", offset, f.POS_P.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PX]=%s", offset, f.POS_PX.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,PP]=%s", offset, f.POS_PP.c_str() ).c_str() ); b.push_back( lem::format_str("pos[%d,MU]=%s", offset, f.POS_MU.c_str() ).c_str() ); } if( EMIT_FORMTAGS_FOR_CONTEXT && offset!=0 ) { for( int k = 0; k < f.allform_tags.size(); ++k ) { b.push_back( lem::format_str("formtag[%d]=%d", offset, f.allform_tags[k] ).c_str() ); } } if( EMIT_SEMANTIC_TAGS ) { for( int k = 0; k < f.semantic_tags.size(); ++k ) { b.push_back( lem::format_str("sem[%d]=%s", offset, lem::to_utf8( f.semantic_tags[k] ).c_str() ).c_str() ); } } } return; }
bool GeneratorLexer::Fetch( const LexerTextPos * current, const TokenExpectation * unused, lem::MCollect<const LexerTextPos*> & next ) { if( current==NULL ) { next.push_back( GetBeginToken() ); return true; } if( current->IsEnd() ) { return false; } next.clear(); // поищем в кэше уже найденные продолжения. std::pair<CACHED_EDGES::const_iterator,CACHED_EDGES::const_iterator> p_edges = edges.equal_range(current); if( p_edges.first!=p_edges.second ) { for( CACHED_EDGES::const_iterator it=p_edges.first; it!=p_edges.second; ++it ) { next.push_back( it->second ); } return true; } // Посмотрим, какие токены были перед данным, и какие слова они уже использовали. lem::MCollect<int> indeces; CollectUsedWords( current, indeces ); /* #if LEM_DEBUGGING==1 if( current->GetWordform()->GetName()->eqi(L"ловит") ) { lem::mout->printf("!\n"); } #endif */ bool token_created=false; lem::MCollect<const LexerTextPos*> matched_by_literal_ngrams, matched_by_normalized_ngrams, all_next_tokens; lem::Ptr<Ngrams> ngrams; lem::UCString prev_lemma; if( UseNGrams ) ngrams = dict->GetNgrams(); // Теперь неиспользованные ранее слова порождают новые токены. for( lem::Container::size_type i=0; i<words.size(); ++i ) if( indeces.find(i)==UNKNOWN ) { // слово не использовалось. typedef INDEX2WORDFORM::const_iterator IT; std::pair<IT,IT> p = index2wordform.equal_range( CastSizeToInt(i) ); for( IT it=p.first; it!=p.second; ++it ) { const Word_Form * wordform = it->second; const int word_index = current->IsRealWord() ? current->GetWordIndex()+1 : 0; const int start_pos = current->IsRealWord() ? (current->GetStartPosition()+current->GetWordLength()+1) : 0; // Нам нужно создать новый вариант этой словоформы. Word_Form * wf = new Word_Form( *wordform, true ); wf->SetOriginPos( word_index ); wordforms.push_back(wf); LexerTextPos * new_token = new LexerTextPos( current, wf, 0, start_pos, wf->GetName()->length(), word_index ); positions.push_back(new_token); all_next_tokens.push_back( new_token ); token2word.insert( std::make_pair(new_token,CastSizeToInt(i)) ); token_created = true; // Слово сочетается с предыдущим? if( UseNGrams && current->IsRealWord() ) { const lem::UCString & prev_word = * current->GetWordform()->GetNormalized(); const lem::UCString & new_word = * new_token->GetWordform()->GetNormalized(); float w2=0; int iw2=0; if( ngrams->FindLiteralNGrams( prev_word, new_word, w2, iw2 ) ) { // TODO: использовать частотность подошедшей N-граммы для взвешивания созданных токенов. matched_by_literal_ngrams.push_back( new_token ); } else { if( prev_lemma.empty() ) { const int prev_ekey = current->GetWordform()->GetEntryKey(); const SG_Entry & prev_e = dict->GetSynGram().GetEntry( prev_ekey ); prev_lemma = prev_e.GetName(); } const int new_ekey = new_token->GetWordform()->GetEntryKey(); const SG_Entry & new_e = dict->GetSynGram().GetEntry( new_ekey ); const lem::UCString & new_lemma = new_e.GetName(); if( ngrams->FindRawNGrams( prev_lemma, new_lemma, w2, iw2 ) ) { // TODO: использовать частотность подошедшей N-граммы для взвешивания созданных токенов. matched_by_normalized_ngrams.push_back( new_token ); } } } } } if( !matched_by_literal_ngrams.empty() ) { // найдена по крайней мере одна буквальная 2-грамма, поэтому отбрасываем все неподтвержденные варианты токенов. next = matched_by_literal_ngrams; } else if( !matched_by_normalized_ngrams.empty() ) { next = matched_by_normalized_ngrams; } else { next = all_next_tokens; } for( lem::Container::size_type i=0; i<next.size(); ++i ) { edges.insert( std::make_pair(current, const_cast<LexerTextPos*>( next[i] ) ) ); } /* #if LEM_DEBUGGING==1 lem::mout->printf( "%60h-\n" ); for( lem::Container::size_type i=0; i<next.size(); ++i ) { lem::mout->printf( "FETCHED: %us(%p) -> %us(%p)\n", current->GetWordform()->GetName()->c_str(), current, next[i]->GetWordform()->GetName()->c_str(), next[i] ); } #endif */ if( !token_created ) { // Возвращаем правую границу. next.push_back( GetEndToken(current) ); return true; } return false; }