public static RingDecomposeList HenselLifting(IntPolynomial f, RingDecomposeList fFactorization, List <RingPolynomial> GCDCoeffs, int liftingDegree)
        {
            IntPolynomial hasSquares;

            IntPolynomial.GCD(f, f.Derivative(), out hasSquares);
            IntPolynomial SquareFreef = (f / hasSquares).Quotient;
            BigInteger    squareCoeff = hasSquares[hasSquares.size - 1];

            SquareFreef *= squareCoeff;

            BigInteger p = RingBint.mod;

            BigInteger           OriginalCoeff = SquareFreef[SquareFreef.size - 1];
            List <IntPolynomial> LiftingList   = new List <IntPolynomial>();

            for (int i = 0; i < fFactorization.CountUniq; i++)
            {
                LiftingList.Add(new IntPolynomial(fFactorization[i]));
            }
            LiftingList[0] *= OriginalCoeff;

            for (int t = 1; t < liftingDegree; t++)
            {
                IntPolynomial multiplyFactor = new IntPolynomial {
                    1
                };
                for (int i = 0; i < LiftingList.Count; i++)
                {
                    multiplyFactor *= new IntPolynomial(LiftingList[i]);
                }

                var            temp = SquareFreef - multiplyFactor;
                RingPolynomial d    = new RingPolynomial(temp / BigInteger.Pow(p, t));


                for (int i = 0; i < fFactorization.CountUniq; i++)
                {
                    RingPolynomial CurrUniqPoly = fFactorization[i];
                    if (i == 0)
                    {
                        CurrUniqPoly *= fFactorization.polyCoef;
                    }
                    RingPolynomial Gc = (d * GCDCoeffs[i] / CurrUniqPoly).Reminder;
                    SetModContext(p, t + 1);
                    LiftingList[i] = LiftingList[i] + new IntPolynomial(Gc) * BigInteger.Pow(p, t);
                    SetModContext(p);
                }
                Program.Log("Разложение поднято до " + BigInteger.Pow(p, t + 1));
            }
            SetModContext(p, liftingDegree);
            RingDecomposeList liftigRes = new RingDecomposeList();

            for (int i = 0; i < LiftingList.Count; i++)
            {
                liftigRes.Add(new RingPolynomial(LiftingList[i]));
            }
            liftigRes.polyCoef = OriginalCoeff;
            return(liftigRes);
        }
 public virtual void AddRange(RingDecomposeList polys)
 {
     foreach (var divisor in polys.divisors)
     {
         for (int i = 0; i < divisor.count; i++)
         {
             Add(divisor.poly);
         }
     }
     polyCoef *= polys.polyCoef;
 }
