예제 #1
0
        /// <summary>
        /// Aplica o método da factorização em corpos finitos ao polinómio simples.
        /// </summary>
        /// <param name="polynom">O polinómio simples.</param>
        /// <param name="integerModule">O corpo responsável pelas operações sobre os coeficientes.</param>
        /// <param name="polynomField">O corpo responsável pelo produto de polinómios.</param>
        /// <param name="bachetBezoutAlgorithm">O objecto responsável pelo algoritmo de máximo divisor comum.</param>
        /// <returns>A lista dos factores.</returns>
        private FiniteFieldPolynomialFactorizationResult <CoeffType> Factorize(
            UnivariatePolynomialNormalForm <CoeffType> polynom,
            IModularField <CoeffType> integerModule,
            UnivarPolynomEuclideanDomain <CoeffType> polynomField,
            LagrangeAlgorithm <UnivariatePolynomialNormalForm <CoeffType> > bachetBezoutAlgorithm)
        {
            var result = new List <UnivariatePolynomialNormalForm <CoeffType> >();

            var polynomialStack = new Stack <UnivariatePolynomialNormalForm <CoeffType> >();
            var processedPols   = this.Process(
                polynom,
                result,
                integerModule,
                polynomField,
                bachetBezoutAlgorithm);

            foreach (var processedPol in processedPols)
            {
                polynomialStack.Push(processedPol);
            }

            while (polynomialStack.Count > 0)
            {
                var topPolynomial = polynomialStack.Pop();
                processedPols = this.Process(
                    topPolynomial,
                    result,
                    integerModule,
                    polynomField,
                    bachetBezoutAlgorithm);

                foreach (var processedPol in processedPols)
                {
                    polynomialStack.Push(processedPol);
                }
            }

            for (int i = 0; i < result.Count; ++i)
            {
                var leadingMon = result[i].GetLeadingCoefficient(integerModule);
                if (!integerModule.IsMultiplicativeUnity(leadingMon))
                {
                    var invLeadingMon = integerModule.MultiplicativeInverse(leadingMon);
                    result[i] = result[i].ApplyFunction(
                        c => integerModule.Multiply(c, invLeadingMon),
                        integerModule);
                }
            }

            var mainLeadingMon = polynom.GetLeadingCoefficient(integerModule);

            return(new FiniteFieldPolynomialFactorizationResult <CoeffType>(
                       mainLeadingMon,
                       result,
                       polynom));
        }
        /// <summary>
        /// Calcula o máximo divisor comum entre dois polinómios.
        /// </summary>
        /// <param name="first">O primeiro polinómio.</param>
        /// <param name="second">O segundo polinómio.</param>
        /// <param name="polynomDomain">O domínio responsável pelas operações sobre os polinómios.</param>
        /// <param name="field">O corpo responsável pelas operações sobre os coeficientes.</param>
        /// <returns>O máximo divisor comum.</returns>
        private UnivariatePolynomialNormalForm <CoeffType> GreatCommonDivisor(
            UnivariatePolynomialNormalForm <CoeffType> first,
            UnivariatePolynomialNormalForm <CoeffType> second,
            UnivarPolynomEuclideanDomain <CoeffType> polynomDomain,
            IField <CoeffType> field
            )
        {
            var result       = MathFunctions.GreatCommonDivisor(first, second, polynomDomain);
            var leadingCoeff = result.GetLeadingCoefficient(field);

            result = result.Multiply(field.MultiplicativeInverse(leadingCoeff), field);
            return(result);
        }
        /// <summary>
        /// Determina o produto de todos os factores modulares.
        /// </summary>
        /// <param name="modularFactors">Os factores modulares.</param>
        /// <param name="modularDomain">O domínio modular.</param>
        /// <returns>O resultado do produto dos factores modulares.</returns>
        private UnivariatePolynomialNormalForm <CoeffType> ComputeModularProduct(
            List <UnivariatePolynomialNormalForm <CoeffType> > modularFactors,
            UnivarPolynomEuclideanDomain <CoeffType> modularDomain)
        {
            if (modularFactors.Count > 0)
            {
                var result = modularFactors[0];
                for (int i = 1; i < modularFactors.Count; ++i)
                {
                    result = modularDomain.Multiply(result, modularFactors[i]);
                }

                return(result);
            }
            else
            {
                return(modularDomain.MultiplicativeUnity);
            }
        }
