public void Check(string line)
    {
        // Морфологический разбор
        using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY))
        {
            // Токенизация без использования синтаксических правил
            using (SolarixGrammarEngineNET.AnalysisResults projs = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_TOKENIZE_ONLY))
            {
                List <List <int> > word2tags = new List <List <int> >();

                if (projs.Count != tokens.Count)
                {
                    return;
                }

                total_word_count += projs.Count - 2;

                // Для каждого слова получим списки альтернативных лемматизаций.
                List <List <string> > word2lemmas   = new List <List <string> >();
                List <List <int> >    word2lemma_id = new List <List <int> >();

                List <string> lemmas = new List <string>();

                int last_word_index = projs.Count - 1;


                List <List <double> > viterbi_P           = new List <List <double> >();
                List <List <int> >    viterbi_backpointer = new List <List <int> >();

                for (int iword = 0; iword < projs.Count; ++iword)
                {
                    if (iword == 0 || iword == last_word_index)
                    {
                        List <string> w2l = new List <string>();
                        w2l.Add(string.Empty);
                        word2lemmas.Add(w2l);

                        List <int> w2li = new List <int>();
                        w2li.Add(MatchSuffix(GetTokenSuffix(0, last_word_index, projs[iword]), false));
                        word2lemma_id.Add(w2li);
                    }
                    else
                    {
                        List <string> word_lemmas    = new List <string>();
                        List <int>    word_lemma_ids = new List <int>();
                        for (int iproj = 0; iproj < projs[iword].VersionCount(); ++iproj)
                        {
                            string lemma = string.Empty;
                            int    ekey  = projs[iword].GetVersionEntryID(iproj);
                            string ename = gren.GetEntryName(ekey);
                            if (IsUnknownLexem(ename))
                            {
                                lemma = projs[iword].GetWord().ToLower();
                            }
                            else
                            {
                                lemma = ename.ToLower();
                            }

                            if (!word_lemmas.Contains(lemma))
                            {
                                word_lemmas.Add(lemma);
                                int id_lemma = MatchSuffix(GetSuffix(lemma), false);
                                if (id_lemma == -1)
                                {
                                    throw new System.ApplicationException();
                                }

                                word_lemma_ids.Add(id_lemma);
                            }
                        }

                        word2lemmas.Add(word_lemmas);
                        word2lemma_id.Add(word_lemma_ids);
                    }

                    lemmas.Add(word2lemmas[iword][0]);

                    List <double> px = new List <double>();
                    List <int>    bx = new List <int>();
                    for (int i = 0; i < word2lemmas[iword].Count; ++i)
                    {
                        if (iword == 0)
                        {
                            px.Add(1.0); // состояние START
                        }
                        else
                        {
                            px.Add(0.0); // для остальных столбцов пока не знаем
                        }
                        bx.Add(-1);
                    }

                    viterbi_P.Add(px);
                    viterbi_backpointer.Add(bx);
                }

                // Для каждого слова получим id_suffix
                List <int> word_suffices = new List <int>();

                for (int iword = 0; iword < projs.Count; ++iword)
                {
                    string word      = projs[iword].GetWord().ToLower();
                    string suffix    = GetTokenSuffix(iword, last_word_index, projs[iword]);
                    int    id_suffix = MatchSuffix(suffix, false);
                    if (id_suffix == -1)
                    {
                        continue;
                    }

                    word_suffices.Add(id_suffix);
                }

                // расчет по решетке
                for (int iword = 1; iword < projs.Count - 1; ++iword)
                {
                    // в этом столбце столько разных состояний
                    int n_states = word2lemmas[iword].Count;

                    // сразу получим теги для контекста
                    int id_suffix1 = word_suffices[iword - 1];
                    int id_suffix2 = word_suffices[iword];
                    int id_suffix3 = word_suffices[iword + 1];

                    string label1 = TagLabel(-1, id_suffix1);
                    string label2 = TagLabel(0, id_suffix2);
                    string label3 = TagLabel(1, id_suffix3);

                    for (int istate = 0; istate < n_states; ++istate)
                    {
                        // для состояния istate получим целевую метку для леммы
                        int    id_result_lemma = word2lemma_id[iword][istate];
                        string result_label    = ResultLabel(id_result_lemma);

                        if (!result_label2id.ContainsKey(result_label))
                        {
                            // переходов в такое состояние не было вообще, будет нулевая верояность
                            continue;
                        }

                        int res_label_index = result_label2id[result_label];

                        // просматриваем переходы из состояний предыдущего шага
                        int n_prev_states = word2lemmas[iword - 1].Count;

                        double best_p = -1.0;
                        int    best_prev_state_index = -1;

                        for (int i_prev_state = 0; i_prev_state < n_prev_states; ++i_prev_state)
                        {
                            int    id_prev_lemma    = word2lemma_id[iword - 1][i_prev_state];
                            string prev_lemma_label = LemmaLabel(-1, id_prev_lemma);
                            double P_prev           = viterbi_P[iword - 1][i_prev_state];

                            // запускаем модель для получения достоверности нового состояния
                            System.Collections.ArrayList context = new System.Collections.ArrayList();
                            context.Add(prev_lemma_label);
                            context.Add(label1);
                            context.Add(label2);
                            context.Add(label3);

                            try
                            {
                                double[] probabilities = mModel.Evaluate((string[])context.ToArray(typeof(string)));

                                double p = probabilities[res_label_index];

                                double P12 = p * P_prev; // вероятность данного перехода
                                if (P12 > best_p)
                                {
                                    best_p = P12;
                                    best_prev_state_index = i_prev_state;
                                }
                            }
                            catch (System.Exception ex)
                            {
                                // ... обычно это означает, что встретился ключ, которые не был включен в обучающий набор.
                                // будем считать, что у таких переходов нулевая вероятность.s
                            }
                        }

                        if (n_states == 1)
                        {
                            // если на данном шаге всего 1 состояние, то можем принудительно присвоить ему накопленную достоверность=1 и таким образом
                            // улучшить поведение модели при появлении неизвестных слов, приводящих к обнулению вероятностей.
                            viterbi_P[iword][istate] = 1.0;
                        }
                        else
                        {
                            viterbi_P[iword][istate] = best_p;
                        }

                        viterbi_backpointer[iword][istate] = best_prev_state_index;
                    }
                }

                // Для последнего состояния END просто найдем самое достоверное на пред. шаге
                double best_P1     = 0;
                int    best_state1 = 0;
                for (int i = 0; i < word2lemmas[last_word_index - 1].Count; ++i)
                {
                    double p = viterbi_P[last_word_index - 1][i];
                    if (p > best_P1)
                    {
                        best_P1     = p;
                        best_state1 = i;
                    }
                }

                viterbi_P[last_word_index][0]           = best_P1;
                viterbi_backpointer[last_word_index][0] = best_state1;

                // теперь обратный проход по решетке, через записи в backpointer'ах восстанавливаем самую достоверную цепочку лемм
                // для последнего шага - всего одно состояние END.
                int cur_backpointer = viterbi_backpointer[projs.Count - 1][0];
                int j = projs.Count - 2;

                List <string> best_lemmas = new List <string>();
                for (int k = 0; k < projs.Count; ++k)
                {
                    best_lemmas.Add(string.Empty);
                }

                while (j > 0)
                {
                    // для этого шага - такая лучшая лемма
                    string best_lemma = word2lemmas[j][cur_backpointer];
                    best_lemmas[j] = best_lemma;

                    // определяем лучшее состояние для предыдущего шага
                    int prev_backpointer = viterbi_backpointer[j][cur_backpointer];
                    cur_backpointer = prev_backpointer;

                    j--;
                }

                // Теперь сравниваем леммы c правильными значениями.
                for (int iword = 1; iword < tokens.Count - 1; ++iword)
                {
                    string mustbe = string.Empty;

                    int    ekey  = tokens[iword].GetEntryID();
                    string ename = gren.GetEntryName(ekey);

                    if (IsUnknownLexem(ename)) // не будем учитывать ошибки лемматизации для не-словарных лексем.
                    {
                        continue;
                    }

                    mustbe = ename.ToLower();

                    if (mustbe != best_lemmas[iword])
                    {
                        error_count_with_ngram++;
                    }

                    string lemma0 = string.Empty;
                    int    ekey0  = projs[iword].GetEntryID();
                    string ename0 = gren.GetEntryName(ekey0);
                    if (IsUnknownLexem(ename0))
                    {
                        continue;
                    }

                    lemma0 = ename0.ToLower();

                    if (mustbe != lemma0)
                    {
                        error_count_no_filter++;
                    }
                }
            }
        }

        return;
    }
