GetEntryClass() 공개 메소드

public GetEntryClass ( int id_entry ) : int
id_entry int
리턴 int
예제 #1
0
    bool IsPreposition(SolarixGrammarEngineNET.SyntaxTreeNode token)
    {
        if (token.VersionCount() == 1)
        {
            int id_entry = token.GetEntryID();
            int pos      = gren.GetEntryClass(id_entry);
            if (pos == SolarixGrammarEngineNET.GrammarEngineAPI.PREPOS_ru)
            {
                return(true);
            }
        }

        return(false);
    }
예제 #2
0
    static int GetPOS(SolarixGrammarEngineNET.GrammarEngine2 gren, SolarixGrammarEngineNET.SyntaxTreeNode node)
    {
        int id_entry = node.GetEntryID();
        int pos_id   = gren.GetEntryClass(id_entry);

        return(pos_id);
    }
예제 #3
0
    static List <string> GetWordFeatures(SolarixGrammarEngineNET.GrammarEngine2 gren, SolarixGrammarEngineNET.SyntaxTreeNode word, string feature_prefix)
    {
        List <string> features = new List <string>();

        if (emit_shingles)
        {
            // шинглы
            features.AddRange(GetShingles(word.GetWord()).Select(z => $"shingle[{feature_prefix}]={z}"));
        }

        if (emit_morphtags)
        {
            // морфологические фичи
            int id_class = gren.GetEntryClass(word.GetEntryID());
            features.Add(string.Format("class[{0}]={1}", feature_prefix, id_class));

            int nfeat = SolarixGrammarEngineNET.GrammarEngine.sol_GetNodePairsCount(word.hNode);
            for (int i = 0; i < nfeat; ++i)
            {
                int id_coord = SolarixGrammarEngineNET.GrammarEngine.sol_GetNodePairCoord(word.hNode, i);
                int id_state = SolarixGrammarEngineNET.GrammarEngine.sol_GetNodePairState(word.hNode, i);
                features.Add(string.Format("{0}[{2}]={1}", id_coord, id_state, feature_prefix));
            }
        }

        return(features);
    }
예제 #4
0
    public bool Match(SolarixGrammarEngineNET.SyntaxTreeNode proj, int iver, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        if (lexeme != null)
        {
            return(proj.GetWord().Equals(lexeme, StringComparison.InvariantCultureIgnoreCase));
        }

        if (id_lemma != null)
        {
            int ekey = proj.GetVersionEntryID(iver);
            if (id_lemma.Contains(ekey))
            {
                return(true);
            }

            return(false);
        }

        if (pos != null)
        {
            bool pos_matched = false;

            int ekey = proj.GetVersionEntryID(iver);
            if (ekey != -1)
            {
                int id_class = gren.GetEntryClass(ekey);
                pos_matched = pos.Contains(id_class);
            }

            if (!pos_matched)
            {
                return(false);
            }
        }

        if (pairs != null)
        {
            bool contains_all_required_pairs = true;
            foreach (SolarixGrammarEngineNET.CoordPair p in pairs)
            {
                if (!proj.VersionContains(iver, p))
                {
                    contains_all_required_pairs = false;
                    break;
                }
            }

            if (!contains_all_required_pairs)
            {
                return(false);
            }
        }

        return(true);
    }
    public string GetContextPoint(SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        System.Text.StringBuilder b = new StringBuilder();

        if (!string.IsNullOrEmpty(lexem))
        {
            b.AppendFormat("\"{0}\"", lexem);
        }
        else
        {
            if (id_class != -1)
            {
                b.AppendFormat("{0}:*", gren.GetClassName(id_class));
            }
            else
            {
                int pos = gren.GetEntryClass(id_entry);
                b.AppendFormat("{0}:{1}", gren.GetClassName(pos), gren.GetEntryName(id_entry));
            }

            b.Append("{");

            // выводим список координатных пар
            foreach (SolarixGrammarEngineNET.CoordPair p in pairs)
            {
                string CoordName = gren.GetCoordName(p.CoordID);
                if (gren.CountCoordStates(p.CoordID) == 0)
                {
                    if (p.StateID == 1)
                    {
                        b.AppendFormat(" {0}", CoordName);
                    }
                    else
                    {
                        b.AppendFormat(" ~{0}", CoordName);
                    }
                }
                else
                {
                    string StateName = gren.GetCoordStateName(p.CoordID, p.StateID);
                    b.AppendFormat(" {0}:{1}", CoordName, StateName);
                }
            }

            b.Append(" }");
        }

        return(b.ToString());
    }
예제 #6
0
    public int MatchTags(SolarixGrammarEngineNET.SyntaxTreeNode token, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        foreach (TagMatcher m in matchers)
        {
            if (m.Match(token, gren))
            {
                return(m.GetId());
            }
        }

        int    entry_id       = token.GetEntryID();
        int    pos_id         = gren.GetEntryClass(entry_id);
        string part_of_speech = gren.GetClassName(pos_id);
        string tags           = string.Join(" ", token.GetPairs().Select(z => string.Format("{0}={1}", gren.GetCoordName(z.CoordID), gren.GetCoordStateName(z.CoordID, z.StateID))).ToArray());
        string msg            = string.Format("Can not find tag for {0} {{ {1} {2} }}", token.GetWord(), part_of_speech, tags);

        throw new ApplicationException(msg);
    }
    public bool Match(SolarixGrammarEngineNET.SyntaxTreeNode token, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        if (!string.IsNullOrEmpty(lexem))
        {
            return(lexem.Equals(token.GetWord(), StringComparison.CurrentCultureIgnoreCase));
        }

        // Признаём сопоставимость с любой версией токена.
        int nver = token.VersionCount();

        for (int iver = 0; iver < nver; ++iver)
        {
            int version_ekey = token.GetVersionEntryID(iver);

            if (id_entry != -1 && version_ekey == id_entry)
            {
                return(true);
            }

            if (id_class != -1 && gren.GetEntryClass(version_ekey) == id_class)
            {
                return(true);
            }

            bool pairs_matched = true;
            foreach (SolarixGrammarEngineNET.CoordPair p in pairs)
            {
                if (!token.VersionContains(iver, p))
                {
                    pairs_matched = false;
                    break;
                }
            }

            if (pairs_matched)
            {
                return(true);
            }
        }

        return(true);
    }