예제 #3
0
        public RingDecomposeList FactorIntPolynomialOverBigModule(out RingDecomposeList fFactorization)
        {
            IntPolynomial f = this;
            IntPolynomial hasSquares;

            IntPolynomial.GCD(f, f.Derivative(), out hasSquares);
            IntPolynomial SquareFreef = (f / hasSquares).Quotient;

            RingDecomposeList LiftedFactorisation;

            if (SquareFreef.degree > 1)
            {
                BigInteger mod = SelectAppropriateMod(f, SquareFreef);
                RingPolynomial.SetModContext(mod);
                RingPolynomial fRing = new RingPolynomial(f);
                fFactorization = fRing.BerlekampFactor();
                List <RingPolynomial> GCDCoeffs = RingPolynomial.GetGCDCoefficientForHensel(fFactorization);

                LiftedFactorisation          = RingPolynomial.HenselLiftingUntilTheEnd(f, fFactorization, GCDCoeffs);
                LiftedFactorisation.polyCoef = f[f.size - 1];
            }
            else
            {
                RingPolynomial.SetModContext(5);
                // f состоит из кратных множителей первой степени
                LiftedFactorisation = new RingDecomposeList();
                BigInteger    coeff      = SquareFreef.CoeffGCD();
                IntPolynomial Multiplier = SquareFreef / coeff;

                // находим наибольшее число в f, чтобы подобрать модуль
                BigInteger biggestCoeff = f[0];
                for (int i = 0; i < f.size; i++)
                {
                    if (f[i] > biggestCoeff)
                    {
                        biggestCoeff = f[i];
                    }
                }

                BigInteger mod = getNextPrime(biggestCoeff);
                RingPolynomial.SetModContext(mod);

                for (int i = 0; i < f.size - 1; i++)
                {
                    LiftedFactorisation.Add(new RingPolynomial(Multiplier));
                }
                LiftedFactorisation.polyCoef *= (RingBint)coeff;
                fFactorization = LiftedFactorisation;
            }
            return(LiftedFactorisation);
        }
        static RingDecomposeList BerlekampDecompose(RingPolynomial poly)
        {
            RingDecomposeList res = new RingDecomposeList {
                poly
            };

            Program.Log("Поиск " + (_BerlekampDecomposingPoly.Length + 1) + " множителей с помощью разлагающих многочленов для:");
            poly.Print('c');
            Program.Log("Найденые множители:");
            for (int m = 0; m < res.CountUniq; m++)
            {
                for (int i = 0; i < _BerlekampDecomposingPoly.Length; i++)
                {
                    RingPolynomial oneDecomposePoly = new RingPolynomial(_BerlekampDecomposingPoly[i]);

                    for (int j = 0; j < RingBint.mod; j++)
                    {
                        RingPolynomial gcd_result;
                        GCD(res[m], oneDecomposePoly, out gcd_result);
                        gcd_result *= (new RingBint(1) / gcd_result[gcd_result.degree]);
                        if (gcd_result.degree > 0)
                        {
                            if (gcd_result == res[m])
                            {
                                break;
                            }
                            else
                            {
                                res.Add(gcd_result);
                                res[m] = (res[m] / gcd_result).Quotient;
                                if (res.CountUniq == _BerlekampDecomposingPoly.Length + 1)
                                {
                                    for (; m < res.CountUniq; m++)
                                    {
                                        res[m].Print('g');
                                    }
                                    Program.Log("На данный момент найдены все множители (" + res.CountUniq + "). Выход.");
                                    return(res);
                                }
                            }
                        }

                        oneDecomposePoly[0] += 1;
                    }
                }
                res[m].Print('g');
            }

            return(res);
        }
 static void PrintDecompositionResult(RingDecomposeList factorRes)
 {
     if (Program.LogEnabled)
     {
         for (int i = 0; i < factorRes.CountUniq; i++)
         {
             factorRes[i].Print('g');
             if (factorRes.divisors[i].count > 1)
             {
                 Program.Log("\tКратность множителя: " + factorRes.divisors[i].count);
             }
         }
     }
 }
 public RingDecomposeList(RingDecomposeList list)
 {
     polyCoef = list.polyCoef;
     divisors = new List <Divisor>(list.divisors);
 }
        public static RingDecomposeList HenselLiftingUntilTheEnd(IntPolynomial f, RingDecomposeList fFactorization, List <RingPolynomial> GCDCoeffs)
        {
            IntPolynomial hasSquares;

            IntPolynomial.GCD(f, f.Derivative(), out hasSquares);
            IntPolynomial SquareFreef = (f / hasSquares).Quotient;
            BigInteger    squareCoeff = hasSquares[hasSquares.size - 1];

            SquareFreef *= squareCoeff;

            BigInteger p = RingBint.mod;

            BigInteger OriginalCoeff = f[f.size - 1];
            BigInteger biggestCoeff  = SquareFreef[0];

            for (int i = 1; i < SquareFreef.size; i++)
            {
                if (SquareFreef[i] > biggestCoeff)
                {
                    biggestCoeff = SquareFreef[i];
                }
            }
            List <IntPolynomial> LiftingList = new List <IntPolynomial>();

            for (int i = 0; i < fFactorization.CountUniq; i++)
            {
                LiftingList.Add(new IntPolynomial(fFactorization[i]));
            }
            LiftingList[0] *= OriginalCoeff;
            bool Decomposed = false;

            int        t       = 1;
            BigInteger currMod = p;

            while (!Decomposed)
            {
                currMod = BigInteger.Pow(p, t + 1);
                IntPolynomial multiplyFactor = new IntPolynomial {
                    1
                };
                for (int i = 0; i < LiftingList.Count; i++)
                {
                    multiplyFactor *= LiftingList[i];
                }

                var            temp = SquareFreef - multiplyFactor;
                RingPolynomial d    = new RingPolynomial(temp / BigInteger.Pow(p, t));


                for (int i = 0; i < fFactorization.CountUniq; i++)
                {
                    RingPolynomial CurrUniqPoly = new RingPolynomial(fFactorization[i]);
                    if (i == 0)
                    {
                        CurrUniqPoly *= fFactorization.polyCoef;
                    }
                    RingPolynomial Gc = ((d * GCDCoeffs[i]) / CurrUniqPoly).Reminder;
                    SetModContext(p, t + 1);
                    LiftingList[i] = LiftingList[i] + new IntPolynomial(Gc) * BigInteger.Pow(p, t);
                    SetModContext(p);
                }
                t++;
                Program.Log("Разложение поднято до " + currMod);
                if (currMod > biggestCoeff)
                {
                    SetModContext(p, t);
                    RingPolynomial res = new RingPolynomial {
                        1
                    };
                    RingPolynomial FirstWithoutCoeff = new RingPolynomial(LiftingList[0]) / LiftingList[0][LiftingList[0].degree];
                    for (int u = 0; u < fFactorization.CountUniq; u++)
                    {
                        for (int j = 0; j < fFactorization.divisors[u].count; j++)
                        {
                            if (j != 0 && u == 0)
                            {
                                res *= FirstWithoutCoeff;
                            }
                            else
                            {
                                res *= new RingPolynomial(LiftingList[u]);
                            }
                        }
                    }
                    IntPolynomial resInt = new IntPolynomial(res);
                    if (f == resInt)
                    {
                        Decomposed = true;
                    }
                }
            }

            SetModContext(p, t);
            RingDecomposeList liftigRes = new RingDecomposeList();

            for (int i = 0; i < LiftingList.Count; i++)
            {
                liftigRes.Add(new RingPolynomial(LiftingList[i]));
            }
            liftigRes.polyCoef = OriginalCoeff;
            return(liftigRes);
        }
        public static List <RingPolynomial> GetGCDCoefficientForHensel(RingDecomposeList fDecompose)
        {
            List <RingPolynomial> factorsOfCoeff = new List <RingPolynomial>();
            List <RingPolynomial> resultCoeff    = new List <RingPolynomial>();

            // изначально задаем все значения коэффициентов единичными
            // и множителей разложения тоже
            for (int i = 0; i < fDecompose.CountUniq; i++)
            {
                resultCoeff.Add(new RingPolynomial {
                    1
                });
                factorsOfCoeff.Add(new RingPolynomial {
                    1
                });
            }
            // запоминаем все сомножители искомого разложения
            for (int i = 0; i < fDecompose.CountUniq; i++)
            {
                for (int j = 0; j < fDecompose.CountUniq; j++)
                {
                    if (i != j)
                    {
                        factorsOfCoeff[i] *= fDecompose[j];
                    }
                }
                if (i != 0)
                {
                    // считаем, что первый множитель разложения содержит степень исходного многочлена
                    factorsOfCoeff[i] *= fDecompose.polyCoef;
                }
            }

            RingPolynomial currentGCD = new RingPolynomial();

            for (int i = 0; i < fDecompose.CountUniq - 1; i++)
            {
                GCDResult currCoefficient = GCD(factorsOfCoeff[i], factorsOfCoeff[i + 1], out currentGCD);
                // раскрываем последовательно GCD, ища GCD соседних множителей [gcd(a, b, c) = gcd(gcd(a, b), c) = gcd(currentGCD, c)]
                factorsOfCoeff[i + 1] = currentGCD;
                for (int j = 0; j < i + 1; j++)
                {
                    resultCoeff[j] *= currCoefficient.Coef1;
                }
                resultCoeff[i + 1] *= currCoefficient.Coef2;
            }

            // Заменяем коэффициенты их остатками от деления на i элемент факторизации (deg(resultCoeff[i]) < deg(fDecompose[i]))
            for (int i = 0; i < fDecompose.CountUniq; i++)
            {
                RingPolynomial currFact = new RingPolynomial(fDecompose[i]);
                if (i == 0)
                {
                    currFact *= fDecompose.polyCoef;
                }
                resultCoeff[i] = (resultCoeff[i] / currFact).Reminder;
                for (int j = 0; j < resultCoeff[i].size; j++)
                {
                    resultCoeff[i][j] /= currentGCD[currentGCD.degree];                                         // нормализуем
                }
            }

            return(resultCoeff);
        }
        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);
        }