예제 #4
0
        /// <summary>
        /// Executa o algoritmo sobre o polinómio com coeficientes inteiros.
        /// </summary>
        /// <remarks>
        /// O polinómio tem de ser livre de quadrados. Caso contrário, o resultado da aplicação do algoritmo
        /// é imprevisível.
        /// </remarks>
        /// <param name="polymomial">O polinómio.</param>
        /// <param name="modularField">O corpo modular.</param>
        /// <returns>A factorização do polinómio.</returns>
        public FiniteFieldPolynomialFactorizationResult <CoeffType> Run(
            UnivariatePolynomialNormalForm <CoeffType> polymomial,
            IModularField <CoeffType> modularField)
        {
            var fractionField = new FractionField <CoeffType>(this.integerNumber);
            var polynomDomain = new UnivarPolynomEuclideanDomain <CoeffType>(
                polymomial.VariableName,
                modularField);
            var bachetBezourAlg = new LagrangeAlgorithm <UnivariatePolynomialNormalForm <CoeffType> >(polynomDomain);

            var polynomialField = new UnivarPolynomEuclideanDomain <CoeffType>(
                polymomial.VariableName,
                modularField);

            var result = this.Factorize(
                polymomial,
                modularField,
                polynomialField,
                bachetBezourAlg);

            return(result);
        }
        /// <summary>
        /// Aplica o algoritmo de factorização livre de quadrados a um polinómio.
        /// </summary>
        /// <param name="data">O polinómio.</param>
        /// <param name="field">O corpos responsável pelas operações sobre os coeficientes.</param>
        /// <returns>O resultado da factorização livre de quadrados.</returns>
        /// <exception cref="ArgumentNullException">Caso algum dos argumentos seja nulo.</exception>
        public SquareFreeFactorizationResult <CoeffType, CoeffType> Run(
            UnivariatePolynomialNormalForm <CoeffType> data,
            IField <CoeffType> field)
        {
            if (field == null)
            {
                throw new ArgumentNullException("field");
            }
            else if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            else
            {
                var independentCoeff = field.MultiplicativeUnity;
                var result           = new Dictionary <int, UnivariatePolynomialNormalForm <CoeffType> >();
                var currentDegree    = 1;
                var polynomDomain    = new UnivarPolynomEuclideanDomain <CoeffType>(data.VariableName, field);
                var dataDerivative   = data.GetPolynomialDerivative(field);
                var gcd = this.GreatCommonDivisor(data, dataDerivative, polynomDomain, field);
                if (polynomDomain.IsMultiplicativeUnity(gcd))
                {
                    result.Add(currentDegree, data.Clone());
                }
                else
                {
                    var polyCoffactor    = polynomDomain.Quo(data, gcd);
                    var nextGcd          = this.GreatCommonDivisor(gcd, polyCoffactor, polynomDomain, field);
                    var squareFreeFactor = polynomDomain.Quo(polyCoffactor, nextGcd);
                    polyCoffactor = gcd;
                    gcd           = nextGcd;
                    if (squareFreeFactor.Degree > 0)
                    {
                        result.Add(currentDegree, squareFreeFactor);
                    }
                    else
                    {
                        var value = squareFreeFactor.GetAsValue(field);
                        if (!field.IsMultiplicativeUnity(value))
                        {
                            if (field.IsMultiplicativeUnity(independentCoeff))
                            {
                                independentCoeff = value;
                            }
                            else
                            {
                                independentCoeff = field.Multiply(independentCoeff, value);
                            }
                        }
                    }

                    ++currentDegree;
                    while (gcd.Degree > 0)
                    {
                        polyCoffactor    = polynomDomain.Quo(polyCoffactor, gcd);
                        nextGcd          = this.GreatCommonDivisor(gcd, polyCoffactor, polynomDomain, field);
                        squareFreeFactor = polynomDomain.Quo(gcd, nextGcd);
                        gcd = nextGcd;
                        if (squareFreeFactor.Degree > 0)
                        {
                            result.Add(currentDegree, squareFreeFactor);
                        }
                        else
                        {
                            var value = squareFreeFactor.GetAsValue(field);
                            if (!field.IsMultiplicativeUnity(value))
                            {
                                if (field.IsMultiplicativeUnity(independentCoeff))
                                {
                                    independentCoeff = value;
                                }
                                else
                                {
                                    independentCoeff = field.Multiply(independentCoeff, value);
                                }
                            }
                        }

                        ++currentDegree;
                    }

                    var cofactorValue = polyCoffactor.GetAsValue(field);
                    if (!field.IsMultiplicativeUnity(cofactorValue))
                    {
                        if (field.IsMultiplicativeUnity(independentCoeff))
                        {
                            independentCoeff = cofactorValue;
                        }
                        else
                        {
                            independentCoeff = field.Multiply(independentCoeff, cofactorValue);
                        }
                    }
                }

                return(new SquareFreeFactorizationResult <CoeffType, CoeffType>(
                           independentCoeff,
                           result));
            }
        }