예제 #8
0
    public FootPrintToken(SolarixGrammarEngineNET.GrammarEngine2 gren, SolarixGrammarEngineNET.SyntaxTreeNode root)
    {
        Contract.Ensures(!string.IsNullOrEmpty(this.word));
        Contract.Ensures(this.node != null);
        Contract.Ensures(this.tags != null);

        this.word = root.GetWord();
        this.tags = new List <string>();
        this.node = root;

        this.tags.Add(root.GetWord().ToLower());

        if (root.GetWord().Equals("не", StringComparison.OrdinalIgnoreCase))
        {
            this.tags.Add("neg");
        }


        int part_of_speech = gren.GetEntryClass(root.GetEntryID());

        switch (part_of_speech)
        {
        case SolarixGrammarEngineNET.GrammarEngineAPI.CONJ_ru: this.tags.Add("conj"); break;     // союз

        case SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN_ru: this.tags.Add("pr"); break;    // местоимение Я

        case SolarixGrammarEngineNET.GrammarEngineAPI.NOUN_ru: this.tags.Add("n"); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.ADJ_ru: this.tags.Add("adj"); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.VERB_ru: this.tags.Add("v"); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.INFINITIVE_ru: this.tags.Add("v"); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.GERUND_2_ru: this.tags.AddRange("adv adv_v".Split(' ')); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.ADVERB_ru:
        {
            this.tags.Add("adv");
            if (StringExtender.InCI(word, "очень крайне наиболее наименее чрезвычайно почти".Split()))         // модификаторы наречий и прилагательных
            {
                this.tags.Add("a_modif");
            }

            string adv_cat = AdverbCategory.GetQuestionWordForAdverb(word);
            if (!string.IsNullOrEmpty(adv_cat))
            {
                this.tags.Add("adv_" + adv_cat);
            }

            break;
        }

        case SolarixGrammarEngineNET.GrammarEngineAPI.PREPOS_ru: this.tags.Add("p"); break;

        case SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN2_ru: this.tags.Add("pr"); break;

        default: this.tags.Add("x"); break;
        }

        foreach (var p in root.GetPairs())
        {
            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.CASE_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.NOMINATIVE_CASE_ru: this.tags.Add("nom"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.GENITIVE_CASE_ru: this.tags.Add("gen"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.ACCUSATIVE_CASE_ru: this.tags.Add("acc"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.DATIVE_CASE_ru: this.tags.Add("dat"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PREPOSITIVE_CASE_ru: this.tags.Add("prep"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PARTITIVE_CASE_ru: this.tags.Add("part"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.LOCATIVE_CASE_ru: this.tags.Add("loc"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.INSTRUMENTAL_CASE_ru: this.tags.Add("instr"); break;
                }
            }

            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.NUMBER_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.SINGULAR_NUMBER_ru: this.tags.Add("sing"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PLURAL_NUMBER_ru: this.tags.Add("pl"); break;
                }
            }

            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.TENSE_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.PAST_ru: this.tags.Add("past"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PRESENT_ru: this.tags.Add("pres"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.FUTURE_ru: this.tags.Add("future"); break;
                }
            }

            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.FORM_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.ANIMATIVE_FORM_ru: this.tags.Add("anim"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.INANIMATIVE_FORM_ru: this.tags.Add("inanim"); break;
                }
            }

            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.GENDER_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.MASCULINE_GENDER_ru: this.tags.Add("masc"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.FEMININE_GENDER_ru: this.tags.Add("fem"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.NEUTRAL_GENDER_ru: this.tags.Add("neut"); break;
                }
            }


            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.PERSON_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.PERSON_1_ru: this.tags.Add("1"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PERSON_2_ru: this.tags.Add("2"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.PERSON_3_ru: this.tags.Add("3"); break;
                }
            }


            if (p.CoordID == SolarixGrammarEngineNET.GrammarEngineAPI.VERB_FORM_ru)
            {
                switch (p.StateID)
                {
                case SolarixGrammarEngineNET.GrammarEngineAPI.VB_INF_ru: this.tags.Add("vf1"); break;

                case SolarixGrammarEngineNET.GrammarEngineAPI.VB_ORDER_ru: this.tags.Add("imper"); break;
                }
            }
        }
    }
예제 #9
0
    public void Check(
        string line,
        ref int total_word_count,
        ref int error_count_no_filter,
        ref int error_count_with_model
        )
    {
        // Морфологический разбор
        using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY))
        {
            List <List <int> > word2tags     = new List <List <int> >();
            List <int>         selected_tags = new List <int>();

            // Токенизация без использования синтаксических правил
            using (SolarixGrammarEngineNET.AnalysisResults projs = gren.AnalyzeMorphology(line, LanguageID,
                                                                                          SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_TOKENIZE_ONLY /*| SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_DISABLE_FILTERS*/))
            {
                if (tokens.Count != projs.Count)
                {
                    return;
                }

                // Преобразуем все проекции каждого слова в варианты распознавания тегов

                List <int> tag_set = new List <int>();

                int start_tag = -1, end_tag = -1;

                //List<string> words = new List<string>();
                bool unmatched_tag = false;

                List <int> suffices        = new List <int>();
                int        last_word_index = tokens.Count - 1;

                for (int i = 0; i < tokens.Count; ++i)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[i];
                    string word = token.GetWord().ToLower();
                    //   words.Add(word);

                    int suffix_id = GetTokenSuffix(i, last_word_index, token);
                    suffices.Add(suffix_id);


                    SolarixGrammarEngineNET.SyntaxTreeNode proj = projs[i];
                    List <int> wt = new List <int>();
                    for (int j = 0; j < proj.VersionCount(); ++j)
                    {
                        int id_tag = tags.GetIndexById(tags.MatchTags(proj, j, gren));
                        if (id_tag != -1)
                        {
                            if (!wt.Contains(id_tag))
                            {
                                wt.Add(id_tag);
                            }

                            if (!tag_set.Contains(id_tag))
                            {
                                tag_set.Add(id_tag);
                            }
                        }

                        if (i == 0)
                        {
                            start_tag = id_tag;
                        }
                        else if (i == tokens.Count - 1)
                        {
                            end_tag = id_tag;
                        }
                    }

                    if (wt.Count == 0)
                    {
                        // ни один тег не подошел, это ошибка кодовой книги.
                        unmatched_tag = true;
                    }

                    word2tags.Add(wt);
                    selected_tags.Add(wt[0]);
                }

                if (unmatched_tag)
                {
                    return;
                }

                // -----------------------------------------
                // Посчитаем ошибки до применения модели
                // -----------------------------------------
                int n_err = 0;

                for (int iword = 1; iword < tokens.Count - 1; ++iword)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[iword];
                    int ekey1     = token.GetEntryID();
                    int id_class1 = gren.GetEntryClass(ekey1);

                    int tag = selected_tags[iword];
                    if (tag != -1)
                    {
                        TagMatcher m = tags[tags.GetIdByIndex(tag)];
                        if (!m.MatchPartOfSpeech(id_class1))
                        {
                            n_err++;
                        }
                    }
                }

                error_count_no_filter += n_err;
                total_word_count      += (tokens.Count - 2);

                int Nword  = tokens.Count; // кол-во последовательных шагов - число слов, включая левую и правую границы
                int Nstate = tag_set.Count;

                // Viterbi trellis

                // вероятности для состояний
                double[,] V = new double[Nword, Nstate];
                for (int t = 0; t < Nword; ++t)
                {
                    for (int s = 0; s < Nstate; ++s)
                    {
                        V[t, s] = 0.0;
                    }
                }

                // backpointers для отслеживания лучшего пути
                int[,] BACKPOINTER = new int[Nword, Nstate];
                for (int t = 0; t < Nword; ++t)
                {
                    for (int s = 0; s < Nstate; ++s)
                    {
                        BACKPOINTER[t, s] = -1; // возможно, надо как-то инициализировать дефолтный путь на случай, если найти лучший не получится - то есть надо проставить от начального до конечного.
                    }
                }
                V[0, tag_set.IndexOf(start_tag)] = 1.0; // начальное состояние - стартуем из этого состояния.

                for (int t = 1; t < Nword; ++t)
                {
                    // проставляем вероятность получения состояний на шаге t, исходя из значений на предыдущем шаге.

                    for (int s2 = 0; s2 < Nstate; ++s2) // состояния на шаге t
                    {
                        double max_v           = 0.0;
                        int    best_prev_state = 0;

                        int id_tag2 = tag_set[s2];

                        double b = 0.0;

                        Dictionary <int, double> bx;
                        if (PB.TryGetValue(id_tag2, out bx))
                        {
                            bx.TryGetValue(suffices[t], out b);
                        }

                        for (int s1 = 0; s1 < Nstate; ++s1) // состояния на шаге t-1
                        {
                            int id_tag1 = tag_set[s1];

                            double vt = V[t - 1, s1] * PA[id_tag1, id_tag2] * b;

                            if (vt > max_v)
                            {
                                max_v           = vt;
                                best_prev_state = s1;
                            }
                        }

                        V[t, s2]           = max_v;
                        BACKPOINTER[t, s2] = best_prev_state;
                    }
                }

                // обратный ход по состояниям, указанным в BACKPOINTER.

                int best_state = tag_set.IndexOf(end_tag);

                for (int t = Nword - 1; t > 0; --t)
                {
                    int best_prev_state = BACKPOINTER[t, best_state];

                    int selected_tag = tag_set[best_prev_state];

                    // Делаем вариант распознавания, давший этот токен, первым в списке.
                    // ATT: грубые ошибки выбора тега не допускаем, то есть разрешаем только те теги, которые были
                    // получены при распознавании слова.
                    if (word2tags[t - 1].Contains(selected_tag))
                    {
                        selected_tags[t - 1] = selected_tag;
                    }
                    else
                    {
                        // ... грубая ошибка выбора тега.
                    }

                    best_state = best_prev_state;
                }


                // Теперь проверяем количество ошибок в выборе частей речи.
                for (int iword = 1; iword < tokens.Count - 1; ++iword)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[iword];
                    int ekey1     = token.GetEntryID();
                    int id_class1 = gren.GetEntryClass(ekey1);

                    int tag = selected_tags[iword];
                    if (tag != -1)
                    {
                        TagMatcher m = tags[tags.GetIdByIndex(tag)];
                        if (!m.MatchPartOfSpeech(id_class1))
                        {
                            error_count_with_model++;
                        }
                    }
                }
            }
        }

        return;
    }
