/***************************************************************************** Ищем вершины Сети и добавляем их в список finitees. Эта процедура вызываетс после построения Сети при подготовке фразоблока к проекции. Нам нужно заполнить список finitees - конечные узлы (листья). Стартуя из корня Сети, мы продвигаемся по каждой ветке, достигая конца. Внимание: не все найденные таким образом листья являются правильными: дело в том, что построение Сети для некоторых веток может обрываться алгоритмом, и нужно уметь обнаруживать, что лист не заканчивает на самом деле ветку. Это легко сделать, зная общее число слов в исходном предложении nword и параметры каждого узла Сети. ******************************************************************************/ void MLNetNode::FindFinitees( MCollect<const MLNetNode*> &finitees, int nword ) const { // Если данный узел не имеет прикрепленных к нему последующих, // то мы нашли один из конечных узлов Сети Потока Распознования. const int nchild = GetnChild(); if (!nchild) { if (from + n == nword) // Истинный лист - ветка доведена до конца предложения. finitees.push_back(this); return; } // Рекурсивно перепоручим последующим узлам найти конечные. for (int i = 0; i < nchild; i++) { GetChild(i).FindFinitees(finitees, nword); } return; }
void LA_WordProjBuffer::Pick_Projection( LA_ProjList *sublist, int i_proj, MCollect<Word_Coord> &coord_list, MCollect<ProjScore> &val_list, PtrCollect<LA_ProjectInfo>& prj_extra_inf ) { // Нашли проекцию для данной мультилексемы! n_succ++; const MCollect<Word_Coord> &coords_to_copy = (*sublist)[i_proj].GetCoord(); const MCollect<ProjScore> &vals_to_copy = (*sublist)[i_proj].GetVal(); for( Container::size_type j=0; j<coords_to_copy.size(); j++ ) { coord_list.push_back( coords_to_copy[j] ); val_list.push_back( vals_to_copy[j] ); prj_extra_inf.push_back(NULL); } (*sublist)[i_proj].Used(); return; }
MLNetNode::MLNetNode( const MLNetNode* prev, int ifrom, int nword, int tot_len, const MCollect<MLProjJob*> &proj, const MCollect<MLProjList*> &job_list, const MCollect<int> &word_job, const MCollect<Lexem> &words, Dictionary &dict ) { // Наш узел описывает мультилексемы, начнающиеся с позиции ifrom и // содержащие nword лексем. previous = prev; from = ifrom; n = nword; const int njob = CastSizeToInt(job_list.size()); // Собираем пробные мультилексемы, начиная с позиции from предложения. // Общая длина предложения задана как tot_len, максимальная длина // создаваемых мультилексем равна max_ml_len. Информация о пробных // мультилексемах будет хранится в подключаемых узлах. const int iFrom = ifrom + nword; // Индекс начала следующих мультилексем. if (iFrom == tot_len) return; int IPROJ_found = UNKNOWN; bool PROJ_found = false; int max_ml_len = dict.GetSynGram().IsMultiLexemBegin(words[iFrom]); if (max_ml_len <= 0) max_ml_len = 1; Lexem ml; SynGram &sg = dict.GetSynGram(); for (int len = 1; len <= max_ml_len && (iFrom + len) <= tot_len; len++) { if (len == 1) { PROJ_found = true; const int m0 = tot_len - iFrom; const int m1 = std::min(m0, max_ml_len); if (m1 == 2) { if (!sg.IsWordForm(words[iFrom])) { ml = words[iFrom]; ml.Add(words[iFrom + 1]); if (sg.IsMultiLexem(ml)) continue; } else if (!sg.IsWordForm(words[iFrom + 1])) { ml = words[iFrom]; ml.Add(words[iFrom + 1]); if (sg.IsMultiLexem(ml)) continue; } } else if (m1 == 3) { ml = words[iFrom]; ml.Add(words[iFrom + 1]); ml.Add(words[iFrom + 2]); if (sg.IsMultiLexem(ml)) { ml = words[iFrom + 1]; ml.Add(words[iFrom + 2]); if (!sg.IsMultiLexem(ml)) { if (!sg.IsWordForm(words[iFrom + 1]) || !sg.IsWordForm(words[iFrom + 2])) continue; } } } } else { PROJ_found = false; IPROJ_found = UNKNOWN; ml.clear(); for (int ii = 0; ii < len; ii++) ml.Add(words[iFrom + ii]); if (dict.GetSynGram().IsMultiLexem(ml)) { // Если в списке job_list заданий на проекцию мультилексем фразоблока // удастся найти задание для нашей мультилексемы и эта мультилексема // хоть раз спроецирована, то имеет смысл продолжать построение сети // далее. for (int ijob = 0; ijob < njob; ijob++) { if ( *(job_list[ijob]->GetContent()) == ml && job_list[ijob]->IsProjected() ) { PROJ_found = true; IPROJ_found = ijob; break; } } } } if (!PROJ_found) continue; MLNetNode *to_add = new MLNetNode( this, iFrom, len, tot_len, proj, job_list, word_job, words, dict ); child.push_back(to_add); // Выставим для узла to_add значение достоверности и индекса задания на // проекцию. if (len == 1) { const MLProjJob &prj = *proj[word_job[iFrom]]; to_add->val = prj.GetVal(); to_add->proj_job_i = prj.GetiJob(); //mout.printf( "ml=%us val=%f\n", proj[word_job[iFrom]].GetContent()->string().c_str(), prj.GetVal().GetFloat() ); } else { Real1 VAL(100); to_add->val = VAL; to_add->proj_job_i = IPROJ_found; } } return; }
/***************************************************************************** ФОНЕТИЧЕСКИЙ АЛЕФ-АВТОМАТ. Именно его деятельность привносит в Систему особый шик распознавания слов, написанных НЕ СОВСЕМ верно, к примеру, с орфографическими ошибками. ВХОДНЫЕ ПАРАМЕТРЫ; proj - задание на проекцию, содержит мультилексему, реально присутствующую в исходном предложении. ВОЗВРАЩАЕМЫЙ РЕЗУЛЬТАТ: Через параметр proj возвращается список фонетических инвариантов дл слова-аргумента. *****************************************************************************/ void LexicalAutomat::ProducePhonInv(MLProjList &proj, int id_language, LA_RecognitionTrace *trace) { // В число оригиналов входят и "ломанные" int n_org = 1 + CastSizeToInt(proj.get_Broken().size()); std::set<lem::UCString> created_phonetic_variants; for (int iorg = 0; iorg < n_org; iorg++) { const RC_Lexem &word = !iorg ? proj.GetContent() : proj.get_Broken()[iorg - 1]; const Lexem &mlex = *word; // Сама исходная, неискаженная лексема также примет участие в микшировании. // Для однолексем брать оригинал не имеет смысла - его и так спроецировали. if (created_phonetic_variants.find(mlex) == created_phonetic_variants.end()) { created_phonetic_variants.insert(mlex); // Получим списки фонетических инвариантов для каждой из nlex лексем, // входящий в мультилексему. MCollect<LA_AA_list*> packs; LA_AA_list *list = new LA_AA_list; list->reserve(16); list->push_back(LA_AA_item(mlex, Real1(100))); // Теперь мутированные варианты. LA_Pack *pack = AlephAuto(id_language, mlex, proj.get_Miss_Parameter(), trace); for (Container::size_type j = 0; j < pack->size(); j++) { const Solarix::Lexem &ph_lex = *(pack->get(j)); if (created_phonetic_variants.find(ph_lex) == created_phonetic_variants.end()) { created_phonetic_variants.insert(ph_lex); list->push_back(LA_AA_item(ph_lex, pack->get(j)->get_Val())); } } delete pack; packs.push_back(list); const int NTOT = CastSizeToInt(packs.front()->size()); // Пропускаем начальную немутированную лексему for (int i = 1; i < NTOT; i++) { const LA_AA_item &x = packs.front()->get(i); Lexem *mutated = new Lexem(x); proj.AddPhonInv(RC_Lexem(mutated), x.val); } // Удаляем ненужные далее списки фонетических инвариантов для однолексем. ZAP_A(packs); // Отсортируем мутации по убыванию достоверности. proj.SortPhonInv(); /* // Можем журнализовать результат. const int ninv=proj.GetnPhonInv(); if( ninv && GetDebugLevel()>=2 ) { lem::LogFile::logfile->printf( "LA: Phonetic invariants production: %d item(s)\n", ninv ); for( int i=0; i<ninv; i++ ) { lem::LogFile::logfile->printf( "#%d ", i ); const RC_Lexem &ml = proj.GetPhonInv(i); lem::LogFile::logfile->printf( "%us\n", ml->c_str() ); } lem::LogFile::logfile->eol(); } */ } } // for - цикл по оригиналам return; }