public int FindNumOfMultipliers()
        {
            RingPolynomial poly = this;

            RingBint[,] matrix = new RingBint[poly.degree, poly.degree - 1]; // транспонированное заполнение матрицы
            RingBint[][] decomposingPoly;
            for (int i = 1; i < poly.degree; i++)
            {
                RingPolynomial edinica = new RingPolynomial()
                {
                    [i * (int)RingBint.mod] = 1
                };
                var reminder = (edinica / poly).Reminder;
                for (int j = 0; j < poly.degree; j++)
                {
                    matrix[j, i - 1] = reminder[j];
                }
                matrix[i, i - 1] -= 1;
            }
            decomposingPoly = RingMatrix.SolveHSLE(matrix);
            return(decomposingPoly.Length);
        }
        public RingDecomposeList BerlekampFactor()
        {
            Program.recDepth++;
            RingPolynomial poly = this.Normalize();

            if (poly.degree < 2) // если многочлен меньше второй степени, то и раскладывать смысла нет
            {
                Program.Log("Разложение для " + poly + " не требуется.");
                //end
                Program.recDepth--;
                return(new RingDecomposeList {
                    poly
                });
            }

            Program.Log("Поиск разложения для многочлена:");
            if (Program.LogEnabled)
            {
                poly.Print('a');
            }
            RingDecomposeList factorRes = new RingDecomposeList(); // результат - список делителей

            factorRes.polyCoef = poly[poly.degree];
            poly *= 1 / factorRes.polyCoef;

            // 1) убираем кратные множители
            bool recheckPower = false;

            RingPolynomial multipleFators, newFactors;

            GCD(poly, poly.Derivative(), out multipleFators);
            if (multipleFators.degree > 0)
            {
                //1.1) Обнаружены кратные множители. Разделение исходного многочлена a(x) на b(x) * c(x)
                //     - c(x) гарантированно не содержит кратных корней
                //     - b(x) - это оставшаяся часть обрабатывается пробным делением в конце алгоритма
                multipleFators *= (new RingBint(1) / multipleFators[multipleFators.degree]);
                Program.Log("Обнаружены кратные множители. b(x) = " + multipleFators);
                poly         = (poly / multipleFators).Quotient; //текущий многочлен теперь c(x)
                recheckPower = true;
            }

            newFactors     = multipleFators;
            multipleFators = new RingPolynomial();
            while (multipleFators != newFactors && newFactors.degree > 0)
            {
                multipleFators = newFactors;
                GCD(multipleFators, multipleFators.Derivative(), out newFactors);
            }
            if (multipleFators == newFactors)
            {
                // 1.2) особый случай, когда производная равна 0. Тогда f(x) = g(x)^p, но тогда f(x) = g(x^p) - воспользуемся этим
                Program.Log("Обнаружена общая степень кратная модулю поля (" + RingBint.mod + ")");
                RingPolynomial g = new RingPolynomial((newFactors.size - 1) / (int)RingBint.mod + 1);
                for (int i = 0; i < g.size; i++)
                {
                    g[i] = newFactors[i * (int)RingBint.mod];
                }
                g *= 1 / g[g.degree];
                RingDecomposeList gFactorRes = g.BerlekampFactor();
                factorRes.AddRange(gFactorRes);
                recheckPower = true;
            }

            // 2) Обработка c(x)
            Program.Log("Разложение многочлена без кратных корней c(x) = " + poly);
            if (poly.degree < 2) // если многочлен меньше второй степени, то и раскладывать смысла нет
            {
                Program.Log("Разложение для " + poly + " не требуется.");
                if (poly.degree == 1)
                {
                    factorRes.Add(poly);
                }
                else
                {
                    factorRes.polyCoef *= poly[0];
                }
                //end
                if (recheckPower)
                {
                    for (int i = 0; i < factorRes.CountUniq; i++)
                    {
                        RingPolynomial divisor = factorRes.divisors[i].poly;
                        int            count   = 1;
                        RingPolynomial temp    = divisor;
                        while (true)
                        {
                            temp *= divisor;
                            if ((this / temp).Reminder.IsNull())
                            {
                                count++;
                            }
                            else
                            {
                                break;
                            }
                        }

                        while (count > factorRes.divisors[i].count)
                        {
                            factorRes.Add(factorRes.divisors[i].poly);
                        }
                    }
                }
                Program.Log("Общее разложение на данном этапе: ");
                PrintDecompositionResult(factorRes);
                Program.recDepth--;
                return(factorRes);
            }
            // 2.1) Построение матрицы и нахождение ФСР ОСЛУ
            RingBint[,] matrix = new RingBint[poly.degree, poly.degree - 1]; // транспонированное заполнение матрицы
            RingBint[][] decomposingPoly;
            for (int i = 1; i < poly.degree; i++)
            {
                RingPolynomial edinica = new RingPolynomial()
                {
                    [i * (int)RingBint.mod] = 1
                };
                var reminder = (edinica / poly).Reminder;
                for (int j = 0; j < poly.degree; j++)
                {
                    matrix[j, i - 1] = reminder[j];
                }
                matrix[i, i - 1] -= 1;
            }
            decomposingPoly = RingMatrix.SolveHSLE(matrix);

            // 2.2) рекурсивное разложение с помощью разлазающих многочленов (в статической переменной)
            if (decomposingPoly.Length > 0)
            {
                _BerlekampDecomposingPoly = decomposingPoly;

                RingBint leadingCoeff = poly[poly.degree];
                poly *= 1 / (RingBint)leadingCoeff; //normalize senior coeff
                var decomposeResult = BerlekampDecompose(poly);

                factorRes.AddRange(decomposeResult);
                factorRes.polyCoef *= leadingCoeff;
            }
            else
            {
                //end
                Program.Log("Разложение для " + poly + " не требуется. Многочлен неприводимый.");
                factorRes.Add(poly);
                if (recheckPower)
                {
                    for (int i = 0; i < factorRes.CountUniq; i++)
                    {
                        RingPolynomial divisor = factorRes.divisors[i].poly;
                        int            count   = 1;
                        RingPolynomial temp    = divisor;
                        while (true)
                        {
                            temp *= divisor;
                            if ((this / temp).Reminder.IsNull())
                            {
                                count++;
                            }
                            else
                            {
                                break;
                            }
                        }

                        while (count > factorRes.divisors[i].count)
                        {
                            factorRes.Add(factorRes.divisors[i].poly);
                        }
                    }
                }

                Program.Log("Общее разложение на данном этапе: ");
                PrintDecompositionResult(factorRes);
                Program.recDepth--;
                return(factorRes);
            }

            //end
            if (recheckPower)
            {
                for (int i = 0; i < factorRes.CountUniq; i++)
                {
                    RingPolynomial divisor = factorRes.divisors[i].poly;
                    int            count   = 1;
                    RingPolynomial temp    = divisor;
                    while (true)
                    {
                        temp *= divisor;
                        if ((this / temp).Reminder.IsNull())
                        {
                            count++;
                        }
                        else
                        {
                            break;
                        }
                    }

                    while (count > factorRes.divisors[i].count)
                    {
                        factorRes.Add(factorRes.divisors[i].poly);
                    }
                }
            }
            Program.Log("Общее разложение на данном этапе: ");
            PrintDecompositionResult(factorRes);

            Program.recDepth--;
            return(factorRes);
        }