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; }
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); }