/// <summary> /// Testa a deomposição sequencial relativa à matriz. /// </summary> /// <param name="target">O algoritmo.</param> /// <param name="matrix">A matriz.</param> private void TestDecomposition( ATriangDiagSymmMatrixDecomp <Fraction <int> > target, ISquareMathMatrix <Fraction <int> > matrix) { // Execução do algoritmo. var decomposition = target.Run( matrix); // Calcula o valor esperado. var matrixFactory = new ArrayMathMatrixFactory <Fraction <int> >(); var matrixMultiplicaton = new MatrixMultiplicationOperation <Fraction <int> >( matrixFactory, target.Field, target.Field); var actual = new TransposeMatrix <Fraction <int> >(decomposition.UpperTriangularMatrix) as IMatrix <Fraction <int> >; actual = matrixMultiplicaton.Multiply(actual, decomposition.DiagonalMatrix); actual = matrixMultiplicaton.Multiply(actual, decomposition.UpperTriangularMatrix); // Valida as asserções. Assert.AreEqual(matrix.GetLength(0), actual.GetLength(0)); Assert.AreEqual(matrix.GetLength(1), actual.GetLength(1)); for (int i = 0; i < actual.GetLength(0); ++i) { for (int j = 0; j < actual.GetLength(1); ++j) { Assert.AreEqual(matrix[i, j], actual[i, j]); } } }
/// <summary> /// Permite criar uma instância de entrada para o algoritmo do simplex na forma normal. /// A base pode corresponder a uma instância que resultou da aplicação do algoritmo. /// </summary> /// <param name="basicVariables">O conjunto de variáveis básicas.</param> /// <param name="nonBasicVariables">O conjunto de variáveis não-básicas.</param> /// <param name="objectiveFunction">Os coeficientes da função objectivo.</param> /// <param name="cost">O custo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <param name="inverseBasisMatrix">A matriz de base inversa que é utilizada durante o processo algorítmico.</param> /// /// <exception cref="ArgumentNullException">Se algum dos argumentos for nulo.</exception> /// <exception cref="ArgumentException"> /// Se as dimensões dos argumentos não definirem correctamente um problema. /// </exception> public RevisedSimplexInput( int[] basicVariables, int[] nonBasicVariables, IMathVector <ObjectiveCoeffType> objectiveFunction, ObjectiveCoeffType cost, IMathMatrix <ConstraintsType> constraintsMatrix, IMathVector <ConstraintsType> constraintsVector, ISquareMathMatrix <ConstraintsType> inverseBasisMatrix) : base( basicVariables, nonBasicVariables, objectiveFunction, cost, constraintsMatrix, constraintsVector) { if (inverseBasisMatrix == null) { throw new ArgumentNullException("The basis matrix must not be null."); } else if (inverseBasisMatrix.GetLength(0) != ConstraintsMatrix.GetLength(0)) { throw new ArgumentException("The dimension of basis matrix must match the number of lines in constraints matrix."); } else { this.inverseBasisMatrix = inverseBasisMatrix; } }
/// <summary> /// Calcula o vector dos termos independentes actual. /// </summary> /// <param name="inverseMatrix">A matriz inversa.</param> /// <param name="constraintsVector">O vector dos termos independentes original.</param> /// <param name="result">O contentor para os resultados.</param> private void ComputeConstraintsVector( ISquareMathMatrix <CoeffType> inverseMatrix, IMathVector <CoeffType> constraintsVector, CoeffType[] result) { var basicLength = inverseMatrix.GetLength(0); var inverseSparseMatrix = inverseMatrix as ISparseMathMatrix <CoeffType>; if (inverseSparseMatrix == null) { Parallel.For(0, basicLength, i => { var sum = this.coeffsField.AdditiveUnity; for (int j = 0; j < basicLength; ++j) { var valueToAdd = constraintsVector[j]; valueToAdd = this.coeffsField.Multiply(valueToAdd, inverseMatrix[i, j]); sum = this.coeffsField.Add(sum, valueToAdd); } result[i] = sum; }); } else { Parallel.For(0, basicLength, i => { result[i] = this.coeffsField.AdditiveUnity; }); Parallel.ForEach(inverseSparseMatrix.GetLines(), inverseLine => { var sum = this.coeffsField.AdditiveUnity; var columns = inverseLine.Value.GetColumns(); foreach (var columnKvp in columns) { var valueToAdd = constraintsVector[columnKvp.Key]; valueToAdd = this.coeffsField.Multiply(valueToAdd, columnKvp.Value); sum = this.coeffsField.Add(sum, valueToAdd); } result[inverseLine.Key] = sum; }); } }
/// <summary> /// Executa o algorimtmo que permite determinar a solução do sistema simétrico /// com base na decomposição LDL^T. /// </summary> /// <param name="first">A matriz dos coeficientes das variáveis.</param> /// <param name="second">O vector dos coeficientes independentes.</param> /// <returns>A solução do sistema.</returns> public LinearSystemSolution <CoeffType> Run( ISquareMathMatrix <CoeffType> first, IMathMatrix <CoeffType> second) { if (first == null) { throw new ArgumentNullException("first"); } else if (second == null) { throw new ArgumentNullException("second"); } else { var size = first.GetLength(0); if (second.GetLength(0) != size) { throw new ArgumentException( "The number of columns in coefficients matrix must equal the number of lines in independent vector."); } else { var result = new LinearSystemSolution <CoeffType>(); var decompRes = this.decompositionAlgorithm.Run( first); var indSol = this.ProcessFirstMatrix( decompRes.UpperTriangularMatrix, second, size); if (this.ProcessDiagonal(decompRes.DiagonalMatrix, indSol, size)) { this.ProcessRemainingMatrices( decompRes.UpperTriangularMatrix, decompRes.DiagonalMatrix, indSol, size, result); } return(result); } } }
/// <summary> /// Calcula os coeficientes da variável de entrada e coloca-os no vector eta. /// </summary> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="inverseMatrix">A matriz inversa.</param> /// <param name="etaVector">O vector eta.</param> private void ComputeVariableCoefficients( int enteringVariable, IMathMatrix <CoeffType> constraintsMatrix, ISquareMathMatrix <CoeffType> inverseMatrix, CoeffType[] etaVector) { var length = constraintsMatrix.GetLength(1); if (enteringVariable >= length) // A matriz das restrições contém a identidade como entrada. { var entryIndex = enteringVariable - length; // O vector conterá a entrada respectiva na matriz inversa. var sparseInverseMatrix = inverseMatrix as ISparseMathMatrix <CoeffType>; length = etaVector.Length; if (sparseInverseMatrix == null) { Parallel.For(0, length, i => { etaVector[i] = inverseMatrix[i, entryIndex]; }); } else { Parallel.For(0, length, i => { etaVector[i] = this.coeffsField.AdditiveUnity; }); foreach (var line in sparseInverseMatrix.GetLines()) { etaVector[line.Key] = line.Value[entryIndex]; } } } else { length = inverseMatrix.GetLength(0); var sparseContraintsMatrix = constraintsMatrix as ISparseMathMatrix <CoeffType>; if (sparseContraintsMatrix == null) { var sparseInverseMatrix = inverseMatrix as ISparseMathMatrix <CoeffType>; if (sparseInverseMatrix == null) { Parallel.For(0, length, i => { var sum = this.coeffsField.AdditiveUnity; for (int j = 0; j < length; ++j) { var valueToAdd = inverseMatrix[i, j]; valueToAdd = this.coeffsField.Multiply( valueToAdd, constraintsMatrix[j, enteringVariable]); sum = this.coeffsField.Add(sum, valueToAdd); } etaVector[i] = sum; }); } else { Parallel.For(0, length, i => { etaVector[i] = this.coeffsField.AdditiveUnity; }); var inverseMatrixLines = sparseInverseMatrix.GetLines(); Parallel.ForEach(inverseMatrixLines, lineKvp => { var sum = this.coeffsField.AdditiveUnity; foreach (var columnKvp in lineKvp.Value.GetColumns()) { var valueToAdd = constraintsMatrix[columnKvp.Key, enteringVariable]; valueToAdd = this.coeffsField.Multiply(valueToAdd, columnKvp.Value); sum = this.coeffsField.Add(sum, valueToAdd); } etaVector[lineKvp.Key] = sum; }); } } else { var sparseInverseMatrix = inverseMatrix as ISparseMathMatrix <CoeffType>; if (sparseInverseMatrix == null) { Parallel.For(0, length, i => { var sum = this.coeffsField.AdditiveUnity; var constraintsMatrixLines = sparseContraintsMatrix.GetLines(); foreach (var constraintsLine in constraintsMatrixLines) { var j = constraintsLine.Key; var valueToAdd = default(CoeffType); if (constraintsLine.Value.TryGetColumnValue(enteringVariable, out valueToAdd)) { valueToAdd = this.coeffsField.Multiply(valueToAdd, inverseMatrix[i, j]); sum = this.coeffsField.Add(sum, valueToAdd); } } etaVector[i] = sum; }); } else { Parallel.For(0, length, i => { etaVector[i] = this.coeffsField.AdditiveUnity; }); Parallel.ForEach(sparseInverseMatrix.GetLines(), inverseMatrixLine => { var sum = this.coeffsField.AdditiveUnity; var constraintsMatrixLines = sparseContraintsMatrix.GetLines(); foreach (var constraintsLine in constraintsMatrixLines) { var j = constraintsLine.Key; var inverseValue = default(CoeffType); if (inverseMatrixLine.Value.TryGetColumnValue(j, out inverseValue)) { var constraintsValue = default(CoeffType); if (constraintsLine.Value.TryGetColumnValue(enteringVariable, out constraintsValue)) { var valueToAdd = this.coeffsField.Multiply(inverseValue, constraintsValue); sum = this.coeffsField.Add(sum, valueToAdd); } } } etaVector[inverseMatrixLine.Key] = sum; }); } } } }
/// <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> /// Obtém a decomposição de uma matriz M=LDL^* onde L é uma matriz triangular e D é uma matriz diagonal. /// </summary> /// <param name="matrix">A matriz.</param> /// <returns>As matrizes triangular e diagonal.</returns> public override TriangDiagSymmMatrixDecompResult <CoeffType> Run( ISquareMathMatrix <CoeffType> matrix) { if (matrix == null) { throw new ArgumentNullException("matrix"); } else { var matrixDimension = matrix.GetLength(0); var triangularMatrix = this.upperTriangularMatrixFactory.Invoke( matrixDimension, this.field.AdditiveUnity); var diagonalMatrix = this.diagonalMatrixFactory.Invoke( matrixDimension, this.field.AdditiveUnity); for (int i = 0; i < matrixDimension; ++i) { var diagonalTask = new Task(() => { var sumValue = this.field.AdditiveUnity; for (int j = 0; j < i; ++j) { var diag = diagonalMatrix[j, j]; if (!this.field.IsAdditiveUnity(diag)) { var value = triangularMatrix[j, i]; value = this.field.Multiply(value, value); value = this.field.Multiply(value, diag); sumValue = this.field.Add(sumValue, value); } } sumValue = this.field.Add( matrix[i, i], this.field.AdditiveInverse(sumValue)); diagonalMatrix[i, i] = sumValue; }); var triangularTask = new Task(() => { Parallel.For(i + 1, matrixDimension, (j, state) => { var sumValue = this.field.AdditiveUnity; for (int k = 0; k < i; ++k) { var value = triangularMatrix[k, i]; value = this.field.Multiply(value, triangularMatrix[k, j]); value = this.field.Multiply(value, diagonalMatrix[k, k]); sumValue = this.field.Add(sumValue, value); } triangularMatrix[i, j] = this.field.Add( matrix[i, j], this.field.AdditiveInverse(sumValue)); }); }); diagonalTask.Start(); triangularTask.Start(); Task.WaitAll(new[] { diagonalTask, triangularTask }); var diagonalValue = diagonalMatrix[i, i]; if (!this.field.IsAdditiveUnity(diagonalValue)) { triangularMatrix.ScalarLineMultiplication( i, this.field.MultiplicativeInverse(diagonalMatrix[i, i]), this.field); } triangularMatrix[i, i] = this.field.MultiplicativeUnity; } return(new TriangDiagSymmMatrixDecompResult <CoeffType>( triangularMatrix, diagonalMatrix)); } }