Пример #2
0
    /*
     * public void Check( string line )
     * {
     * // Морфологический разбор
     * using( SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology( line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_COMPLETE_ONLY ) )
     * {
     * // Токенизация без использования синтаксических правил
     * using( SolarixGrammarEngineNET.AnalysisResults projs = gren.AnalyzeMorphology( line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_TOKENIZE_ONLY ) )
     * {
     *  List<List<int>> word2tags = new List<List<int>>();
     *
     *  if( projs.Count != tokens.Count )
     *   return;
     *
     *  total_word_count += projs.Count - 2;
     *
     *  // Для каждого слова получим списки альтернативных лемматизаций.
     *  List<List<string>> word2lemmas = new List<List<string>>();
     *
     *  List<string> lemmas = new List<string>();
     *
     *  int last_word_index = projs.Count - 1;
     *
     *  for( int iword = 0; iword < projs.Count; ++iword )
     *  {
     *   if( iword == 0 || iword == last_word_index )
     *   {
     *    List<string> w2l = new List<string>();
     *    w2l.Add( string.Empty );
     *    word2lemmas.Add( w2l );
     *   }
     *   else
     *   {
     *    List<string> word_lemmas = new List<string>();
     *    for( int iproj = 0; iproj < projs[iword].VersionCount(); ++iproj )
     *    {
     *     string lemma = string.Empty;
     *     int ekey = projs[iword].GetVersionEntryID( iproj );
     *     string ename = gren.GetEntryName( ekey );
     *     if( IsUnknownLexem( ename ) )
     *      lemma = projs[iword].GetWord().ToLower();
     *     else
     *      lemma = ename.ToLower();
     *
     *     if( !word_lemmas.Contains( lemma ) )
     *      word_lemmas.Add( lemma );
     *    }
     *
     *    word2lemmas.Add( word_lemmas );
     *   }
     *
     *   lemmas.Add( word2lemmas[iword][0] );
     *  }
     *
     *
     *  for( int iword = 1; iword < projs.Count - 1; ++iword )
     *  {
     *   string suffix1 = GetTokenSuffix( iword - 1, last_word_index, projs[iword - 1] );
     *   int id_suffix1 = MatchSuffix( suffix1, false );
     *   if( id_suffix1 == -1 )
     *    continue;
     *
     *   string suffix2 = GetTokenSuffix( iword, last_word_index, projs[iword] );
     *   int id_suffix2 = MatchSuffix( suffix2, false );
     *   if( id_suffix2 == -1 )
     *    continue;
     *
     *   string suffix3 = GetTokenSuffix( iword + 1, last_word_index, projs[iword + 1] );
     *   int id_suffix3 = MatchSuffix( suffix3, false );
     *   if( id_suffix3 == -1 )
     *    continue;
     *
     *   string label1 = TagLabel( -1, id_suffix1 );
     *   string label2 = TagLabel( 0, id_suffix2 );
     *   string label3 = TagLabel( 1, id_suffix3 );
     *
     *
     *   System.Collections.ArrayList context = new System.Collections.ArrayList();
     *   context.Add( label1 );
     *   context.Add( label2 );
     *   context.Add( label3 );
     *
     *   double[] probabilities = mModel.Evaluate( (string[])context.ToArray( typeof( string ) ) );
     *
     *   // теперь надо выбрать самый достоверный вариант.
     *   double best_score = 0;
     *
     *   // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
     *   for( int iproj = 0; iproj < word2lemmas[iword].Count; ++iproj )
     *   {
     *    string ename = word2lemmas[iword][iproj];
     *    string proj_suffix = GetSuffix( ename.ToLower() );
     *    int id_suffix = MatchSuffix( proj_suffix, false );
     *    if( id_suffix == -1 )
     *     continue;
     *
     *    string res_label = ResultLabel( id_suffix );
     *
     *    if( !result_label2id.ContainsKey( res_label ) )
     *     continue;
     *
     *    int res_label_index = result_label2id[res_label];
     *
     *    double p = probabilities[res_label_index];
     *
     *    if( p > best_score )
     *    {
     *     best_score = p;
     *     lemmas[iword] = ename.ToLower();
     *    }
     *   }
     *  }
     *
     *
     *  // Теперь сравниваем леммы c правильными значениями.
     *  for( int iword = 1; iword < tokens.Count - 1; ++iword )
     *  {
     *   string mustbe = string.Empty;
     *
     *   int ekey = tokens[iword].GetEntryID();
     *   string ename = gren.GetEntryName( ekey );
     *
     *   if( IsUnknownLexem( ename ) ) // не будем учитывать ошибки лемматизации для не-словарных лексем.
     *    continue;
     *
     *   mustbe = ename.ToLower();
     *
     *   if( mustbe != lemmas[iword] )
     *    error_count_with_ngram++;
     *
     *   string lemma0 = string.Empty;
     *   int ekey0 = projs[iword].GetEntryID();
     *   string ename0 = gren.GetEntryName( ekey0 );
     *   if( IsUnknownLexem( ename0 ) )
     *    continue;
     *
     *   lemma0 = ename0.ToLower();
     *
     *   if( mustbe != lemma0 )
     *    error_count_no_filter++;
     *  }
     * }
     * }
     *
     * return;
     * }
     */

    public void Check(string line)
    {
        // Морфологический разбор
        using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY))
        {
            total_word_count += tokens.Count - 2;

            System.Text.StringBuilder b = new System.Text.StringBuilder();
            b.Capacity = 100;

            // Для каждого слова получим списки альтернативных лемматизаций.
            List <List <string> > word2lemmas = new List <List <string> >();

            List <string> lemmas         = new List <string>();
            List <int>    model_lemma_id = new List <int>();

            int last_word_index = tokens.Count - 1;

            for (int iword = 0; iword < tokens.Count; ++iword)
            {
                if (iword == 0 || iword == last_word_index)
                {
                    List <string> w2l = new List <string>();
                    w2l.Add(string.Empty);
                    word2lemmas.Add(w2l);
                }
                else
                {
                    List <string> word_lemmas = new List <string>();

                    string        word    = tokens[iword].GetWord();
                    System.IntPtr hLemmas = SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_GetLemmasW(lemm_engine, word);
                    if (hLemmas == System.IntPtr.Zero)
                    {
                        throw new System.ApplicationException();
                    }

                    int nlemma = SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_CountLemmas(hLemmas);
                    for (int i = 0; i < nlemma; ++i)
                    {
                        b.Length = 0;
                        SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_GetLemmaStringW(hLemmas, i, b, b.Capacity);

                        string lemma = b.ToString().ToLower();

                        if (!word_lemmas.Contains(lemma))
                        {
                            word_lemmas.Add(lemma);
                        }
                    }
                    SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_DeleteLemmas(hLemmas);

                    word2lemmas.Add(word_lemmas);
                }

                lemmas.Add(word2lemmas[iword][0]);
                model_lemma_id.Add(0);
            }

            for (int iword = 1; iword < tokens.Count - 1; ++iword)
            {
                string suffix1    = GetTokenSuffix(iword - 1, last_word_index, tokens[iword - 1]);
                int    id_suffix1 = MatchSuffix(suffix1, false);
                if (id_suffix1 == -1)
                {
                    continue;
                }

                string suffix2    = GetTokenSuffix(iword, last_word_index, tokens[iword]);
                int    id_suffix2 = MatchSuffix(suffix2, false);
                if (id_suffix2 == -1)
                {
                    continue;
                }

                string suffix3    = GetTokenSuffix(iword + 1, last_word_index, tokens[iword + 1]);
                int    id_suffix3 = MatchSuffix(suffix3, false);
                if (id_suffix3 == -1)
                {
                    continue;
                }

                string label1 = TagLabel(-1, id_suffix1);
                string label2 = TagLabel(0, id_suffix2);
                string label3 = TagLabel(1, id_suffix3);


                System.Collections.ArrayList context = new System.Collections.ArrayList();
                context.Add(label1);
                context.Add(label2);
                context.Add(label3);

                double[] probabilities = mModel.Evaluate((string[])context.ToArray(typeof(string)));

                // теперь надо выбрать самый достоверный вариант.
                double best_score = 0;

                // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
                for (int iproj = 0; iproj < word2lemmas[iword].Count; ++iproj)
                {
                    string ename       = word2lemmas[iword][iproj];
                    string proj_suffix = GetSuffix(ename.ToLower());
                    int    id_suffix   = MatchSuffix(proj_suffix, false);
                    if (id_suffix == -1)
                    {
                        continue;
                    }

                    string res_label = ResultLabel(id_suffix);

                    if (!result_label2id.ContainsKey(res_label))
                    {
                        continue;
                    }

                    int res_label_index = result_label2id[res_label];

                    double p = probabilities[res_label_index];

                    if (p > best_score)
                    {
                        best_score            = p;
                        model_lemma_id[iword] = id_suffix;
                        lemmas[iword]         = ename.ToLower();
                    }
                }
            }


            // Теперь сравниваем леммы c правильными значениями.
            for (int iword = 1; iword < tokens.Count - 1; ++iword)
            {
                string mustbe = string.Empty;

                int    ekey  = tokens[iword].GetEntryID();
                string ename = gren.GetEntryName(ekey);

                if (IsUnknownLexem(ename)) // не будем учитывать ошибки лемматизации для не-словарных лексем.
                {
                    continue;
                }

                mustbe = ename.ToLower();

                // отдельно считаем все ошибки модели, так как часть из них могут быть
                // скрыты при выборе леммы в случаях, когда есть только один правильный вариант леммы, и он не совпадает с выбором модели.
                string mustbe_suffix    = GetSuffix(mustbe);
                int    mustbe_id_suffix = MatchSuffix(mustbe_suffix, false);
                if (mustbe_id_suffix != model_lemma_id[iword])
                {
                    raw_model_error_count++;
                }

                if (mustbe != lemmas[iword])
                {
                    error_count_with_ngram++;
                }

                string lemma0 = word2lemmas[iword][0].ToLower();

                if (mustbe != lemma0)
                {
                    error_count_no_filter++;
                }
            }
        }

        return;
    }