예제 #6
0
        /// <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>
        /// 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>
        /// Permite obter a lista de factores irredutíveis a partir de uma factorização módulo um número primo.
        /// </summary>
        /// <param name="liftedFactorization">A factorização módulo o número primo.</param>
        /// <param name="testValue">
        /// O valor de teste que depende do grau, da norma e do coeficiente principal do polinómio original.
        /// </param>
        /// <param name="combinationsNumber">O número máximo de combinações a testar.</param>
        /// <returns>A lista de factores irredutíveis.</returns>
        /// <exception cref="ArgumentNullException">Se a factorização ou o valor de teste forem nulos.</exception>
        /// <exception cref="ArgumentException">Se não forem providenciadas quaisquer combinações.</exception>
        public SearchFactorizationResult <CoeffType> Run(
            MultiFactorLiftingResult <CoeffType> liftedFactorization,
            CoeffType testValue,
            int combinationsNumber)
        {
            if (liftedFactorization == null)
            {
                throw new ArgumentNullException("liftedFactorization");
            }
            else if (testValue == null)
            {
                throw new ArgumentNullException("testValue");
            }
            else if (combinationsNumber <= 0)
            {
                throw new ArgumentException("At least one combination is expected.");
            }
            else
            {
                var modularField = this.modularFieldFactory.CreateInstance(liftedFactorization.LiftingPrimePower);
                var halfPrime    = this.integerNumber.Quo(
                    liftedFactorization.LiftingPrimePower,
                    this.integerNumber.MapFrom(2));

                var modularFactors = new List <UnivariatePolynomialNormalForm <CoeffType> >();
                foreach (var liftedFactor in liftedFactorization.Factors)
                {
                    if (liftedFactor.Degree != 0)
                    {
                        modularFactors.Add(liftedFactor.ApplyFunction(
                                               c => this.GetSymmetricRemainder(c, liftedFactorization.LiftingPrimePower, halfPrime),
                                               this.integerNumber));
                    }
                }

                var integerFactors = new List <UnivariatePolynomialNormalForm <CoeffType> >();

                // Lida com os factores lineares
                var i             = 0;
                var constantCoeff = this.integerNumber.MultiplicativeUnity;
                while (i < modularFactors.Count)
                {
                    var currentModularFactor = modularFactors[i];
                    var norm = this.GetPlynomialNorm(currentModularFactor);
                    if (this.integerNumber.Compare(norm, testValue) < 0)
                    {
                        integerFactors.Add(currentModularFactor);
                        modularFactors.RemoveAt(i);
                    }
                    else
                    {
                        ++i;
                    }
                }

                var modularPolynomialDomain = new UnivarPolynomEuclideanDomain <CoeffType>(
                    liftedFactorization.Polynom.VariableName,
                    modularField);
                this.ProcessRemainingPolynomials(
                    modularFactors,
                    integerFactors,
                    liftedFactorization.LiftingPrimePower,
                    halfPrime,
                    testValue,
                    combinationsNumber,
                    modularPolynomialDomain);

                return(new SearchFactorizationResult <CoeffType>(
                           liftedFactorization.Polynom,
                           integerFactors,
                           modularFactors));
            }
        }
        /// <summary>
        /// Permite processar as restantes combinações.
        /// </summary>
        /// <param name="modularFactors">Os factores modulares.</param>
        /// <param name="integerFactors">Os factores inteiros.</param>
        /// <param name="primePower">A potência de um número primo que servirá de módulo.</param>
        /// <param name="halfPrimePower">A metade da potência do número primo.</param>
        /// <param name="testValue">O valor de teste.</param>
        /// <param name="combinationsNumber">O número máximo de polinómios nas combinações.</param>
        /// <param name="modularPolynomialDomain">O corpo responsável pelas operações modulares.</param>
        private void ProcessRemainingPolynomials(
            List <UnivariatePolynomialNormalForm <CoeffType> > modularFactors,
            List <UnivariatePolynomialNormalForm <CoeffType> > integerFactors,
            CoeffType primePower,
            CoeffType halfPrimePower,
            CoeffType testValue,
            int combinationsNumber,
            UnivarPolynomEuclideanDomain <CoeffType> modularPolynomialDomain)
        {
            if (combinationsNumber > 1 && modularFactors.Count > 1)
            {
                var modularProduct           = default(UnivariatePolynomialNormalForm <CoeffType>);
                var currentCombinationNumber = 2;
                var productStack             = new Stack <UnivariatePolynomialNormalForm <CoeffType> >();
                productStack.Push(modularFactors[0]);
                var pointers = new Stack <int>();
                pointers.Push(0);
                pointers.Push(1);
                var state = 0;
                while (state != -1)
                {
                    if (state == 0)
                    {
                        if (pointers.Count == currentCombinationNumber)
                        {
                            var topPointer = pointers.Pop();
                            var topPol     = productStack.Pop();

                            // Obtém o produto de todos os polinómios.
                            var currentPol = modularPolynomialDomain.Multiply(
                                topPol,
                                modularFactors[topPointer]);
                            currentPol = currentPol.ApplyFunction(
                                c => this.GetSymmetricRemainder(
                                    c,
                                    primePower,
                                    halfPrimePower),
                                this.integerNumber);

                            // Compara as normas com o valor de teste
                            var firstNorm = this.GetPlynomialNorm(currentPol);
                            if (this.integerNumber.Compare(firstNorm, testValue) < 0)
                            {
                                if (modularProduct == null)
                                {
                                    modularProduct = this.ComputeModularProduct(
                                        modularFactors,
                                        modularPolynomialDomain);
                                }

                                var coPol = modularPolynomialDomain.Quo(
                                    modularProduct,
                                    currentPol);
                                coPol = coPol.ApplyFunction(
                                    c => this.GetSymmetricRemainder(
                                        c,
                                        primePower,
                                        halfPrimePower),
                                    this.integerNumber);
                                var secondNorm = this.GetPlynomialNorm(coPol);
                                var normProd   = this.integerNumber.Multiply(firstNorm, secondNorm);
                                if (this.integerNumber.Compare(normProd, testValue) < 0)
                                {
                                    integerFactors.Add(currentPol);
                                    modularFactors.RemoveAt(topPointer);
                                    while (pointers.Count > 0)
                                    {
                                        var removeIndex = pointers.Pop();
                                        modularFactors.RemoveAt(removeIndex);
                                    }

                                    productStack.Clear();
                                    if (modularFactors.Count < currentCombinationNumber)
                                    {
                                        state = -1;
                                    }
                                    else
                                    {
                                        productStack.Push(modularFactors[0]);
                                        pointers.Push(0);
                                        pointers.Push(1);
                                    }
                                }
                                else
                                {
                                    productStack.Push(topPol);
                                    pointers.Push(topPointer);
                                    state = 1;
                                }
                            }
                            else
                            {
                                productStack.Push(topPol);
                                pointers.Push(topPointer);
                                state = 1;
                            }
                        }
                        else
                        {
                            var topPointer = pointers.Pop();
                            var topPol     = productStack.Pop();
                            var currentPol = modularPolynomialDomain.Multiply(
                                topPol,
                                modularFactors[topPointer]);
                            currentPol = currentPol.ApplyFunction(
                                c => this.GetSymmetricRemainder(
                                    c,
                                    primePower,
                                    halfPrimePower),
                                this.integerNumber);

                            productStack.Push(topPol);
                            productStack.Push(currentPol);
                            pointers.Push(topPointer);
                            pointers.Push(topPointer + 1);
                        }
                    }
                    else if (state == 1)
                    {
                        var pointerLimit = modularFactors.Count - combinationsNumber + pointers.Count + 1;
                        if (pointers.Count > 1)
                        {
                            var topPointer = pointers.Pop();
                            ++topPointer;
                            if (topPointer < pointerLimit)
                            {
                                pointers.Push(topPointer);
                                state = 0;
                            }
                            else
                            {
                                productStack.Pop();
                            }
                        }
                        else
                        {
                            var topPointer = pointers.Pop();
                            ++topPointer;
                            if (topPointer < pointerLimit)
                            {
                                pointers.Push(topPointer);
                                productStack.Push(modularFactors[topPointer]);
                                pointers.Push(topPointer + 1);
                            }
                            else
                            {
                                ++currentCombinationNumber;
                                if (currentCombinationNumber < combinationsNumber)
                                {
                                    state = -1;
                                }
                                else if (modularFactors.Count < currentCombinationNumber)
                                {
                                    state = -1;
                                }
                                else
                                {
                                    pointers.Push(0);
                                    pointers.Push(1);
                                    productStack.Push(modularFactors[0]);
                                }
                            }
                        }
                    }
                }
            }
        }