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