bool ModelTagMatcher::Match( const Word_Form & wf, Solarix::Dictionary & dict ) const { if( !lexeme.empty() ) { if( !lexeme.eqi( *wf.GetName() ) ) return false; } else if( !id_lemma.empty() ) { bool m=false; for( lem::Container::size_type i=0; i<id_lemma.size(); ++i ) if( id_lemma[i] == wf.GetEntryKey() ) { m=true; break; } if( !m ) return false; } else if( !pos.empty() ) { bool m=false; const int ekey = wf.GetEntryKey(); const SG_Entry & e = dict.GetSynGram().GetEntry(ekey); const int wf_pos = e.GetClass(); for( lem::Container::size_type i=0; i<pos.size(); ++i ) if( pos[i]==wf_pos ) { m=true; break; } if( !m ) return false; } if( !pairs.empty() ) { for( lem::Container::size_type i=0; i<pairs.size(); ++i ) { const GramCoordPair & p = pairs[i]; if( wf.GetPairs().FindOnce(p)!=UNKNOWN ) continue; // для бистабильных координат - состояние 0 равнозначно отсутствию вообще такой пары if( dict.GetSynGram().coords()[ p.GetCoord().GetIndex() ].IsBistable() ) { if( wf.GetPairs().FindOnce( p.GetCoord().GetIndex() ) != UNKNOWN ) return false; } else return false; } } return true; }
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; }
/********************************************************************** Проверяет равенство координатных пар, хранимых в списке pair здесь и в указанной словоформе wf, причем из процедуры сравнения исключаются переданные в списке excoord координаты. Также проверяется совпадение хранимой лексической информации. ***********************************************************************/ bool Word_Form::AreEqualExcept( const Word_Form &wf, const CA_Array &excoord ) const { // Прежде всего должна совпасть хранимая лексическая информация. if( entry_key==UNKNOWN_STATE || wf.entry_key==UNKNOWN_STATE ) return wf.GetName() == GetName(); if( entry_key != wf.entry_key ) return false; // Собираем координаты для нашей словоформы. const Container::size_type npair=pair.size(); CA_Array pairs; pairs.reserve( npair+1 ); for( Container::size_type i1=0; i1<npair; i1++ ) { const GramCoordAdr pair_index = pair[i1].GetCoord(); if( // Если координата уже попала в список, и она встречается второй раз, // то это AND-координата, мы ее второй раз в список не будем включать. pairs.find(pair_index)!=UNKNOWN || // Координаты из списка excoord не включаем в проверку. excoord.find(pair_index)!=UNKNOWN ) continue; pairs.push_back(pair_index); } // Добавляем координаты второй синтаксемы. const Container::size_type nwfpair=wf.GetnPair(); for( Container::size_type i2=0; i2<nwfpair; i2++ ) { const GramCoordAdr pair_index = wf.pair[i2].GetCoord(); if( // Если координата уже попала в список, и она встречается второй раз, // то это AND-координата. pairs.find(pair_index)!=UNKNOWN || excoord.find(pair_index)!=UNKNOWN ) continue; pairs.push_back(pair_index); } // Проверяем совпадение координат из списка собранных нами. // // Требуем от обеих словоформ дать списки состояний по очередной // координате из приготовленного списка pairs. При этом мы учтем // И-координаты. Далее проверяем, чтобы у полученных списков // состояний совпали хотя бы по одному состоянию. for( Container::size_type i3=0; i3<pairs.size(); i3++ ) { const IntCollect pair_states1 = GetStates(pairs[i3]); const IntCollect pair_states2 = wf.GetStates(pairs[i3]); if( !find_any(pair_states1,pair_states2) ) return false; } // Список координат для проверки оказался пуст - считаем, что все совпали. return true; }