/// <summary> /// Obtém uma matriz identidade. /// </summary> /// <typeparam name="RingType">O tipo do anel responsável pelas operações sobre os coeficientes.</typeparam> /// <param name="order">A dimensão da matriz.</param> /// <param name="ring">O anel responsável pelas operações sobre os coeficientes.</param> /// <returns>A matriz identidade.</returns> /// <exception cref="ArgumentNullException">Se o anel proporcionado for nulo.</exception> /// <exception cref="ArgumentOutOfRangeException">See a dimensão da matriz for inferior a um.</exception> public static ArrayMathMatrix <ObjectType> GetIdentity <RingType>(int order, RingType ring) where RingType : IRing <ObjectType> { if (ring == null) { throw new ArgumentNullException("ring"); } else if (order <= 0) { throw new ArgumentOutOfRangeException("Order of identity matrix must be greater than one."); } else { var result = new ArrayMathMatrix <ObjectType>(order, order); for (int i = 0; i < order; ++i) { for (int j = 0; j < order; ++j) { if (i == j) { result.elements[i][j] = ring.MultiplicativeUnity; } else { result.elements[i][j] = ring.AdditiveUnity; } } } return(result); } }
/// <summary> /// Obtém o produto da matriz corrente com outra matriz. /// </summary> /// <param name="right">A outra matriz.</param> /// <param name="ring">O anel.</param> /// <returns>O resultado do produto.</returns> public ArrayMathMatrix <ObjectType> ParallelMultiply( ArrayMathMatrix <ObjectType> right, IRing <ObjectType> ring) { if (right == null) { throw new ArgumentNullException("right"); } else if (ring == null) { throw new ArgumentNullException("ring"); } else { var columnNumber = this.numberOfColumns; var lineNumber = right.numberOfColumns; if (columnNumber != lineNumber) { throw new MathematicsException("To multiply two matrices, the number of columns of the first must match the number of lines of second."); } else { var firstDimension = this.numberOfLines; var secondDimension = right.numberOfColumns; var result = new ArrayMathMatrix <ObjectType>( firstDimension, secondDimension); Parallel.For(0, firstDimension, i => { for (int j = 0; j < secondDimension; ++j) { var addResult = ring.AdditiveUnity; for (int k = 0; k < columnNumber; ++k) { var multResult = ring.Multiply( this.elements[i][k], right.elements[k][j]); addResult = ring.Add(addResult, multResult); } result.elements[i][j] = addResult; } }); return(result); } } }
/// <summary> /// Obtém o valor final do determinante. /// </summary> /// <param name="triangularMatrix">A matriz triangular resultante.</param> /// <param name="divisors">A lista de factores.</param> /// <param name="sign">O sinal.</param> /// <returns>O resultado do cálculo.</returns> private ObjectType GetDeterminantValue(ArrayMathMatrix <ObjectType> triangularMatrix, List <ObjectType> divisors, bool sign) { var dimensions = triangularMatrix.GetLength(0); var result = triangularMatrix[0, 0]; for (int i = 1; i < dimensions; ++i) { result = this.ring.Multiply(result, triangularMatrix[i, i]); } for (int i = 0; i < divisors.Count; ++i) { result = this.domain.Quo(result, divisors[i]); } if (!sign) { result = this.ring.AdditiveInverse(result); } return(result); }
/// <summary> /// Obtém a soma da matriz corrente com outra matriz. /// </summary> /// <param name="right">A outra matriz.</param> /// <param name="semigroup">O semigrupo.</param> /// <returns>O resultado da soma.</returns> public ArrayMathMatrix <ObjectType> Add(ArrayMathMatrix <ObjectType> right, ISemigroup <ObjectType> semigroup) { if (right == null) { throw new ArgumentNullException("right"); } else if (semigroup == null) { throw new ArgumentNullException("semigroup"); } else { if (this.numberOfLines == right.numberOfLines && this.numberOfColumns == right.numberOfColumns) { var result = new ArrayMathMatrix <ObjectType>( this.numberOfLines, this.numberOfColumns); for (int i = 0; i < this.numberOfLines; ++i) { for (int j = 0; j < this.numberOfColumns; ++j) { result.elements[i][j] = semigroup.Add( this.elements[i][j], right.elements[i][j]); } } return(result); } else { throw new ArgumentException("Matrices don't have the same dimensions."); } } }
/// <summary> /// Determina o polinómio característico de uma matriz. /// </summary> /// <param name="data">A matriz.</param> /// <returns>O polinómio característico.</returns> public UnivariatePolynomialNormalForm <ElementType> Run(ISquareMathMatrix <ElementType> data) { if (data == null) { return(new UnivariatePolynomialNormalForm <ElementType>(this.variableName)); } else { var lines = data.GetLength(0); if (lines == 0) { return(new UnivariatePolynomialNormalForm <ElementType>(this.variableName)); } else if (lines == 1) { var entry = data[0, 0]; var result = new UnivariatePolynomialNormalForm <ElementType>( this.ring.MultiplicativeUnity, 1, this.variableName, this.ring); result = result.Add(this.ring.AdditiveInverse(entry), 0, this.ring); return(result); } else if (lines == 2) { var variablePol = new UnivariatePolynomialNormalForm <ElementType>( this.ring.MultiplicativeUnity, 1, this.variableName, this.ring); var firstDiagonalElement = variablePol.Add( this.ring.AdditiveInverse(data[0, 0]), this.ring); var secondDiagonalElement = variablePol.Add( this.ring.AdditiveInverse(data[1, 1]), this.ring); var result = firstDiagonalElement.Multiply(secondDiagonalElement, this.ring); result = result.Add( this.ring.AdditiveInverse(this.ring.Multiply(data[0, 1], data[1, 0])), this.ring); return(result); } else { var matrixFactory = new ArrayMathMatrixFactory <ElementType>(); var matrixMultiplicator = new MatrixMultiplicationOperation <ElementType>( matrixFactory, this.ring, this.ring); var subMatrixSequence = new IntegerSequence(); var singleValueSequence = new IntegerSequence(); IMatrix <ElementType> multiplicationMatrix = new ArrayMathMatrix <ElementType>( lines + 1, lines, this.ring.AdditiveUnity); subMatrixSequence.Add(1, lines - 1); singleValueSequence.Add(0); this.FillMultiplicationMatrix( data, data[0, 0], subMatrixSequence, singleValueSequence, matrixMultiplicator, multiplicationMatrix); var currentDimension = 1; while (currentDimension < lines - 1) { subMatrixSequence.Clear(); singleValueSequence.Clear(); subMatrixSequence.Add(currentDimension + 1, lines - 1); singleValueSequence.Add(currentDimension); var otherLines = lines - currentDimension; var otherMultiplicationMatrix = new ArrayMathMatrix <ElementType>( otherLines + 1, otherLines, this.ring.AdditiveUnity); this.FillMultiplicationMatrix( data, data[currentDimension, currentDimension], subMatrixSequence, singleValueSequence, matrixMultiplicator, otherMultiplicationMatrix); multiplicationMatrix = matrixMultiplicator.Multiply( multiplicationMatrix, otherMultiplicationMatrix); ++currentDimension; } var lastOtherMultiplicationMatrix = new ArrayMathMatrix <ElementType>( 2, 1, this.ring.AdditiveUnity); lastOtherMultiplicationMatrix[0, 0] = this.ring.MultiplicativeUnity; lastOtherMultiplicationMatrix[1, 0] = this.ring.AdditiveInverse(data[currentDimension, currentDimension]); multiplicationMatrix = matrixMultiplicator.Multiply( multiplicationMatrix, lastOtherMultiplicationMatrix); var result = new UnivariatePolynomialNormalForm <ElementType>( multiplicationMatrix[0, 0], lines, this.variableName, this.ring); for (int i = 1; i <= lines; ++i) { result = result.Add(multiplicationMatrix[i, 0], lines - i, this.ring); } return(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> /// Calcula o determinante. /// </summary> /// <param name="data">A matriz.</param> /// <returns>O valor do determinante.</returns> protected override ObjectType ComputeDeterminant(IMatrix <ObjectType> data) { var positiveResult = true; var determinantFactors = new List <ObjectType>(); var matrixDimension = data.GetLength(0); if (matrixDimension == 0) { return(this.ring.AdditiveUnity); } else { // Copia a matriz uma vez que o algoritmo a vai alterar var temporaryArray = new ArrayMathMatrix <ObjectType>(matrixDimension, matrixDimension); for (int i = 0; i < matrixDimension; ++i) { for (int j = 0; j < matrixDimension; ++j) { temporaryArray[i, j] = data[i, j]; } } for (int i = 0; i < matrixDimension - 1; ++i) { var pivotValue = temporaryArray[i, i]; if (this.ring.IsAdditiveUnity(pivotValue)) { var nextPivotCandidate = this.GetNextNonEmptyPivotLineNumber(i, temporaryArray); if (nextPivotCandidate == -1) { return(this.ring.AdditiveUnity); } else { positiveResult = !positiveResult; temporaryArray.SwapLines(i, nextPivotCandidate); pivotValue = temporaryArray[i, i]; } } if (this.ring.IsMultiplicativeUnity(pivotValue)) { for (int j = i + 1; j < matrixDimension; ++j) { var value = temporaryArray[j, i]; if (!this.ring.IsAdditiveUnity(value)) { temporaryArray[j, i] = this.ring.AdditiveUnity; for (int k = i + 1; k < matrixDimension; ++k) { var temp = this.ring.Multiply(value, temporaryArray[i, k]); temporaryArray[j, k] = this.ring.Add(temporaryArray[j, k], this.ring.AdditiveInverse(temp)); } } } } else { for (int j = i + 1; j < matrixDimension; ++j) { var value = temporaryArray[j, i]; if (!this.ring.IsAdditiveUnity(value)) { var gcd = MathFunctions.GreatCommonDivisor(pivotValue, value, this.domain); var lcm = this.ring.Multiply(pivotValue, value); lcm = this.domain.Quo(lcm, gcd); var pivotCoffactor = this.domain.Quo(pivotValue, gcd); var valueCoffactor = this.domain.Quo(value, gcd); determinantFactors.Add(pivotCoffactor); temporaryArray[j, i] = this.ring.AdditiveUnity; for (int k = i + 1; k < matrixDimension; ++k) { var positive = this.ring.Multiply(pivotCoffactor, temporaryArray[j, k]); var negative = this.ring.Multiply(valueCoffactor, temporaryArray[i, k]); temporaryArray[j, k] = this.ring.Add(positive, this.ring.AdditiveInverse(negative)); } } } } } return(this.GetDeterminantValue(temporaryArray, determinantFactors, positiveResult)); } }