예제 #10
0
    string GetNodeNonterminal(SolarixGrammarEngineNET.SyntaxTreeNode node)
    {
        string res = string.Empty;

        int e1 = node.GetEntryID();
        int c1 = gren.GetEntryClass(e1);

        if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.NOUN_ru || c1 == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN_ru || c1 == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN2_ru)
        {
            int    id_case  = node.GetCoordState(SolarixGrammarEngineNET.GrammarEngineAPI.CASE_ru);
            string case_str = string.Empty;
            switch (id_case)
            {
            case SolarixGrammarEngineNET.GrammarEngineAPI.NOMINATIVE_CASE_ru: case_str = "им"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.INSTRUMENTAL_CASE_ru: case_str = "твор"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.GENITIVE_CASE_ru: case_str = "род"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.ACCUSATIVE_CASE_ru: case_str = "вин"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.DATIVE_CASE_ru: case_str = "дат"; break;
            }

            res = string.Format("Сущ_{0}", case_str);
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.ADJ_ru)
        {
            int    id_case  = node.GetCoordState(SolarixGrammarEngineNET.GrammarEngineAPI.CASE_ru);
            string case_str = string.Empty;
            switch (id_case)
            {
            case SolarixGrammarEngineNET.GrammarEngineAPI.NOMINATIVE_CASE_ru: case_str = "им"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.INSTRUMENTAL_CASE_ru: case_str = "твор"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.GENITIVE_CASE_ru: case_str = "род"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.ACCUSATIVE_CASE_ru: case_str = "вин"; break;

            case SolarixGrammarEngineNET.GrammarEngineAPI.DATIVE_CASE_ru: case_str = "дат"; break;
            }

            res = string.Format("Прил_{0}", case_str);
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.ADVERB_ru)
        {
            res = string.Format("Наречие_{0}", node.GetWord());
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.PREPOS_ru)
        {
            res = string.Format("Предлог_{0}", node.GetWord());
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.PARTICLE_ru)
        {
            res = string.Format("Частица_{0}", node.GetWord());
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.INFINITIVE_ru)
        {
            res = string.Format("Инф_{0}", node.GetWord());
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.PUNCTUATION_class)
        {
            res = string.Empty;
        }
        else if (c1 == SolarixGrammarEngineNET.GrammarEngineAPI.CONJ_ru)
        {
            res = string.Empty;
        }
        else
        {
            res = string.Empty;
        }

        return(res);
    }
 public string GetContextPoint(SolarixGrammarEngineNET.GrammarEngine2 gren)
 {
     return(string.Format("[\"{0}\"{{class:{1}}}]", word, gren.GetClassName(gren.GetEntryClass(id_entry))));
 }
    public TokenTagsEnumerator(bool IsBoundaryToken, SolarixGrammarEngineNET.SyntaxTreeNode _token, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        token = _token;
        list  = new List <TokenRecognizer>();


        int id_entry = token.GetEntryID();
        int id_class = gren.GetEntryClass(id_entry);

        // Подготовим список измерений и атрибутов.
        List <SolarixGrammarEngineNET.CoordPair> dims  = new List <SolarixGrammarEngineNET.CoordPair>();
        List <SolarixGrammarEngineNET.CoordPair> attrs = new List <SolarixGrammarEngineNET.CoordPair>();
        List <SolarixGrammarEngineNET.CoordPair> pairs = token.GetPairs();

        foreach (SolarixGrammarEngineNET.CoordPair p in pairs)
        {
            int t = gren.GetCoordType(id_class, p.CoordID);
            if (t == 0 || t == 2)
            {
                attrs.Add(p);
            }
            else if (t == 1)
            {
                dims.Add(p);
            }
        }

        // ------------------------------------------------------
        // Часть речи - самый общий случай
        // ------------------------------------------------------

        TokenRecognizer tr4 = new TokenRecognizer(id_class, -1);

        list.Add(tr4);

        List <TokenRecognizer> more_abstract = new List <TokenRecognizer>();

        more_abstract.Add(tr4);

        // ------------------------------------------------------
        // Часть речи и комбинации атрибутов
        // ------------------------------------------------------

        if (attrs.Count > 0)
        {
            List <TokenRecognizer> created_recognizers = new List <TokenRecognizer>();

            bool[] dim_bit = new bool[attrs.Count];
            for (int i = 0; i < attrs.Count; ++i)
            {
                dim_bit[i] = false;
            }

            while (true)
            {
                List <SolarixGrammarEngineNET.CoordPair> selected_pairs = new List <SolarixGrammarEngineNET.CoordPair>();
                for (int i = 0; i < attrs.Count; ++i)
                {
                    if (dim_bit[i])
                    {
                        selected_pairs.Add(attrs[i]);
                    }
                }

                if (selected_pairs.Count > 0)
                {
                    TokenRecognizer tr3 = new TokenRecognizer(id_class, -1, selected_pairs);
                    tr3.SetMoreAbstract(more_abstract);
                    list.Add(tr3);
                    created_recognizers.Add(tr3);
                }

                // Следующая комбинация
                int carry = 1;
                for (int ibit = dim_bit.Length - 1; ibit >= 0; --ibit)
                {
                    if (dim_bit[ibit] == false)
                    {
                        dim_bit[ibit] = true;
                        carry         = 0;
                        break;
                    }
                    else
                    {
                        dim_bit[ibit] = false;
                    }
                }

                if (carry == 1)
                {
                    break;
                }
            }

            more_abstract = created_recognizers;
        }


        // Лемма - только id словарной статьи. Это боее частный случай, чем указание части речи.
        TokenRecognizer tr2 = new TokenRecognizer(-1, id_entry);

        tr2.SetMoreAbstract(more_abstract);
        list.Add(tr2);
        more_abstract = new List <TokenRecognizer>();
        more_abstract.Add(tr2);


        if (dims.Count > 0)
        {
            List <TokenRecognizer> created_recognizers = new List <TokenRecognizer>();

            // -----------------------------------------------------------------------
            // Лемма (то есть id словарной статьи) и различные комбинации измерений.
            // -----------------------------------------------------------------------
            bool[] dim_bit = new bool[dims.Count];
            for (int i = 0; i < dims.Count; ++i)
            {
                dim_bit[i] = false;
            }

            while (true)
            {
                List <SolarixGrammarEngineNET.CoordPair> selected_pairs = new List <SolarixGrammarEngineNET.CoordPair>();
                for (int i = 0; i < dims.Count; ++i)
                {
                    if (dim_bit[i])
                    {
                        selected_pairs.Add(dims[i]);
                    }
                }

                if (selected_pairs.Count > 0)
                {
                    TokenRecognizer tr5 = new TokenRecognizer(-1, id_entry, selected_pairs);
                    tr5.SetMoreAbstract(more_abstract);
                    created_recognizers.Add(tr5);
                    list.Add(tr5);
                }

                // Следующая комбинация
                int carry = 1;
                for (int ibit = dim_bit.Length - 1; ibit >= 0; --ibit)
                {
                    if (dim_bit[ibit] == false)
                    {
                        dim_bit[ibit] = true;
                        carry         = 0;
                        break;
                    }
                    else
                    {
                        dim_bit[ibit] = false;
                    }
                }

                if (carry == 1)
                {
                    break;
                }
            }

            more_abstract = created_recognizers;
        }


        // ----------------------------------
        // Лексема - самый частный случай.
        // ----------------------------------

        /*
         * if( !IsBoundaryToken )
         * {
         * TokenRecognizer tr0 = new TokenRecognizer( token.GetWord() );
         * tr0.SetMoreAbstract( more_abstract );
         * list.Add( tr0 );
         * }
         */

        return;
    }
