// Ищем в справочнике набор тегов, заданный списком tags. При необходимости // вносим в БД новую запись. Возвращается ID найденной или созданной записи. int TagSets::Register( const lem::MCollect< std::pair<int,int> > &tags ) { if( tags.empty() ) { return 0; } #if defined LEM_THREADS lem::Process::CritSecLocker lock(&cs); #endif // Для устранения вариантов записи одного и того же набора тегов отсортируем элементы по id_tag. lem::MCollect< std::pair<int,int> > *sorted_tags = new lem::MCollect< std::pair<int,int> >(tags); std::sort( sorted_tags->begin(), sorted_tags->end(), tags_sorter ); // Такой кортеж есть? const int i = tag_ptr.find(*sorted_tags); if( i==UNKNOWN ) { // Нет. // Поищем в БД. lem::UFString s; if( tags.size()==1 ) { s = lem::format_str( L"%d %d", tags.front().first, tags.front().second ); } else if( tags.size()==2 ) { s = lem::format_str( L"%d %d %d %d", sorted_tags->get(0).first, sorted_tags->get(0).second, sorted_tags->get(1).first, sorted_tags->get(1).second ); } else { for( lem::Container::size_type i=0; i<sorted_tags->size(); ++i ) { if(i>0) s += L' '; s += lem::format_str( L"%d %d", sorted_tags->get(i).first, sorted_tags->get(i).second ); } } const int id = db->AddTagSet(s); id2tags.insert( std::make_pair(id,sorted_tags) ); tag_ptr.push_back( sorted_tags ); tagset_id.push_back(id); return id; } else { delete sorted_tags; return tagset_id[i]; } }
static bool x_contains_any_of_y( const lem::MCollect<int> &x, const lem::MCollect<int> &y ) { if( y.size()==1 ) return x.find(y.front())!=UNKNOWN; else if( y.size()==2 ) return x.find(y.front())!=UNKNOWN || x.find(y.back())!=UNKNOWN; else { for( lem::Container::size_type i=0; i<y.size(); ++i ) if( x.find(y[i])!=UNKNOWN ) return true; return false; } }
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 SynPatternResult::FilterExportedNodes(const lem::MCollect< ExportNode > & must_be_exported) { if (must_be_exported.empty()) { exported_nodes.clear(); } else { lem::MCollect< std::pair<const lem::UCString*, const Word_Form*> > filtered; for (lem::Container::size_type i = 0; i < exported_nodes.size(); ++i) { const lem::UCString & name = *exported_nodes[i].first; for (lem::Container::size_type j = 0; j < must_be_exported.size(); ++j) { if (must_be_exported[j].node_name == name) { // Нашли ссылку, которую нужно перебросить в новый список, возможно уже под другим именем filtered.push_back(std::make_pair(&must_be_exported[j].as_name, exported_nodes[i].second)); break; } } } exported_nodes = filtered; } return; }
void SynPatternResult::SelectUnique_WithoutRemoval(lem::MCollect<const SynPatternResult*> & results) { lem::MCollect<int> result_hash; lem::MCollect<const SynPatternResult*> unique_result; for (lem::Container::size_type k = 0; k < results.size(); ++k) { const 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 = unique_result; return; }
void SynPatternResult::AppendDebugTrace(const lem::MCollect<SynPatternDebugTrace> & debug_trace2) { for (lem::Container::size_type i = 0; i < debug_trace2.size(); ++i) { debug_trace.push_back(debug_trace2[i]); } return; }
void TreeMatchingExperience::AddKBCheckerMatching( int id_facts, const lem::MCollect< const Solarix::Word_Form * > & arg_values, const KB_CheckingResult & res ) { LEM_CHECKIT_Z( id_facts!=UNKNOWN ); LEM_CHECKIT_Z( arg_values.size()>0 ); TME_KBChecker * y = new TME_KBChecker( arg_values, res ); kbid2item.insert( std::make_pair( std::make_pair(id_facts,arg_values.front()), y ) ); return; }
void SyntaxShell::PrintLexerPerformance( Solarix::BasicLexer & lexer, const lem::MCollect<const LexerTextPos*> & final_tokens ) { for( lem::Container::size_type i=0; i<final_tokens.size(); ++i ) { lem::mout->printf( "#%vf9%d%vn-->", CastSizeToInt(i) ); PrintLexerPerformance( lexer, final_tokens[i] ); lem::mout->eol(); } return; }
void SyllabContext::Replace(int start_index, int count, lem::MCollect<SyllabContextPoint*> & new_points) { for (int n = 0; n < count; ++n) points.Remove(start_index); for (lem::Container::size_type i = 0; i < new_points.size(); ++i) { const int new_index = start_index + CastSizeToInt(i); if (new_index == Count()) points.push_back(new_points[i]); else points.Insert(new_index, new_points[i]); } return; }
void NGramsStorage_SQLITE::UpdateNGrams( const lem::FString &suffix, int order, const lem::MCollect< std::pair<int,int> > & list ) { char asql_buf[1000]; sprintf( asql_buf, "UPDATE NGRAM%d%s SET w=w+? WHERE id=?", order, suffix.c_str() ); sqlite3_stmt *stmt2=NULL; int res = sqlite3_prepare_v2( hdb, asql_buf, -1, &stmt2, NULL ); if( res!=SQLITE_OK ) { const char *errmsg = sqlite3_errmsg(hdb); throw E_BaseException( lem::format_str( L"SQLite error %S", errmsg ).c_str() ); } for( lem::Container::size_type i=0; i<list.size(); ++i ) { #if LEM_DEBUGGING==1 int debug_id_ngram = list[i].first; int debug_add_w = list[i].second; if( debug_id_ngram==5 ) { // printf( "add_w=%d\n", debug_add_w ); } #endif res = sqlite3_bind_int( stmt2, 1, list[i].second ); res = sqlite3_bind_int( stmt2, 2, list[i].first ); res = sqlite3_step( stmt2 ); if( res!=SQLITE_DONE ) { const char *errmsg = sqlite3_errmsg(hdb); throw E_BaseException( lem::format_str( L"SQLite error %S", errmsg ).c_str() ); } res = sqlite3_reset(stmt2); } sqlite3_finalize(stmt2); return; }
void SynPatternResult::ResetCoordStates(int coord_id, const lem::MCollect<int> & state_ids) { std::multimap< int /*id_coord*/, int /*id_state*/ > filtered; for (auto it = exported_coords.begin(); it != exported_coords.end(); ++it) { if (coord_id != it->first) filtered.insert(*it); } for (lem::Container::size_type i = 0; i < state_ids.size(); ++i) { filtered.insert(std::make_pair(coord_id, state_ids[i])); } exported_coords = filtered; return; }
bool TreeMatchingExperience::FindKBCheckerMatching( int id_facts, const lem::MCollect< const Solarix::Word_Form * > & arg_values, KB_CheckingResult * res ) const { LEM_CHECKIT_Z( id_facts!=UNKNOWN ); LEM_CHECKIT_Z( arg_values.size()>0 ); typedef KBID2ITEM::const_iterator IT; std::pair<IT,IT> pit = kbid2item.equal_range( std::make_pair( id_facts, arg_values.front() ) ); for( IT it=pit.first; it!=pit.second; ++it ) { if( arg_values == it->second->arg_values ) { *res = it->second->res; return true; } } return false; }
Word_Form::Word_Form( const lem::MCollect<const Word_Form*> &variants ) { LEM_CHECKIT_Z( !variants.empty() ); // Первая версия становится основной, ее не копируем в альтернативы. for( lem::Container::size_type i=1; i<variants.size(); ++i ) alt.push_back( new Word_Form(*variants[i]) ); name = variants[0]->name; normalized = variants[0]->normalized; pair = variants[0]->pair; entry_key = variants[0]->entry_key; val = variants[0]->val; score=variants[0]->score; origin_pos = variants[0]->origin_pos; tokenizer_flags = variants[0]->tokenizer_flags; iversion = seq_iversion++; 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; }
int WordEntries_File::FindEntryOmonym(const Lexem& lname, int iclass, const lem::MCollect<Solarix::GramCoordPair> &p) { #if defined SOL_LOADTXT && defined SOL_COMPILER if (iclass != ANY_STATE && iclass != UNKNOWN) { UCString uname = to_upper(lname); typedef std::multimap< std::pair<UCString, int>, int >::const_iterator IT; std::pair<IT, IT> r = entry_class_lookup.equal_range(std::make_pair(uname, iclass)); for (IT it = r.first; it != r.second; ++it) { // Найденный омоним имеет нужную координатную пару? const int ekey = it->second; const Solarix::SG_Entry &e = GetEntryByKey(ekey); bool all = true; for (lem::Container::size_type k = 0; k < p.size(); ++k) { const int istate = e.GetAttrState(p[k].GetCoord()); if (istate != p[k].GetState()) { all = false; break; } } if (all) { // да - возвращаем return ekey; } } } #endif return UNKNOWN; }
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; }
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; }