public bool EqualTokens(ContextRecognizer y)
    {
        for (int i = 0; i < points.Count; ++i)
        {
            if (points[i] != null && !points[i].SameChecker(y.points[i]))
            {
                return(false);
            }
        }

        return(true);
    }
    // Вернет true, если данное правило более общее, чем y.
    public bool IncludesY(ContextRecognizer y)
    {
        for (int i = 0; i < points.Count; ++i)
        {
            if (points[i] != null)
            {
                if (!points[i].DoesIncludeArgument(y.points[i]))
                {
                    return(false);
                }
            }
        }

        return(true);
    }
    public OmonymContextEnumerator(SolarixGrammarEngineNET.AnalysisResults tokens, int _omonym_position, int _left_i, int _len, SolarixGrammarEngineNET.GrammarEngine2 _gren)
    {
        gren            = _gren;
        left_i          = _left_i;
        len             = _len;
        omonym_position = _omonym_position;

        recognizers = new List <ContextRecognizer>();

        // Для каждого токена, кроме омонимичной формы, генерируем список вариантов.

        // ... пока только код для контекстов длины=2
        if (len == 2)
        {
            SolarixGrammarEngineNET.SyntaxTreeNode omonym_token = tokens[left_i + omonym_position];

            OmonymTokenRecognizer omonym_point = new OmonymTokenRecognizer(omonym_position, omonym_token);

            if (omonym_position == 0)
            {
                TokenTagsEnumerator tte = new TokenTagsEnumerator(IsBoundaryToken(tokens, left_i + 1), tokens[left_i + 1], gren);

                int n = tte.Count;
                for (int i = 0; i < n; ++i)
                {
                    List <TokenRecognizer> points = new List <TokenRecognizer>();
                    points.Add(null); // это омонимичная форма
                    points.Add(tte[i]);
                    ContextRecognizer ctx_recognizer = new ContextRecognizer(points, omonym_point, gren);
                    recognizers.Add(ctx_recognizer);
                }
            }
            else
            {
                TokenTagsEnumerator tte = new TokenTagsEnumerator(IsBoundaryToken(tokens, left_i), tokens[left_i], gren);

                int n = tte.Count;
                for (int i = 0; i < n; ++i)
                {
                    List <TokenRecognizer> points = new List <TokenRecognizer>();
                    points.Add(tte[i]);
                    points.Add(null); // это омонимичная форма
                    ContextRecognizer ctx_recognizer = new ContextRecognizer(points, omonym_point, gren);
                    recognizers.Add(ctx_recognizer);
                }
            }
        }
    }
    public int DumpRules(System.IO.TextWriter dest, int LanguageID, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        int counter = 0;

        // Выводим все правила (todo - надо только самые общие из возможных), которые ни разу не ошиблись.
        List <ContextRecognizer> good = new List <ContextRecognizer>();

        foreach (ContextRecognizer r in recognizers)
        {
            if (!r.HasEverFailed())
            {
                good.Add(r);
            }
        }

        // теперь оставим в этом списке только ортогональные правила.
        List <ContextRecognizer> orthogonal = new List <ContextRecognizer>();

        for (int i = 0; i < good.Count; ++i)
        {
            ContextRecognizer x = good[i];

            bool is_orthogonal = true;

            for (int j = 0; j < good.Count; ++j)
            {
                if (i != j && good[j].IncludesY(x))
                {
                    is_orthogonal = false;
                    break;
                }
            }

            if (is_orthogonal)
            {
                orthogonal.Add(x);
            }
        }

        foreach (ContextRecognizer r in orthogonal)
        {
            counter += r.DumpRule(dest, LanguageID, gren);
        }

        return(counter);
    }
    public void ProcessSample(string line, SolarixGrammarEngineNET.AnalysisResults tokens, int left_i, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        // В контекст входят слова от left_i по left_i+ctx.len.

        /*
         * // ---- DEBUG
         * System.Text.StringBuilder b = new StringBuilder();
         * for( int i=0; i<ctx.len; ++i )
         * if( i>0 )
         *  b.AppendFormat( " {0}", tokens[left_i+i].GetWord() );
         * else
         *  b.AppendFormat( "{0}", tokens[left_i+i].GetWord() );
         *
         * string context_str = b.ToString();
         * // --- END DEBUG
         */

        // ... todo проверяем, не сопоставляются ли слова с уже имеющимися контекстами.
        for (int i = 0; i < recognizers.Count; ++i)
        {
            ContextRecognizer recognizer = recognizers[i];
            int match = recognizer.Match(tokens, left_i, gren);
            if (match == 1)
            {
                // правило правильно распознало контекст и сняло омонимию.
                recognizer.Success(new MatchedContextInfo(line, tokens, left_i, ctx.len));
            }
            else if (match == 0)
            {
                // правило распознало контекст, но неправильно сняло омонимию.
                recognizer.Fail(new MatchedContextInfo(line, tokens, left_i, ctx.len));
            }
        }

        // Используем сэмпл для генерации правил только в том случае, если омонимичный токен дал 1 вариант словарной статьи.
        bool generate_rule = true;
        int  omonym_ekey   = -1;

        SolarixGrammarEngineNET.SyntaxTreeNode omonym_token = tokens[left_i + ctx.position];
        int omonym_versions = omonym_token.VersionCount();

        for (int iver = 0; iver < omonym_versions; ++iver)
        {
            int ekey = omonym_token.GetVersionEntryID(iver);
            if (omonym_ekey == -1)
            {
                omonym_ekey = ekey;
            }
            else if (omonym_ekey != ekey)
            {
                // омонимичный токен распознан как несколько разных лемм, поэтому не будет генерировать для него правила.
                generate_rule = false;
                break;
            }
        }

        if (generate_rule)
        {
            // Генерируем варианты распознавания контекста, начиная от самого конкретного - через лексемы не-мононимичных слов, для самых
            // общих - частей речи для них же.
            OmonymContextEnumerator ctx_generator = new OmonymContextEnumerator(tokens, ctx.position, left_i, ctx.len, gren);

            for (int i = 0; i < ctx_generator.Count; ++i)
            {
                ContextRecognizer recognizer = ctx_generator[i];

                // проверим, что такого распознавателя еще нет.
                bool is_unique = true;
                foreach (ContextRecognizer r in recognizers)
                {
                    if (r.EqualTokens(recognizer))
                    {
                        is_unique = false;
                        break;
                    }
                }

                if (is_unique)
                {
                    recognizer.Success(new MatchedContextInfo(line, tokens, left_i, ctx.len));
                    recognizers.Add(recognizer);
                }
            }
        }

        return;
    }