예제 #13
0
    public static bool IsPartOfSpeech(this SolarixGrammarEngineNET.SyntaxTreeNode node, SolarixGrammarEngineNET.GrammarEngine2 gren, int part_of_speech)
    {
        int p = gren.GetEntryClass(node.GetEntryID());

        return(p == part_of_speech);
    }
예제 #14
0
    public bool Match(SolarixGrammarEngineNET.SyntaxTreeNode token, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        if (lexeme != null)
        {
            return(token.GetWord().Equals(lexeme, StringComparison.InvariantCultureIgnoreCase));
        }

        if (id_lemma != null)
        {
            for (int iver = 0; iver < token.VersionCount(); ++iver)
            {
                int ekey = token.GetVersionEntryID(iver);
                if (id_lemma.Contains(ekey))
                {
                    return(true);
                }
            }

            return(false);
        }

        if (pos != null)
        {
            bool pos_matched = false;

            for (int iver = 0; iver < token.VersionCount(); ++iver)
            {
                int ekey = token.GetVersionEntryID(iver);
                if (ekey != -1)
                {
                    int id_class = gren.GetEntryClass(ekey);
                    pos_matched = pos.Contains(id_class);
                    if (pos_matched)
                    {
                        break;
                    }
                }
            }

            if (!pos_matched)
            {
                return(false);
            }
        }

        if (pairs != null && pairs.Count > 0)
        {
            bool a_version_matched = false;

            for (int iver = 0; iver < token.VersionCount(); ++iver)
            {
                bool ver_ok = true;

                foreach (SolarixGrammarEngineNET.CoordPair p in pairs)
                {
                    if (!token.VersionContains(iver, p))
                    {
                        ver_ok = false;
                        break;
                    }
                }

                if (ver_ok)
                {
                    a_version_matched = true;
                    break;
                }
            }

            return(a_version_matched);
        }

        return(true);
    }
    public void Check(
        string line,
        ref int total_word_count,
        ref int error_count_no_filter,
        ref int error_count_with_model
        )
    {
        // Морфологический разбор
        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 /*| SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_DISABLE_FILTERS*/))
            {
                if (tokens.Count != projs.Count)
                {
                    return;
                }


                int last_word_index = projs.Count - 1;

                // -----------------------------------------
                // Посчитаем ошибки до применения модели
                // -----------------------------------------
                int n_err = 0;
                for (int iword = 1; iword < last_word_index; ++iword)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode proj = projs[iword];
                    int ekey0     = proj.GetEntryID();
                    int id_class0 = gren.GetEntryClass(ekey0);

                    // Совпадает с точным значением?
                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[iword];
                    int ekey1     = token.GetEntryID();
                    int id_class1 = gren.GetEntryClass(ekey1);

                    if (id_class0 != id_class1)
                    {
                        n_err++;
                    }
                }

                error_count_no_filter += n_err;
                total_word_count      += (tokens.Count - 2);



                List <int> n_pos     = new List <int>(); // кол-во разных частей речи для каждого токена
                List <int> word2tags = new List <int>();

                // Преобразуем все проекции каждого слова в варианты распознавания тегов
                for (int i = 0; i < tokens.Count; ++i)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[i];
                    int index = GetTokenSuffix(i, last_word_index, token);

                    word2tags.Add(index);

                    // На сколько разных частей речи проецируется данное слово
                    List <int> pos_list = new List <int>();
                    for (int k = 0; k < projs[i].VersionCount(); ++k)
                    {
                        int ekey0     = projs[i].GetVersionEntryID(k);
                        int id_class0 = gren.GetEntryClass(ekey0);
                        if (!pos_list.Contains(id_class0))
                        {
                            pos_list.Add(id_class0);
                        }
                    }

                    n_pos.Add(pos_list.Count);
                }


                List <Dictionary <int, int> > pos_score = new List <Dictionary <int, int> >();
                List <int> pos_score_order = new List <int>();

                // Инициализируем вектор частей речи значениями, которые соответствуют
                // чамым частотным словоформам.
                for (int iword = 0; iword < tokens.Count - 1; ++iword)
                {
                    SolarixGrammarEngineNET.SyntaxTreeNode proj = projs[iword];

                    Dictionary <int, int> p = new Dictionary <int, int>();

                    for (int iproj = 0; iproj < proj.VersionCount(); ++iproj)
                    {
                        int ekey     = proj.GetVersionEntryID(iproj);
                        int id_class = gren.GetEntryClass(ekey);

                        if (!p.ContainsKey(id_class))
                        {
                            if (iproj == 0)
                            {
                                p.Add(id_class, 1);
                            }
                            else
                            {
                                p.Add(id_class, 0);
                            }
                        }
                    }

                    pos_score.Add(p);
                    pos_score_order.Add(1);
                }


                // ---------------------------------
                // теперь применим модель
                // ---------------------------------
                bool use_4grams = true;
                bool use_3grams = true;
                bool use_2grams = true;

                for (int iword = 1; iword < tokens.Count - 1; ++iword)
                {
                    string word = tokens[iword].GetWord();

                    bool applied = false;

                    // ==============
                    // ТЕТРАГРАММЫ
                    // ==============

                    if (use_4grams && !applied && iword > 2)
                    {
                        if (n_pos[iword] > 1) // Выбираем POS для iword на основе iword-3,iword-2,iword-1
                        {
                            int tag0 = word2tags[iword - 3];
                            int tag1 = word2tags[iword - 2];
                            int tag2 = word2tags[iword - 1];

                            List <NGram4> n4_list;
                            Int3          k = new Int3(tag0, tag1, tag2);

                            if (tag0_2_ngram4.TryGetValue(k, out n4_list))
                            {
                                // Перебираем варианты, которые вытекают из наличия тегов tag0,tag1,tag2 и прибавляем очки соответствующим частям речи.
                                foreach (NGram4 n4_probe in n4_list)
                                {
                                    int        tag3 = n4_probe.tags3;
                                    TagMatcher m    = selectors[tag3];

                                    List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                    Dictionary <int, int> pos2score = pos_score[iword];

                                    foreach (KeyValuePair <int, int> p in pos2score)
                                    {
                                        if (m.MatchPartOfSpeech(p.Key))
                                        {
                                            int m_freq = ngrams4[n4_probe];
                                            changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                            applied = true;
                                        }
                                    }

                                    foreach (var kv in changes)
                                    {
                                        pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                    }

                                    pos_score_order[iword] = 4;
                                }
                            }
                        }
                        else if (n_pos[iword - 1] > 1 && pos_score_order[iword - 1] < 4) // Выбираем POS для iword-1 на основе iword-3,iword-2,iword
                        {
                            int tag0 = word2tags[iword - 3];
                            int tag1 = word2tags[iword - 2];
                            int tag3 = word2tags[iword];

                            List <NGram4> n4_list;
                            Int3          k = new Int3(tag0, tag1, tag3);

                            if (tag1_2_ngram4.TryGetValue(k, out n4_list))
                            {
                                // Перебираем варианты, которые вытекают из наличия тегов tag0,tag1,tag2 и прибавляем очки соответствующим частям речи.
                                foreach (NGram4 n4_probe in n4_list)
                                {
                                    int        tag2 = n4_probe.tags2;
                                    TagMatcher m    = selectors[tag2];

                                    List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                    Dictionary <int, int> pos2score = pos_score[iword];

                                    foreach (KeyValuePair <int, int> p in pos2score)
                                    {
                                        if (m.MatchPartOfSpeech(p.Key))
                                        {
                                            int m_freq = ngrams4_1[n4_probe];
                                            changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                            applied = true;
                                        }
                                    }

                                    foreach (var kv in changes)
                                    {
                                        pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                    }

                                    pos_score_order[iword - 1] = 4;
                                }
                            }
                        }
                    }



                    // ==============
                    // ТРИГРАММЫ
                    // ==============

                    if (use_3grams && !applied && iword > 1)
                    {
                        if (n_pos[iword] > 1) // Выбираем POS для iword на основе iword-2,iword-1
                        {
                            {
                                int tag0 = word2tags[iword - 2];
                                int tag1 = word2tags[iword - 1];

                                List <NGram3> n3_list;
                                Int2          k = new Int2(tag0, tag1);

                                if (tag0_2_ngram3.TryGetValue(k, out n3_list))
                                {
                                    // Перебираем варианты, которые вытекают из наличия тегов tag0,tag1, и прибавляем очки соответствующим частям речи.
                                    foreach (NGram3 n3_probe in n3_list)
                                    {
                                        int        tag2 = n3_probe.tags2;
                                        TagMatcher m    = selectors[tag2];

                                        List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                        Dictionary <int, int> pos2score = pos_score[iword];

                                        foreach (KeyValuePair <int, int> p in pos2score)
                                        {
                                            if (m.MatchPartOfSpeech(p.Key))
                                            {
                                                int m_freq = ngrams3[n3_probe];
                                                changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                                applied = true;
                                            }
                                        }

                                        foreach (var kv in changes)
                                        {
                                            pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                        }
                                    }
                                }
                            }


                            if (iword < last_word_index)
                            {
                                // iword-1 --> iword <-- iword+1

                                int tag0 = word2tags[iword - 1];
                                int tag2 = word2tags[iword + 1];

                                List <NGram3> n3_list;
                                Int2          k = new Int2(tag0, tag2);

                                if (tag1_2_ngram3.TryGetValue(k, out n3_list))
                                {
                                    // Перебираем варианты, которые вытекают из наличия тегов tag0,tag2, и прибавляем очки соответствующим частям речи.
                                    foreach (NGram3 n3_probe in n3_list)
                                    {
                                        int        tag1 = n3_probe.tags1;
                                        TagMatcher m    = selectors[tag1];

                                        List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                        Dictionary <int, int> pos2score = pos_score[iword];

                                        foreach (KeyValuePair <int, int> p in pos2score)
                                        {
                                            if (m.MatchPartOfSpeech(p.Key))
                                            {
                                                int m_freq = ngrams3_1[n3_probe];
                                                changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                                applied = true;
                                            }
                                        }

                                        foreach (var kv in changes)
                                        {
                                            pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                        }

                                        pos_score_order[iword] = 3;
                                    }
                                }
                            }
                        }
                        else if (n_pos[iword - 1] > 1 && pos_score_order[iword - 1] < 3) // Выбираем POS для iword-1 на основе iword-2,iword
                        {
                            int tag0 = word2tags[iword - 2];
                            int tag2 = word2tags[iword];

                            List <NGram3> n3_list;
                            Int2          k = new Int2(tag0, tag2);

                            if (tag1_2_ngram3.TryGetValue(k, out n3_list))
                            {
                                // Перебираем варианты, которые вытекают из наличия тегов tag0,tag2, и прибавляем очки соответствующим частям речи.
                                foreach (NGram3 n3_probe in n3_list)
                                {
                                    int        tag1 = n3_probe.tags1;
                                    TagMatcher m    = selectors[tag1];

                                    List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                    Dictionary <int, int> pos2score = pos_score[iword];

                                    foreach (KeyValuePair <int, int> p in pos2score)
                                    {
                                        if (m.MatchPartOfSpeech(p.Key))
                                        {
                                            int m_freq = ngrams3_1[n3_probe];
                                            changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                            applied = true;
                                        }
                                    }

                                    foreach (var kv in changes)
                                    {
                                        pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                    }

                                    pos_score_order[iword] = 3;
                                }
                            }
                        }
                    }


                    // ==============
                    // ДИГРАММЫ
                    // ==============

                    if (use_2grams && !applied && iword > 1)
                    {
                        if (n_pos[iword] > 1) // Выбираем POS для iword на основе iword-1
                        {
                            {
                                int tag0 = word2tags[iword - 1];

                                List <NGram2> n2_list;
                                if (tag0_2_ngram2.TryGetValue(tag0, out n2_list))
                                {
                                    // Перебираем варианты, которые вытекают из наличия тега tag0, и прибавляем очки соответствующим частям речи.
                                    foreach (NGram2 n2_probe in n2_list)
                                    {
                                        int        tag1 = n2_probe.tags1;
                                        TagMatcher m    = selectors[tag1];

                                        List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                        Dictionary <int, int> pos2score = pos_score[iword];

                                        foreach (KeyValuePair <int, int> p in pos2score)
                                        {
                                            if (m.MatchPartOfSpeech(p.Key))
                                            {
                                                int m_freq = ngrams2[n2_probe];
                                                changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                                applied = true;
                                            }
                                        }

                                        foreach (var kv in changes)
                                        {
                                            pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                        }

                                        pos_score_order[iword] = 2;
                                    }
                                }
                            }

                            if (iword < last_word_index)
                            {
                                // iword <-- iword+1
                                int tag1 = word2tags[iword + 1];

                                List <NGram2> n2_list;
                                if (tag1_2_ngram2.TryGetValue(tag1, out n2_list))
                                {
                                    // Перебираем варианты, которые вытекают из наличия тега tag1, и прибавляем очки соответствующим частям речи.
                                    foreach (NGram2 n2_probe in n2_list)
                                    {
                                        int        tag0 = n2_probe.tags0;
                                        TagMatcher m    = selectors[tag0];

                                        List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                        Dictionary <int, int> pos2score = pos_score[iword];

                                        foreach (KeyValuePair <int, int> p in pos2score)
                                        {
                                            if (m.MatchPartOfSpeech(p.Key))
                                            {
                                                int m_freq = ngrams2_1[n2_probe];
                                                changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                                applied = true;
                                            }
                                        }

                                        foreach (var kv in changes)
                                        {
                                            pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                        }

                                        pos_score_order[iword] = 2;
                                    }
                                }
                            }
                        }
                        else if (n_pos[iword - 1] > 1 && pos_score_order[iword - 1] == 1) // Выбираем POS для iword-1 на основе iword
                        {
                            int tag1 = word2tags[iword];

                            List <NGram2> n2_list;
                            if (tag1_2_ngram2.TryGetValue(tag1, out n2_list))
                            {
                                // Перебираем варианты, которые вытекают из наличия тега tag1, и прибавляем очки соответствующим частям речи.
                                foreach (NGram2 n2_probe in n2_list)
                                {
                                    int        tag0 = n2_probe.tags0;
                                    TagMatcher m    = selectors[tag0];

                                    List <KeyValuePair <int, int> > changes = new List <KeyValuePair <int, int> >();

                                    Dictionary <int, int> pos2score = pos_score[iword - 1];

                                    foreach (KeyValuePair <int, int> p in pos2score)
                                    {
                                        if (m.MatchPartOfSpeech(p.Key))
                                        {
                                            int m_freq = ngrams2_1[n2_probe];
                                            changes.Add(new KeyValuePair <int, int>(p.Key, m_freq));
                                            applied = true;
                                        }
                                    }

                                    foreach (var kv in changes)
                                    {
                                        pos2score[kv.Key] = pos2score[kv.Key] + kv.Value;
                                    }

                                    pos_score_order[iword - 1] = 2;
                                }
                            }
                        }
                    }
                }



                // Все вероятности перехода учтены.

                // Совпадает ли selected_id_class с требуемыми значениями?
                for (int iword = 1; iword < projs.Count - 1; ++iword)
                {
                    Dictionary <int, int> word_pos_scores = pos_score[iword];
                    int best_score = 0;
                    int best_pos   = -1;
                    foreach (KeyValuePair <int, int> k in word_pos_scores)
                    {
                        if (k.Value > best_score)
                        {
                            best_score = k.Value;
                            best_pos   = k.Key;
                        }
                    }

                    SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[iword];
                    int ekey1     = token.GetEntryID();
                    int id_class1 = gren.GetEntryClass(ekey1);

                    if (best_pos != id_class1)
                    {
                        error_count_with_model++;
                    }
                }
            }
        }


        return;
    }
    public void Collect(SolarixGrammarEngineNET.AnalysisResults tokens, SolarixGrammarEngineNET.AnalysisResults trees, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        if (trees.Count == 3)
        {
            SolarixGrammarEngineNET.SyntaxTreeNode root = trees[1];
            int p_ekey   = root.GetEntryID();
            int id_class = gren.GetEntryClass(p_ekey);

            if (
                id_class == SolarixGrammarEngineNET.GrammarEngineAPI.IMPERSONAL_VERB_ru ||
                id_class == SolarixGrammarEngineNET.GrammarEngineAPI.VERB_ru ||
                id_class == SolarixGrammarEngineNET.GrammarEngineAPI.INFINITIVE_ru
                )
            {
                ok = true;
            }
        }

        if (ok)
        {
            int N = tokens.Count;

            labels = new List <List <string> >();
            for (int iroot = 0; iroot < N; ++iroot)
            {
                List <string> x = new List <string>();
                x.Add("O");
                labels.Add(x);
            }

            for (int iroot = 1; iroot < trees.Count - 1; ++iroot)
            {
                ProcessTree(trees[iroot], gren);
            }

            // -----------------------------------------------
            // Уточняем разметку для групп существительных
            // -----------------------------------------------
            for (int i = 1; i < N - 1; ++i)
            {
                List <string> l = labels[i];

                if (l[0].StartsWith("NP"))
                {
                    string NP = l[0];

                    // меняем метку у первого токена на B-NP
                    l.RemoveAt(0);
                    l.Insert(0, "B-NP");

                    // идем вправо до появления другой NP-метки.
                    for (int k = i + 1; k < N; ++k)
                    {
                        if (labels[k][0] == NP)
                        {
                            labels[k].RemoveAt(0);
                            labels[k].Insert(0, "I-NP");
                        }
                        else
                        {
                            // Удалим все появления NP-метки далее вправо.
                            for (int q = k; q < N; ++q)
                            {
                                labels[q].Remove(NP);
                            }

                            break;
                        }
                    }
                }
            }


            // Уточняем разметку для глагольных групп.
            for (int i = 1; i < N - 1; ++i)
            {
                List <string> l = labels[i];

                if (l[0].StartsWith("VX"))
                {
                    // Корневой глагол в сказуемом.
                    // Цепочка токенов в группе может быть разорвана из-за того, что наречный оборот, привязанный к сказуемому,
                    // стоит справа от глагольного дополнения. Поэтому проверим наличие таких разрывов.
                    l.RemoveAt(0); // под VX лежит VP, который мы сейчас поднимем
                    string VP = l[0];

                    int vp_begin = i;
                    // ищем разрыв слева
                    for (int k = i - 1; k >= 0; --k)
                    {
                        if (labels[k][0] != VP)
                        {
                            // слева - конец цепочки токенов для этого сказуемого. Удалим все более левые упоминания этого VP.
                            for ( ; k >= 0; --k)
                            {
                                labels[k].Remove(VP);
                            }

                            break;
                        }
                        else
                        {
                            vp_begin = k;
                        }
                    }

                    int vp_end = i;
                    // ищем разрыв справа
                    for (int k = i + 1; k < N; ++k)
                    {
                        if (labels[k][0] != VP)
                        {
                            // справа - конец цепочки токенов для этого сказуемого. Удалим все более правые упоминания этого VP.
                            for ( ; k < N; ++k)
                            {
                                labels[k].Remove(VP);
                            }
                            break;
                        }
                        else
                        {
                            vp_end = k;
                        }
                    }

                    // поставим отметку на первый VP-токен
                    labels[vp_begin].RemoveAt(0);
                    labels[vp_begin].Insert(0, "B-VP");

                    // а остальные пометим как I-VP
                    for (int j = vp_begin + 1; j <= vp_end; ++j)
                    {
                        labels[j].Remove(VP);
                        labels[j].Insert(0, "I-VP");
                    }
                }
            }


            for (int i = 0; i < labels.Count; ++i)
            {
                string   l = labels[i][0];
                string[] t = l.Split(':');
                labels[i].Clear();
                labels[i].Add(t[0]);
            }
        }

        return;
    }
    private void ProcessTree(SolarixGrammarEngineNET.SyntaxTreeNode node, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        int p_ekey   = node.GetEntryID();
        int id_class = gren.GetEntryClass(p_ekey);

        if (
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.NOUN_ru ||
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN2_ru ||
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN_ru
            )
        {
            SetLabel(node, string.Format("NP:{0}", chunk_num++), true);

            for (int ileaf = 0; ileaf < node.leafs.Count; ++ileaf)
            {
                SolarixGrammarEngineNET.SyntaxTreeNode leaf = node.leafs[ileaf];

                if (
                    node.GetLinkType(ileaf) == SolarixGrammarEngineNET.GrammarEngineAPI.RIGHT_GENITIVE_OBJECT_link ||
                    node.GetLinkType(ileaf) == SolarixGrammarEngineNET.GrammarEngineAPI.OBJECT_link
                    )
                {
                    SetLabel(leaf, string.Format("NP:{0}", chunk_num++), true);
                }
            }
        }
        else if (id_class == SolarixGrammarEngineNET.GrammarEngineAPI.PREPOS_ru)
        {
            SetLabel(node, string.Format("PN:{0}", chunk_num++), true);

            for (int ileaf = 0; ileaf < node.leafs.Count; ++ileaf)
            {
                SolarixGrammarEngineNET.SyntaxTreeNode leaf = node.leafs[ileaf];

                int p_ekey2   = leaf.GetEntryID();
                int id_class2 = gren.GetEntryClass(p_ekey2);
                if (
                    id_class2 == SolarixGrammarEngineNET.GrammarEngineAPI.NOUN_ru ||
                    id_class2 == SolarixGrammarEngineNET.GrammarEngineAPI.ADJ_ru ||
                    id_class2 == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN_ru ||
                    id_class2 == SolarixGrammarEngineNET.GrammarEngineAPI.PRONOUN2_ru ||
                    id_class2 == SolarixGrammarEngineNET.GrammarEngineAPI.NUMBER_ru
                    )
                {
                    SetLabel(leaf, string.Format("NP:{0}", chunk_num++), true);
                }
            }
        }
        else if (
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.IMPERSONAL_VERB_ru ||
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.VERB_ru ||
            id_class == SolarixGrammarEngineNET.GrammarEngineAPI.INFINITIVE_ru
            )
        {
            SetLabel(node, string.Format("VP:{0}", chunk_num++), true);
            SetLabel(node, string.Format("VX:{0}", chunk_num++), false); // корневой глагол отмечаем как VX

            for (int ileaf = 0; ileaf < node.leafs.Count; ++ileaf)
            {
                SolarixGrammarEngineNET.SyntaxTreeNode leaf = node.leafs[ileaf];

                if (node.GetLinkType(ileaf) == SolarixGrammarEngineNET.GrammarEngineAPI.SUBJECT_link)
                {
                    SetLabel(leaf, string.Format("NP:{0}", chunk_num++), true);
                }
                else if (node.GetLinkType(ileaf) == SolarixGrammarEngineNET.GrammarEngineAPI.OBJECT_link)
                {
                    SetLabel(leaf, string.Format("NP:{0}", chunk_num++), true);
                }
            }
        }

        for (int ileaf = 0; ileaf < node.leafs.Count; ++ileaf)
        {
            SolarixGrammarEngineNET.SyntaxTreeNode leaf = node.leafs[ileaf];
            ProcessTree(leaf, gren);
        }

        return;
    }
    public bool ProcessSample(string line)
    {
        int occurence_count = 0;

        // Морфологический разбор
        using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY))
        {
            for (int i = 1; i < tokens.Count - 1; ++i)
            {
                SolarixGrammarEngineNET.SyntaxTreeNode token = tokens[i];
                string word = token.GetWord().ToLower();

                if (retrieve_omonyms_from_samples)
                {
                    if (omonyms.Contains(word))
                    {
                        occurence_count++;
                        omonym_processors[word].ProcessSample(line, tokens, LanguageID, gren);
                    }
                    else if (!not_omonyms.Contains(word) && omonyms.Count < MaxOmonymPerSession)
                    {
                        bool is_omonym = false;

                        if (!ignore_omonyms.Contains(word))
                        {
                            // сделаем проекцию слова
                            int id_class0 = -1;
                            using (SolarixGrammarEngineNET.WordProjections projs = gren.FindWordForm(word))
                            {
                                for (int j = 0; j < projs.Count; ++j)
                                {
                                    int id_entry = projs.GetEntryKey(j);
                                    int id_class = gren.GetEntryClass(id_entry);
                                    if (id_class0 == -1)
                                    {
                                        id_class0 = id_class;
                                    }
                                    else if (id_class0 != id_class)
                                    {
                                        is_omonym = true;
                                        break;
                                    }
                                }
                            }

                            if (is_omonym)
                            {
                                omonyms.Add(word);
                                OmonymProcessor processor = new OmonymProcessor(word);
                                omonym_processors.Add(word, processor);

                                occurence_count++;
                                omonym_processors[word].ProcessSample(line, tokens, LanguageID, gren);
                            }
                            else
                            {
                                not_omonyms.Add(word);
                            }
                        }
                    }
                }
                else if (omonyms.Contains(word))
                {
                    occurence_count++;
                    omonym_processors[word].ProcessSample(line, tokens, LanguageID, gren);
                }
            }
        }

        return(occurence_count > 0);
    }