/// <summary> /// Verifica se o módulo do número especificado consiste numa potência perfeita. /// </summary> /// <param name="data">O número a testar.</param> /// <returns>Verdadeiro caso o número seja uma potência perfeita e falso no caso contrário.</returns> public bool Run(int data) { var innerData = Math.Abs(data); if (innerData == 0) { return(true); } else if (innerData == 1) { return(true); } else { var maximumTestValue = (int)Math.Floor(Math.Log(innerData) / Math.Log(2)); var primeNumbersIterator = this.primeNumbersIteratorFactory.CreatePrimeNumberIterator( maximumTestValue + 1); foreach (var prime in primeNumbersIterator) { var root = (int)Math.Floor(Math.Pow(innerData, 1.0 / prime)); var power = MathFunctions.Power(root, prime, this.integerDomain); if (power == innerData) { return(true); } } return(false); } }
/// <summary> /// Determina a potência do elemento. /// </summary> /// <param name="left">O elemento.</param> /// <param name="right">O expoente.</param> /// <returns>O resultado da potência.</returns> /// <exception cref="MathematicsException"> /// Se nenhum objecto responsável pelas operações sobre inteiros foi providenciado. /// </exception> protected virtual ObjectType Power( ObjectType left, ObjectType right) { if (this.integerNumber == null) { throw new MathematicsException("No integer number arithmetic operations class was provided."); } else { return(MathFunctions.Power(left, right, this.ring, this.integerNumber)); } }
/// <summary> /// Obtém o valor da estimativa para o valor máximo dos números primos a serem gerados. /// </summary> /// <param name="polynomialNorm">A norma do polinómio.</param> /// <param name="degree">O grau do polinómio.</param> /// <returns>O valor para o número primo máximo.</returns> private CoeffType ComputeGamma(CoeffType polynomialNorm, int degree) { var result = this.integerNumber.Successor( this.integerNumber.MapFrom(degree)); var doubleDegree = 2 * degree; result = MathFunctions.Power(result, doubleDegree, this.integerNumber); var temp = MathFunctions.Power(polynomialNorm, doubleDegree + 1, this.integerNumber); result = this.integerNumber.Multiply(result, temp); var doubleLogResult = this.logarithmAlgorithm.Run(result) * 2; doubleLogResult = Math.Ceiling(doubleLogResult); doubleLogResult = 2 * doubleLogResult * Math.Log(doubleLogResult); return(this.integerNumber.MapFrom((int)Math.Floor(doubleLogResult))); }
/// <summary> /// Calcula o produto de um dicionário com os factores e respectivas potências. /// </summary> /// <param name="factors">O dicionário com os factores e respectivas potências.</param> /// <returns>O valor do produto.</returns> private int ComputeProduct(Dictionary <int, int> factors) { var result = 1; foreach (var kvp in factors) { if (kvp.Value == 1) { result *= kvp.Key; } else if (kvp.Value == 2) { result *= kvp.Key * kvp.Key; } else { result *= MathFunctions.Power(kvp.Key, kvp.Value, this.integerEuclideanDomain); } } return(result); }
/// <summary> /// Establece os parâmetros internos com base nos argumentos externos. /// </summary> /// <param name="integerPart">A parte inteira da raiz.</param> /// <param name="rootNumberFactorization">A factorização do radicando.</param> /// <param name="multipliable">O objecto responsável pela multiplicação de coeficientes.</param> /// <exception cref="ArgumentNullException">Se algum dos argumentos for nulo.</exception> private void SetupParameters( ObjectType integerPart, Dictionary <ObjectType, int> rootNumberFactorization, IMultiplication <ObjectType> multipliable) { if (integerPart == null) { throw new ArgumentNullException("integerPart"); } else if (rootNumberFactorization == null) { throw new ArgumentNullException("rootNumberFactorization"); } else if (multipliable == null) { throw new ArgumentNullException("multipliable"); } else { this.integerPart = integerPart; this.rootNumberFactorization = new Dictionary <ObjectType, int>(rootNumberFactorization.Comparer); foreach (var fact in rootNumberFactorization) { var factDegree = fact.Value; var factSquaredValue = factDegree / 2; var factRem = factDegree % 2; this.integerPart = multipliable.Multiply( this.integerPart, MathFunctions.Power(fact.Key, factSquaredValue, multipliable)); if (factRem == 1) { rootNumberFactorization.Add(fact.Key, 1); } } } }
/// <summary> /// Obtém o último sub-resultante entre dois polinómios. /// </summary> /// <param name="first">O primeiro polinómio.</param> /// <param name="second">O segundo polinómio.</param> /// <param name="domain">O domínio responsável pelas operações sobre os coeficientes.</param> /// <returns>O polinómio que constitui o último sub-resultante.</returns> /// <exception cref="ArgumentNullException">Se algum dos argumentos for nulo.</exception> public UnivariatePolynomialNormalForm <CoeffType> Run( UnivariatePolynomialNormalForm <CoeffType> first, UnivariatePolynomialNormalForm <CoeffType> second, IEuclidenDomain <CoeffType> domain) { if (first == null) { throw new ArgumentNullException("first"); } else if (second == null) { throw new ArgumentNullException("second"); } else if (domain == null) { throw new ArgumentNullException("domain"); } else { var pseudoDomain = new UnivarPolynomPseudoDomain <CoeffType>(first.VariableName, domain); var innerFirstPol = first; var innerSecondPol = second; if (innerSecondPol.Degree > innerFirstPol.Degree) { var swap = innerFirstPol; innerFirstPol = innerSecondPol; innerSecondPol = swap; } if (!pseudoDomain.IsAdditiveUnity(innerSecondPol)) { var firstLeadingCoeff = innerFirstPol.GetLeadingCoefficient(pseudoDomain.CoeffsDomain); var tempDegree = innerFirstPol.Degree - innerSecondPol.Degree; var temp = innerSecondPol; innerSecondPol = pseudoDomain.Rem(innerFirstPol, innerSecondPol); innerSecondPol = innerSecondPol.ApplyQuo( firstLeadingCoeff, pseudoDomain.CoeffsDomain); if (tempDegree % 2 == 0) { innerSecondPol = innerSecondPol.GetSymmetric(pseudoDomain.CoeffsDomain); } innerFirstPol = temp; // Ciclo relativo à determinação do primeiro valor de c if (!pseudoDomain.IsAdditiveUnity(innerSecondPol)) { firstLeadingCoeff = innerFirstPol.GetLeadingCoefficient(pseudoDomain.CoeffsDomain); var c = MathFunctions.Power(firstLeadingCoeff, tempDegree, pseudoDomain.CoeffsDomain); tempDegree = innerFirstPol.Degree - innerSecondPol.Degree; temp = innerSecondPol; innerSecondPol = pseudoDomain.Rem(innerFirstPol, innerSecondPol); var den = MathFunctions.Power(c, tempDegree, pseudoDomain.CoeffsDomain); innerSecondPol = innerSecondPol.ApplyQuo( pseudoDomain.CoeffsDomain.Multiply(firstLeadingCoeff, den), pseudoDomain.CoeffsDomain); if (tempDegree % 2 == 0) { innerSecondPol = innerSecondPol.GetSymmetric(pseudoDomain.CoeffsDomain); } innerFirstPol = temp; // Início do ciclo para obter a sequência de sub-resultantes while (!pseudoDomain.IsAdditiveUnity(innerSecondPol)) { firstLeadingCoeff = innerFirstPol.GetLeadingCoefficient(pseudoDomain.CoeffsDomain); c = pseudoDomain.CoeffsDomain.Quo( MathFunctions.Power(firstLeadingCoeff, tempDegree, pseudoDomain.CoeffsDomain), MathFunctions.Power(c, tempDegree - 1, pseudoDomain.CoeffsDomain)); tempDegree = innerFirstPol.Degree - innerSecondPol.Degree; temp = innerSecondPol; innerSecondPol = pseudoDomain.Rem(innerFirstPol, innerSecondPol); den = MathFunctions.Power(c, tempDegree, pseudoDomain.CoeffsDomain); innerSecondPol = innerSecondPol.ApplyQuo( pseudoDomain.CoeffsDomain.Multiply(firstLeadingCoeff, den), pseudoDomain.CoeffsDomain); if (tempDegree % 2 == 0) { innerSecondPol = innerSecondPol.GetSymmetric(pseudoDomain.CoeffsDomain); } innerFirstPol = temp; } } } return(innerFirstPol); } }
/// <summary> /// Obtém o quociente e o resto da pseudo-divisão entre dois polinómios. /// </summary> /// <param name="dividend">O dividendo.</param> /// <param name="divisor">O divisor.</param> /// <returns>O quociente e o resto.</returns> /// <exception cref="ArgumentNullException">Se algum dos argumentos for nulo.</exception> /// <exception cref="ArgumentException"> /// Se algum dos polinómio contiver uma variável diferente da estipulada para o /// domínio corrente. /// </exception> public DomainResult <UnivariatePolynomialNormalForm <CoeffType> > GetQuotientAndRemainder( UnivariatePolynomialNormalForm <CoeffType> dividend, UnivariatePolynomialNormalForm <CoeffType> divisor) { if (dividend == null) { throw new ArgumentNullException("dividend"); } else if (divisor == null) { throw new ArgumentNullException("divisor"); } else if (divisor.VariableName != divisor.VariableName) { throw new ArgumentException("Polynomials must share the same variable name in order to be operated."); } else { if (divisor.Degree > dividend.Degree) { return(new DomainResult <UnivariatePolynomialNormalForm <CoeffType> >( new UnivariatePolynomialNormalForm <CoeffType>(this.variableName), dividend)); } else { var remainderSortedCoeffs = dividend.GetOrderedCoefficients(Comparer <int> .Default); var divisorSorteCoeffs = divisor.GetOrderedCoefficients(Comparer <int> .Default); var quotientCoeffs = new UnivariatePolynomialNormalForm <CoeffType>(this.variableName); var remainderLeadingDegree = remainderSortedCoeffs.Keys[remainderSortedCoeffs.Keys.Count - 1]; var divisorLeadingDegree = divisorSorteCoeffs.Keys[divisorSorteCoeffs.Keys.Count - 1]; var divisorLeadingCoeff = divisorSorteCoeffs.Values[divisorSorteCoeffs.Values.Count - 1]; var multiplyNumber = MathFunctions.Power( divisorLeadingCoeff, remainderLeadingDegree - divisorLeadingDegree + 1, this.ring); var temporaryRemainderCoeffs = new SortedList <int, CoeffType>(Comparer <int> .Default); foreach (var kvp in remainderSortedCoeffs) { temporaryRemainderCoeffs.Add( kvp.Key, this.ring.Multiply(kvp.Value, multiplyNumber)); } remainderSortedCoeffs = temporaryRemainderCoeffs; while (remainderLeadingDegree >= divisorLeadingDegree && remainderSortedCoeffs.Count > 0) { var remainderLeadingCoeff = remainderSortedCoeffs[remainderLeadingDegree]; var differenceDegree = remainderLeadingDegree - divisorLeadingDegree; var factor = this.coeffsDomain.Quo(remainderLeadingCoeff, divisorLeadingCoeff); quotientCoeffs = quotientCoeffs.Add(factor, differenceDegree, this.ring); remainderSortedCoeffs.Remove(remainderLeadingDegree); for (int i = 0; i < divisorSorteCoeffs.Keys.Count - 1; ++i) { var currentDivisorDegree = divisorSorteCoeffs.Keys[i]; var currentCoeff = this.ring.Multiply( divisorSorteCoeffs[currentDivisorDegree], factor); currentDivisorDegree += differenceDegree; var addCoeff = default(CoeffType); if (remainderSortedCoeffs.TryGetValue(currentDivisorDegree, out addCoeff)) { addCoeff = this.ring.Add( addCoeff, this.ring.AdditiveInverse(currentCoeff)); if (this.ring.IsAdditiveUnity(addCoeff)) { remainderSortedCoeffs.Remove(currentDivisorDegree); } else { remainderSortedCoeffs[currentDivisorDegree] = addCoeff; } } else { remainderSortedCoeffs.Add( currentDivisorDegree, this.ring.AdditiveInverse(currentCoeff)); } } if (remainderSortedCoeffs.Count > 0) { remainderLeadingDegree = remainderSortedCoeffs.Keys[remainderSortedCoeffs.Keys.Count - 1]; } else { remainderLeadingDegree = 0; } } var remainder = new UnivariatePolynomialNormalForm <CoeffType>( remainderSortedCoeffs, this.variableName, this.ring); return(new DomainResult <UnivariatePolynomialNormalForm <CoeffType> >( quotientCoeffs, remainder)); } } }
/// <summary> /// Averigua se o número especificado é primo. /// </summary> /// <param name="data">O número.</param> /// <returns>Verdadeiro caso o número seja primo e falso caso este seja composto.</returns> public bool Run(int data) { if (this.integerNumber.IsAdditiveUnity(data)) { return(false); } else if ( this.integerNumber.IsMultiplicativeUnity(data) || this.integerNumber.IsMultiplicativeUnity(this.integerNumber.AdditiveInverse(data))) { return(false); } else { var innerData = this.integerNumber.GetNorm(data); var two = this.integerNumber.MapFrom(2); if (this.integerNumber.Equals(innerData, two)) { return(true); } else if (this.perfectPowerTest.Run(data)) { return(false); } else { var log = Math.Log(innerData) / Math.Log(2); var r = this.EvaluateLimitValue(innerData, log); r = this.totientFunctionAlg.Run(r); var i = two; for (; this.integerNumber.Compare(i, r) <= 0; i = this.integerNumber.Successor(i)) { var gcd = MathFunctions.GreatCommonDivisor(innerData, i, this.integerNumber); if (this.integerNumber.Compare(gcd, this.integerNumber.MultiplicativeUnity) > 0 && this.integerNumber.Compare(gcd, innerData) < 0) { return(false); } } var limit = (int)Math.Floor(Math.Sqrt(r) * log); var modularField = this.modularFactory.CreateInstance(innerData); var terms = new Dictionary <int, int>(); var modularPolynomialRing = new AuxAksModArithmRing <int>( r, "x", modularField); for (int j = 1; j <= limit; ++j) { terms.Clear(); terms.Add(0, j); terms.Add(1, 1); var polynomial = new UnivariatePolynomialNormalForm <int>( terms, "x", modularField); terms.Clear(); terms.Add(0, j); terms.Add(innerData, 1); var comparisionPol = new UnivariatePolynomialNormalForm <int>( terms, "x", modularField); var poweredPol = MathFunctions.Power(polynomial, innerData, modularPolynomialRing); if (!poweredPol.Equals(modularPolynomialRing.GetReduced(comparisionPol))) { return(false); } } return(true); } } }
/// <summary> /// Processa o polinómio determinando os respectivos factores. /// </summary> /// <remarks> /// Os factores constantes são ignorados, os factores lineares são anexados ao resultado e os factores /// cujos graus são superiores são retornados para futuro processamento. Se o polinómio a ser processado /// for irredutível, é adicionado ao resultado. /// </remarks> /// <param name="polynom">O polinómio a ser processado.</param> /// <param name="result">O contentor dos factores sucessivamente processados.</param> /// <param name="integerModule">O objecto responsável pelas operações sobre inteiros.</param> /// <param name="polynomField">O objecto responsável pelas operações sobre os polinómios.</param> /// <param name="inverseAlgorithm">O algoritmo inverso.</param> /// <returns></returns> List <UnivariatePolynomialNormalForm <CoeffType> > Process( UnivariatePolynomialNormalForm <CoeffType> polynom, List <UnivariatePolynomialNormalForm <CoeffType> > result, IModularField <CoeffType> integerModule, UnivarPolynomEuclideanDomain <CoeffType> polynomField, LagrangeAlgorithm <UnivariatePolynomialNormalForm <CoeffType> > inverseAlgorithm) { var resultPol = new List <UnivariatePolynomialNormalForm <CoeffType> >(); if (polynom.Degree < 2) { result.Add(polynom); } else { var module = new ModularBachetBezoutField <UnivariatePolynomialNormalForm <CoeffType> >( polynom, inverseAlgorithm); var degree = polynom.Degree; var arrayMatrix = new ArrayMathMatrix <CoeffType>(degree, degree, integerModule.AdditiveUnity); arrayMatrix[0, 0] = integerModule.AdditiveUnity; var pol = new UnivariatePolynomialNormalForm <CoeffType>( integerModule.MultiplicativeUnity, 1, polynom.VariableName, integerModule); var integerModuleValue = this.integerNumber.ConvertToInt(integerModule.Module); pol = MathFunctions.Power(pol, integerModuleValue, module); foreach (var term in pol) { arrayMatrix[term.Key, 1] = term.Value; } var auxPol = pol; for (int i = 2; i < degree; ++i) { auxPol = module.Multiply(auxPol, pol); foreach (var term in auxPol) { arrayMatrix[term.Key, i] = term.Value; } } for (int i = 1; i < degree; ++i) { var value = arrayMatrix[i, i]; value = integerModule.Add( value, integerModule.AdditiveInverse(integerModule.MultiplicativeUnity)); arrayMatrix[i, i] = value; } var emtpyMatrix = new ZeroMatrix <CoeffType>(degree, 1, integerModule); var linearSystemSolution = this.linearSystemSolver.Run(arrayMatrix, emtpyMatrix); var numberOfFactors = linearSystemSolution.VectorSpaceBasis.Count; if (numberOfFactors < 2) { result.Add(polynom); } else { var hPol = default(UnivariatePolynomialNormalForm <CoeffType>); var linearSystemCount = linearSystemSolution.VectorSpaceBasis.Count; for (int i = 0; i < linearSystemCount; ++i) { var currentBaseSolution = linearSystemSolution.VectorSpaceBasis[i]; var rowsLength = currentBaseSolution.Length; for (int j = 1; j < rowsLength; ++j) { if (!integerModule.IsAdditiveUnity(currentBaseSolution[j])) { hPol = this.GetPolynomial(currentBaseSolution, integerModule, polynom.VariableName); j = rowsLength; } if (hPol != null) { j = rowsLength; } } if (hPol != null) { i = linearSystemCount; } } for (int i = 0, k = 0; k < numberOfFactors && i < integerModuleValue; ++i) { var converted = this.integerNumber.MapFrom(i); var currentPol = MathFunctions.GreatCommonDivisor( polynom, hPol.Subtract(converted, integerModule), polynomField); var currentDegree = currentPol.Degree; if (currentDegree == 1) { result.Add(currentPol); ++k; } else if (currentDegree > 1) { resultPol.Add(currentPol); ++k; } } } } return(resultPol); }
/// <summary> /// Determina a potência do polinómio. /// </summary> /// <param name="left">O polinómio.</param> /// <param name="right">O expoente.</param> /// <returns>O resultado da potência.</returns> /// <exception cref="MathematicsException">Se a operação falhar por vários motivos.</exception> protected virtual ParsePolynomialItem <T> Power(ParsePolynomialItem <T> left, ParsePolynomialItem <T> right) { var result = new ParsePolynomialItem <T>(); if (left.ValueType == EParsePolynomialValueType.COEFFICIENT) { if (right.ValueType == EParsePolynomialValueType.COEFFICIENT) { var degree = this.conversion.DirectConversion(right.Coeff); result.Coeff = MathFunctions.Power(left.Coeff, degree, this.ring); } else if (right.ValueType == EParsePolynomialValueType.INTEGER) { result.Coeff = MathFunctions.Power(left.Coeff, right.Degree, this.ring); } else if (right.ValueType == EParsePolynomialValueType.POLYNOMIAL) { if (right.Polynomial.IsValue) { var exponent = this.conversion.DirectConversion(right.Polynomial.GetAsValue(this.ring)); result.Coeff = MathFunctions.Power(left.Coeff, exponent, this.ring); } else { throw new MathematicsException("Polynomial exponents aren't allowed."); } } } else if (left.ValueType == EParsePolynomialValueType.INTEGER) { if (right.ValueType == EParsePolynomialValueType.COEFFICIENT) { var rightConversion = this.conversion.DirectConversion(right.Coeff); result.Degree = MathFunctions.Power(left.Degree, rightConversion, this.integerRing); } else if (right.ValueType == EParsePolynomialValueType.INTEGER) { result.Degree = MathFunctions.Power(left.Degree, right.Degree, this.integerRing); } else if (right.ValueType == EParsePolynomialValueType.POLYNOMIAL) { if (right.Polynomial.IsValue) { var exponent = this.conversion.DirectConversion(right.Polynomial.GetAsValue(this.ring)); result.Degree = MathFunctions.Power(left.Degree, exponent, this.integerRing); } else { throw new MathematicsException("Polynomial exponents aren't allowed."); } } } else if (left.ValueType == EParsePolynomialValueType.POLYNOMIAL) { if (right.ValueType == EParsePolynomialValueType.COEFFICIENT) { var exponent = this.conversion.DirectConversion(right.Coeff); result.Polynomial = left.Polynomial.Power(exponent, this.ring); } else if (right.ValueType == EParsePolynomialValueType.INTEGER) { result.Polynomial = left.Polynomial.Power(right.Degree, this.ring); } else if (right.ValueType == EParsePolynomialValueType.POLYNOMIAL) { if (right.Polynomial.IsValue) { var exponent = this.conversion.DirectConversion(right.Polynomial.GetAsValue(this.ring)); result.Polynomial = left.Polynomial.Power(exponent, this.ring); } else { throw new MathematicsException("Polynomial exponents aren't allowed."); } } } return(result); }
/// <summary> /// Executa o algoritmo que permite obter uma factorização livre de quadrados. /// </summary> /// <param name="polynomial">O polinómio de entrada.</param> /// <returns>A factorização livre de quadrados.</returns> /// <exception cref="ArgumentNullException"> /// Se o argumento for nulo. /// </exception> public SquareFreeFactorizationResult <Fraction <CoeffType>, CoeffType> Run( UnivariatePolynomialNormalForm <Fraction <CoeffType> > polynomial) { if (polynomial == null) { throw new ArgumentNullException("polynomial"); } else { var independentCoeff = this.fractionField.MultiplicativeUnity; var result = new Dictionary <int, UnivariatePolynomialNormalForm <CoeffType> >(); var currentDegree = 1; var polynomDomain = new UnivarPolynomEuclideanDomain <Fraction <CoeffType> >( polynomial.VariableName, this.fractionField); var lagAlg = new LagrangeAlgorithm <CoeffType>(this.integerNumber); var dataDerivative = polynomial.GetPolynomialDerivative(this.fractionField); var gcd = this.GreatCommonDivisor(polynomial, dataDerivative, polynomDomain); if (gcd.Degree == 0) { var lcm = this.GetDenominatorLcm(polynomial, lagAlg); if (this.integerNumber.IsMultiplicativeUnity(lcm)) { var integerPol = this.GetIntegerPol(polynomial); result.Add(currentDegree, integerPol); } else { independentCoeff = new Fraction <CoeffType>( this.integerNumber.MultiplicativeUnity, lcm, this.integerNumber); var multipliable = new Fraction <CoeffType>( lcm, this.integerNumber.MultiplicativeUnity, this.integerNumber); var multipliedPol = polynomial.Multiply(independentCoeff, this.fractionField); var integerPol = this.GetIntegerPol(multipliedPol); result.Add(currentDegree, integerPol); } } else { var polyCoffactor = polynomDomain.Quo(polynomial, gcd); var nextGcd = this.GreatCommonDivisor(gcd, polyCoffactor, polynomDomain); var squareFreeFactor = polynomDomain.Quo(polyCoffactor, nextGcd); polyCoffactor = gcd; gcd = nextGcd; if (squareFreeFactor.Degree > 0) { var lcm = this.GetDenominatorLcm(squareFreeFactor, lagAlg); if (this.integerNumber.IsMultiplicativeUnity(lcm)) { var integerPol = this.GetIntegerPol(squareFreeFactor); result.Add(currentDegree, integerPol); } else if (this.fractionField.IsAdditiveUnity(independentCoeff)) { independentCoeff = new Fraction <CoeffType>( this.integerNumber.MultiplicativeUnity, MathFunctions.Power(lcm, currentDegree, this.integerNumber), this.integerNumber); var multipliable = new Fraction <CoeffType>( lcm, this.integerNumber.MultiplicativeUnity, this.integerNumber); var multipliedPol = squareFreeFactor.Multiply(independentCoeff, this.fractionField); var integerPol = this.GetIntegerPol(multipliedPol); result.Add(currentDegree, integerPol); } else { var multiplicationCoeff = new Fraction <CoeffType>( this.integerNumber.MultiplicativeUnity, MathFunctions.Power(lcm, currentDegree, this.integerNumber), this.integerNumber); independentCoeff = this.fractionField.Multiply(independentCoeff, multiplicationCoeff); var multipliable = new Fraction <CoeffType>( lcm, this.integerNumber.MultiplicativeUnity, this.integerNumber); var multipliedPol = squareFreeFactor.Multiply(independentCoeff, this.fractionField); var integerPol = this.GetIntegerPol(multipliedPol); result.Add(currentDegree, integerPol); } } else { var value = squareFreeFactor.GetAsValue(this.fractionField); if (!this.fractionField.IsMultiplicativeUnity(value)) { if (this.fractionField.IsMultiplicativeUnity(independentCoeff)) { independentCoeff = value; } else { independentCoeff = this.fractionField.Multiply(independentCoeff, value); } } } ++currentDegree; while (gcd.Degree > 0) { polyCoffactor = polynomDomain.Quo(polyCoffactor, gcd); nextGcd = MathFunctions.GreatCommonDivisor(gcd, polyCoffactor, polynomDomain); squareFreeFactor = polynomDomain.Quo(gcd, nextGcd); gcd = nextGcd; if (squareFreeFactor.Degree > 0) { var lcm = this.GetDenominatorLcm(squareFreeFactor, lagAlg); if (this.integerNumber.IsMultiplicativeUnity(lcm)) { var integerPol = this.GetIntegerPol(squareFreeFactor); result.Add(currentDegree, integerPol); } else if (this.fractionField.IsAdditiveUnity(independentCoeff)) { independentCoeff = new Fraction <CoeffType>( this.integerNumber.MultiplicativeUnity, MathFunctions.Power(lcm, currentDegree, this.integerNumber), this.integerNumber); var multipliable = new Fraction <CoeffType>( lcm, this.integerNumber.MultiplicativeUnity, this.integerNumber); var multipliedPol = squareFreeFactor.Multiply(independentCoeff, this.fractionField); var integerPol = this.GetIntegerPol(multipliedPol); result.Add(currentDegree, integerPol); } else { var multiplicationCoeff = new Fraction <CoeffType>( this.integerNumber.MultiplicativeUnity, MathFunctions.Power(lcm, currentDegree, this.integerNumber), this.integerNumber); independentCoeff = this.fractionField.Multiply(independentCoeff, multiplicationCoeff); var multipliable = new Fraction <CoeffType>( lcm, this.integerNumber.MultiplicativeUnity, this.integerNumber); var multipliedPol = squareFreeFactor.Multiply(multipliable, this.fractionField); var integerPol = this.GetIntegerPol(multipliedPol); result.Add(currentDegree, integerPol); } } else { var value = squareFreeFactor.GetAsValue(this.fractionField); if (!this.fractionField.IsMultiplicativeUnity(value)) { if (this.fractionField.IsMultiplicativeUnity(independentCoeff)) { independentCoeff = value; } else { independentCoeff = this.fractionField.Multiply(independentCoeff, value); } } } ++currentDegree; } var cofactorValue = polyCoffactor.GetAsValue(this.fractionField); if (!this.fractionField.IsMultiplicativeUnity(cofactorValue)) { if (this.fractionField.IsMultiplicativeUnity(independentCoeff)) { independentCoeff = cofactorValue; } else { independentCoeff = this.fractionField.Multiply(independentCoeff, cofactorValue); } } } return(new SquareFreeFactorizationResult <Fraction <CoeffType>, CoeffType>( independentCoeff, result)); } }
/// <summary> /// Obtém os valores da solução. /// </summary> /// <param name="solution">A solução do sistema modular.</param> /// <param name="matrixList">A matriz.</param> /// <param name="primesList">A lista dos números primos da base.</param> /// <param name="innerData">O número que está a ser factorizado.</param> /// <returns>Os factores.</returns> private Tuple <NumberType, NumberType> GetSolution( LinearSystemSolution <int> solution, List <int[]> matrixList, List <int> primesList, NumberType innerData) { var innerDataModularField = this.modularFieldFactory.CreateInstance(innerData); var countFactors = primesList.Count - 1; foreach (var solutionBase in solution.VectorSpaceBasis) { var firstValue = this.integerNumber.MultiplicativeUnity; var factorsCount = new Dictionary <int, int>(); for (int i = 0; i < matrixList.Count; ++i) { var currentMatrixLine = matrixList[i]; if (solutionBase[i] == 1) { firstValue = innerDataModularField.Multiply( firstValue, this.integerNumber.GetNorm(this.integerNumber.MapFrom(currentMatrixLine[currentMatrixLine.Length - 1]))); for (int j = 0; j < countFactors; ++j) { if (currentMatrixLine[j] != 0) { var countValue = 0; if (factorsCount.TryGetValue(primesList[j], out countValue)) { countValue += currentMatrixLine[j]; factorsCount[primesList[j]] = countValue; } else { factorsCount.Add(primesList[j], currentMatrixLine[j]); } } } } } var secondValue = this.integerNumber.MultiplicativeUnity; foreach (var factorCountKvp in factorsCount) { var primePower = MathFunctions.Power( this.integerNumber.MapFrom(factorCountKvp.Key), factorCountKvp.Value / 2, innerDataModularField); secondValue = innerDataModularField.Multiply( secondValue, primePower); } if (!this.integerNumber.Equals(firstValue, secondValue)) { var firstFactor = MathFunctions.GreatCommonDivisor( innerData, this.integerNumber.GetNorm(this.integerNumber.Add(firstValue, this.integerNumber.AdditiveInverse(secondValue))), this.integerNumber); if (!this.integerNumber.IsMultiplicativeUnity(firstFactor)) { var secondFactor = this.integerNumber.Quo(innerData, firstFactor); return(Tuple.Create(firstFactor, secondFactor)); } } } return(Tuple.Create(this.integerNumber.MultiplicativeUnity, innerData)); }
/// <summary> /// Determina o resíduo quadrático de um número módulo o número primo ímpar especificado. /// </summary> /// <remarks> /// Se o módulo não for um número primo ímpar, os resultados estarão errados. Esta verificação /// não é realizada sobre esse módulo. /// </remarks> /// <param name="number">O número.</param> /// <param name="primeModule">O número primo que servirá de módulo.</param> /// <returns>A lista com os dois resíduos.</returns> /// <exception cref="ArgumentException"> /// Se o módulo não for superior a dois, se o módulo for par ou se a solução não existir. /// </exception> public List <NumberType> Run(NumberType number, NumberType primeModule) { var two = this.integerNumber.MapFrom(2); if (this.integerNumber.Compare(primeModule, two) < 0) { throw new ArgumentException("The prime module must be a number greater than two."); } if (this.integerNumber.IsAdditiveUnity(this.integerNumber.Rem(primeModule, two))) { throw new ArgumentException("The prime module must be an even number."); } else if (!this.integerNumber.IsMultiplicativeUnity(this.legendreJacobiSymAlg.Run(number, primeModule))) { throw new ArgumentException("Solution doesn't exist."); } else { var innerNumber = this.integerNumber.Rem(number, primeModule); var firstStepModule = this.integerNumber.Predecessor(primeModule); var power = this.integerNumber.AdditiveUnity; var remQuoResult = this.integerNumber.GetQuotientAndRemainder(firstStepModule, two); while (this.integerNumber.IsAdditiveUnity(remQuoResult.Remainder)) { power = this.integerNumber.Successor(power); firstStepModule = remQuoResult.Quotient; remQuoResult = this.integerNumber.GetQuotientAndRemainder(firstStepModule, two); } var modularIntegerField = this.modularFieldFactory.CreateInstance(primeModule); if (this.integerNumber.IsMultiplicativeUnity(power)) { var tempPower = this.integerNumber.Successor(primeModule); tempPower = this.integerNumber.Quo(tempPower, this.integerNumber.MapFrom(4)); var value = MathFunctions.Power(number, tempPower, modularIntegerField, this.integerNumber); var result = new List <NumberType>() { value, this.integerNumber.Add(primeModule, this.integerNumber.AdditiveInverse(value)) }; return(result); } else { var nonQuadraticResidue = this.FindNonQuadraticResidue(primeModule); var poweredNonQuadraticResult = MathFunctions.Power( nonQuadraticResidue, firstStepModule, modularIntegerField, this.integerNumber); var innerPower = this.integerNumber.Successor(firstStepModule); innerPower = this.integerNumber.Quo(innerPower, two); var result = MathFunctions.Power(innerNumber, innerPower, modularIntegerField, this.integerNumber); var temp = MathFunctions.Power(innerNumber, firstStepModule, modularIntegerField, this.integerNumber); while (!this.integerNumber.IsMultiplicativeUnity(temp)) { var lowestIndex = this.FindLowestIndex(temp, power, modularIntegerField); var aux = this.SquareValue( poweredNonQuadraticResult, this.integerNumber.Add(power, this.integerNumber.AdditiveInverse(this.integerNumber.Successor(lowestIndex))), modularIntegerField); result = modularIntegerField.Multiply(result, aux); aux = modularIntegerField.Multiply(aux, aux); temp = modularIntegerField.Multiply(temp, aux); poweredNonQuadraticResult = aux; power = lowestIndex; } return(new List <NumberType>() { result, this.integerNumber.Add(primeModule, this.integerNumber.AdditiveInverse(result)) }); } } }
/// <summary> /// Determina o corte de um número sobre as potências de um número primo. /// </summary> /// <param name="value">O valor do qual se pretende obter o corte.</param> /// <param name="prime">O número primo.</param> /// <param name="firstExponent">O expoente inferior do corte.</param> /// <param name="secondExponent">O expoente superior do corte.</param> /// <returns>O resultado do corte.</returns> private CoeffType ComputeTwoSidedCut( CoeffType value, CoeffType prime, CoeffType firstExponent, CoeffType secondExponent) { var difference = this.integerNumber.Add( secondExponent, this.integerNumber.AdditiveInverse(firstExponent)); if (this.integerNumber.Compare(firstExponent, difference) < 0) { // Cálculo da primeira potência. var firstExponentFactor = MathFunctions.Power( prime, firstExponent, this.integerNumber, this.integerNumber); // Cálculo da segunda potência com base na primeira. var increment = this.integerNumber.Add( firstExponent, this.integerNumber.AdditiveInverse(difference)); var differenceExponentFactor = MathFunctions.Power( prime, increment, this.integerNumber, this.integerNumber); differenceExponentFactor = this.integerNumber.Multiply( differenceExponentFactor, firstExponentFactor); var result = this.integerNumber.Rem(value, firstExponentFactor); result = this.integerNumber.Add( value, this.integerNumber.AdditiveInverse(result)); result = this.integerNumber.Quo(result, firstExponentFactor); result = this.integerNumber.Rem(result, differenceExponentFactor); return(result); } else { // Cálculo da primeira potência. var differenceExponentFactor = MathFunctions.Power( prime, difference, this.integerNumber, this.integerNumber); // Cálculo da segunda potência com base na primeira. var increment = this.integerNumber.Add( difference, this.integerNumber.AdditiveInverse(firstExponent)); var firstExponentFactor = MathFunctions.Power( prime, increment, this.integerNumber, this.integerNumber); firstExponentFactor = this.integerNumber.Multiply( firstExponentFactor, firstExponentFactor); var result = this.integerNumber.Rem(value, firstExponentFactor); result = this.integerNumber.Add( value, this.integerNumber.AdditiveInverse(result)); result = this.integerNumber.Quo(result, firstExponentFactor); result = this.integerNumber.Rem(result, differenceExponentFactor); return(result); } }
/// <summary> /// Permite calcular a aproximação de Mignotte relativamente à factorização de polinómios. /// </summary> /// <remarks> /// A aproximaçáo calculada consiste num limite superior para os coeficientes de um polinómio /// módulo a potência de um número primo caso este seja factor do polinómio proposto. /// </remarks> /// <param name="polynomialNorm">A norma do polinómio.</param> /// <param name="leadingCoeff">O coeficiente principal do polinómio.</param> /// <param name="degree">O grau do polinómio.</param> /// <returns>O valor da aproximação.</returns> private CoeffType ComputeMignotteApproximation( CoeffType polynomialNorm, CoeffType leadingCoeff, int degree) { var result = MathFunctions.Power(this.integerNumber.MapFrom(2), degree, this.integerNumber); result = this.integerNumber.Multiply(result, leadingCoeff); result = this.integerNumber.Multiply(result, polynomialNorm); // Utilização da expansão em série para a determinação do valor inteiro da raiz quadrada. // a_1=1, b_1=2, a_{n+1}=-(2n+1)a_n, b_{n+1}=2(n+1)b_n var integerSquareRoot = this.integerNumber.MapFrom(this.integerSquareRootAlgorithm.Run(degree + 1)); var difference = this.integerNumber.Multiply(integerSquareRoot, integerSquareRoot); var squared = this.integerNumber.Multiply(integerSquareRoot, integerSquareRoot); difference = this.integerNumber.Add( this.integerNumber.MapFrom(degree + 1), this.integerNumber.AdditiveInverse(squared)); if (this.integerNumber.IsAdditiveUnity(difference)) { result = this.integerNumber.Multiply(result, integerSquareRoot); } else { var db = this.integerNumber.MapFrom(2); var numMult = this.integerNumber.MultiplicativeUnity; var denMult = this.integerNumber.MultiplicativeUnity; var sign = true; var numeratorCoeff = this.integerNumber.Multiply(result, difference); var denominatorCoeff = db; denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, integerSquareRoot); var gcd = MathFunctions.GreatCommonDivisor(numeratorCoeff, denominatorCoeff, this.integerNumber); if (!this.integerNumber.IsMultiplicativeUnity(gcd)) { numeratorCoeff = this.integerNumber.Quo(numeratorCoeff, gcd); denominatorCoeff = this.integerNumber.Quo(denominatorCoeff, gcd); } result = this.integerNumber.Multiply(result, integerSquareRoot); if (this.integerNumber.Compare(numeratorCoeff, denominatorCoeff) > 0) { // Adicionar a primeira parcela da expansão em série. var divide = this.integerNumber.Quo(numeratorCoeff, denominatorCoeff); if (!sign) { divide = this.integerNumber.AdditiveInverse(divide); } result = this.integerNumber.Add(result, divide); // Actualiza com a nova informação. sign = !sign; denMult = this.integerNumber.Successor(denMult); numeratorCoeff = this.integerNumber.Multiply(numeratorCoeff, difference); numeratorCoeff = this.integerNumber.Multiply(numeratorCoeff, numMult); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, denMult); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, squared); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, db); gcd = MathFunctions.GreatCommonDivisor(numeratorCoeff, denominatorCoeff, this.integerNumber); if (!this.integerNumber.IsMultiplicativeUnity(gcd)) { numeratorCoeff = this.integerNumber.Quo(numeratorCoeff, gcd); denominatorCoeff = this.integerNumber.Quo(denominatorCoeff, gcd); } while (this.integerNumber.Compare(numeratorCoeff, denominatorCoeff) > 0) { // Adicionar a primeira parcela da expansão em série. divide = this.integerNumber.Quo(numeratorCoeff, denominatorCoeff); if (!sign) { divide = this.integerNumber.AdditiveInverse(divide); } result = this.integerNumber.Add(result, divide); // Actualiza com a nova informação. sign = !sign; numMult = this.integerNumber.Successor(this.integerNumber.Successor(numMult)); denMult = this.integerNumber.Successor(denMult); numeratorCoeff = this.integerNumber.Multiply(numeratorCoeff, difference); numeratorCoeff = this.integerNumber.Multiply(numeratorCoeff, numMult); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, denMult); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, squared); denominatorCoeff = this.integerNumber.Multiply(denominatorCoeff, db); this.integerNumber.Multiply(denominatorCoeff, db); gcd = MathFunctions.GreatCommonDivisor(numeratorCoeff, denominatorCoeff, this.integerNumber); if (!this.integerNumber.IsMultiplicativeUnity(gcd)) { numeratorCoeff = this.integerNumber.Quo(numeratorCoeff, gcd); denominatorCoeff = this.integerNumber.Quo(denominatorCoeff, gcd); } } } if (sign) { result = this.integerNumber.Successor(result); } } return(result); }
/// <summary> /// Permite determinar a factorização racional de um polinómio. /// </summary> /// <param name="polynomial">O polinómio.</param> /// <returns>O resultado da factorização.</returns> public PolynomialFactorizationResult <Fraction <CoeffType>, CoeffType> Run( UnivariatePolynomialNormalForm <Fraction <CoeffType> > polynomial) { if (polynomial == null) { throw new ArgumentNullException("polynomial"); } else { var squareFreeResult = this.squareFreeAlg.Run(polynomial); var independentCoeff = squareFreeResult.IndependentCoeff; var factorizationDictionary = new Dictionary <int, List <UnivariatePolynomialNormalForm <CoeffType> > >(); foreach (var squareFreeFactorKvp in squareFreeResult.Factors) { if (squareFreeFactorKvp.Value.Degree == 1) { factorizationDictionary.Add( squareFreeFactorKvp.Key, new List <UnivariatePolynomialNormalForm <CoeffType> >() { squareFreeFactorKvp.Value }); } else { var currentPolynomial = squareFreeFactorKvp.Value; var polynomialLeadingCoeff = currentPolynomial.GetLeadingCoefficient(this.integerNumber); var polynomialNorm = this.GetPolynomialNorm(currentPolynomial); var bound = this.ComputeMignotteApproximation( polynomialNorm, polynomialLeadingCoeff, polynomial.Degree); var primeNumbersBound = this.ComputeGamma(polynomialNorm, polynomial.Degree); var primeNumbersIterator = this.primeNumbersIteratorFactory.CreatePrimeNumberIterator( primeNumbersBound); var primeNumbersEnumerator = primeNumbersIterator.GetEnumerator(); var discriminant = this.resultantAlg.Run( currentPolynomial, currentPolynomial.GetPolynomialDerivative(this.integerNumber)); var currentPrime = this.integerNumber.MultiplicativeUnity; var status = 0; while (status == 0) { if (primeNumbersEnumerator.MoveNext()) { currentPrime = primeNumbersEnumerator.Current; if (!this.integerNumber.IsAdditiveUnity( this.integerNumber.Rem(polynomialLeadingCoeff, currentPrime)) && !this.integerNumber.IsAdditiveUnity(this.integerNumber.Rem( discriminant, currentPrime))) { status = 1; } } else { status = -1; } } if (status == 1) // Encontrou um número primo sobre o qual é possível proceder à elevação. { var factorList = new List <UnivariatePolynomialNormalForm <CoeffType> >(); var iterationsNumber = this.GetHenselLiftingIterationsNumber(bound, currentPrime); var coeff = this.FactorizePolynomial( currentPolynomial, currentPrime, bound, iterationsNumber, factorList); var multiplicationCoeff = this.fractionField.InverseConversion(coeff); multiplicationCoeff = MathFunctions.Power( multiplicationCoeff, squareFreeFactorKvp.Key, this.fractionField); independentCoeff = this.fractionField.Multiply(independentCoeff, multiplicationCoeff); factorizationDictionary.Add( squareFreeFactorKvp.Key, factorList); } else { factorizationDictionary.Add( squareFreeFactorKvp.Key, new List <UnivariatePolynomialNormalForm <CoeffType> >() { squareFreeFactorKvp.Value }); } } } return(new PolynomialFactorizationResult <Fraction <CoeffType>, CoeffType>( independentCoeff, factorizationDictionary)); } }