/// <summary> /// Obtém a simetrização da matriz. /// </summary> /// <param name="matrix">A matriz original.</param> /// <returns>A matriz simétrica.</returns> private ISquareMathMatrix <CoeffType> GetSymmetricMatrix( IMathMatrix <CoeffType> matrix) { var lines = matrix.GetLength(0); var columns = matrix.GetLength(1); var result = this.squareMatrixFactory.Invoke(columns); for (var i = 0; i < columns; ++i) { for (var j = 0; j < columns; ++j) { var sum = this.ring.AdditiveUnity; for (var k = 0; k < lines; ++k) { var value = this.ring.Multiply( matrix[k, i], matrix[k, j]); sum = this.ring.Add( sum, value); } result[i, j] = sum; } } return(result); }
/// <summary> /// Averigua se o sistema possui alguma solução. /// </summary> /// <param name="diagonalMatrix">A matriz diagonal.</param> /// <param name="indSolVector">O vector independente da solução.</param> /// <param name="size">A dimensão das matrizes.</param> /// <returns> /// Verdadeiro caso o sistema tenha solução e falso caso contrário. /// </returns> private bool ProcessDiagonal( IMathMatrix <CoeffType> diagonalMatrix, IMathVector <CoeffType> indSolVector, int size) { var field = this.decompositionAlgorithm.Field; for (var i = 0; i < size; ++i) { var diagValue = diagonalMatrix[i, i]; if (field.IsAdditiveUnity(diagValue)) { var indValue = indSolVector[i]; if (!field.IsAdditiveUnity(indValue)) { return(false); } } else { indSolVector[i] = field.Multiply( indSolVector[i], field.MultiplicativeInverse(diagValue)); } } return(true); }
/// <summary> /// Cria uma nova instância de um objecto do tipo <see cref="TriangDiagSymmMatrixDecompResult{CoeffType}"/>. /// </summary> /// <param name="upperTriangularMatrix">A matriz triangular inferior.</param> /// <param name="diagonalMatrix">A matriz diagonal.</param> internal TriangDiagSymmMatrixDecompResult( IMathMatrix <CoeffType> upperTriangularMatrix, IMathMatrix <CoeffType> diagonalMatrix) { this.upperTriangularMatrix = upperTriangularMatrix; this.diagonalMatrix = diagonalMatrix; }
/// <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> /// Obtém o vector dos coeficientes independentes após a transformação. /// </summary> /// <param name="matrix">A matriz dos coeficientes das variáveis.</param> /// <param name="independent">O vector dos coeficientes independentes.</param> /// <returns>O vector transformado.</returns> private IMathMatrix <CoeffType> GetTransformedVector( IMathMatrix <CoeffType> matrix, IMathMatrix <CoeffType> independent) { var lines = matrix.GetLength(0); var columns = matrix.GetLength(1); var result = this.independentVectorFactory.Invoke(columns); for (var i = 0; i < columns; ++i) { var sum = this.ring.AdditiveUnity; for (var j = 0; j < lines; ++j) { var value = this.ring.Multiply( matrix[j, i], independent[j, 0]); sum = this.ring.Add( sum, value); } result[i, 0] = sum; } return(result); }
/// <summary> /// Testa a solução do sistema de equações. /// </summary> /// <param name="matrix">A matriz dos coeficientes das variáveis.</param> /// <param name="independent">O vector dos coeficientes independentes.</param> /// <param name="solution">A solução do sistema simétrico.</param> private void TestSolution( IMathMatrix <CoeffType> matrix, IMathMatrix <CoeffType> independent, LinearSystemSolution <CoeffType> solution) { if (solution.Vector != null) { var vec = solution.Vector; var lines = matrix.GetLength(0); var columns = matrix.GetLength(1); for (var i = 0; i < lines; ++i) { var sum = this.ring.AdditiveUnity; for (var j = 0; j < columns; ++j) { var value = this.ring.Multiply( matrix[i, j], vec[j]); sum = this.ring.Add( sum, value); } if (!this.ring.Equals(sum, independent[i, 0])) { solution.Vector = null; solution.VectorSpaceBasis.Clear(); } } } }
/// <summary> /// Cria instâncias de objectos do tipo <see cref="MetricMatrixVectorScalarProduct{CoeffType}"/>. /// </summary> /// <param name="metricMatrix">A matriz dos coeficientes métricos.</param> /// <param name="comparer">O comparador de coeficientes.</param> /// <param name="ring">O anel responsável pelas operações sobre os coeficientes.</param> /// <exception cref="ArgumentNullException"> /// Caso a matriz dos coeficientes métricos ou o anel responsável pelas operações sobre os coeficientes /// sejam nulos. /// </exception> /// <exception cref="ArgumentException"> /// Se a matriz dos coeficientes métricos não for quadrada. /// </exception> public MetricMatrixVectorScalarProduct( IMathMatrix <CoeffType> metricMatrix, IComparer <CoeffType> comparer, IRing <CoeffType> ring) { if (ring == null) { throw new ArgumentNullException("ring"); } else if (metricMatrix == null) { throw new ArgumentNullException("metricMatrix"); } else if (metricMatrix.GetLength(0) == metricMatrix.GetLength(1)) { if (comparer == null) { this.comparer = Comparer <CoeffType> .Default; } else { this.comparer = comparer; } this.metricMatrix = metricMatrix; this.ring = ring; } else { throw new ArgumentException("The metric coefficients matrix must be square."); } }
/// <summary> /// Determina a solução de um sistema linear de equações. /// </summary> /// <remarks> /// A matriz e o vector independente são alterados durante o processo. /// </remarks> /// <param name="coefficientsMatrix">A matriz dos coeficientes.</param> /// <param name="independentVector">O vector independente.</param> /// <returns>A solução do sistema.</returns> public LinearSystemSolution <ElementType> Run( IMathMatrix <ElementType> coefficientsMatrix, IMathMatrix <ElementType> independentVector) { this.condensationAlgorithm.Run(coefficientsMatrix, independentVector); var result = new LinearSystemSolution <ElementType>(); var matrixLines = coefficientsMatrix.GetLength(0); var matrixColumns = coefficientsMatrix.GetLength(1); var currentPivotLine = 0; var currentPivotColumn = 0; var lastNonZeroColumn = -1; var independentSolutionVector = new ArrayMathVector <ElementType>(matrixColumns, this.field.AdditiveUnity); while (currentPivotLine < matrixLines && currentPivotColumn < matrixColumns) { var pivotValue = coefficientsMatrix[currentPivotLine, currentPivotColumn]; if (this.field.IsAdditiveUnity(pivotValue)) { if (this.field.IsAdditiveUnity(independentSolutionVector[currentPivotLine])) { var basisVector = new ArrayMathVector <ElementType>(matrixColumns, this.field.AdditiveUnity); basisVector[currentPivotColumn] = this.field.AdditiveInverse( this.field.MultiplicativeUnity); var i = currentPivotLine - 1; var j = lastNonZeroColumn; while (i >= 0 && j >= 0) { var linePivotValue = coefficientsMatrix[i, j]; if (this.field.IsMultiplicativeUnity(linePivotValue)) { basisVector[j] = coefficientsMatrix[i, currentPivotColumn]; --i; } --j; } result.VectorSpaceBasis.Add(basisVector); } else { result.Vector = null; result.VectorSpaceBasis.Clear(); return(result); } } else { lastNonZeroColumn = currentPivotColumn; independentSolutionVector[currentPivotColumn] = independentVector[currentPivotLine, 0]; ++currentPivotLine; } ++currentPivotColumn; } result.Vector = independentSolutionVector; return(result); }
/// <summary> /// Processa a função objectivo. /// </summary> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="leavingVariable">a variável de saída.</param> /// <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="currentCost">O custo actual.</param> /// <param name="objective">A função objectivo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <returns>O resultado.</returns> private SimplexMaximumNumberField <CoeffType> ProcessObjectiveFunction( int enteringVariable, int leavingVariable, int[] basicVariables, int[] nonBasicVariables, SimplexMaximumNumberField <CoeffType> currentCost, IMathVector <SimplexMaximumNumberField <CoeffType> > objective, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <CoeffType> constraintsVector) { var result = currentCost; var multiplicativeProduct = this.GetAdditiveInverse(objective[enteringVariable]); if (!this.IsAdditiveUnity(multiplicativeProduct)) { Parallel.For(0, enteringVariable, column => { objective[column] = this.Add( objective[column], this.Multiply(constraintsMatrix[leavingVariable, column], multiplicativeProduct)); }); var constraintsEntry = constraintsMatrix[leavingVariable, enteringVariable]; if (this.coeffsField.IsAdditiveUnity(constraintsEntry)) { objective[enteringVariable] = multiplicativeProduct; } else { objective[enteringVariable] = this.Multiply( constraintsEntry, multiplicativeProduct); } Parallel.For(enteringVariable + 1, objective.Length, column => { objective[column] = this.Add( objective[column], this.Multiply(constraintsMatrix[leavingVariable, column], multiplicativeProduct)); }); result = this.Add( result, this.Multiply(constraintsVector[leavingVariable], multiplicativeProduct)); } // Troca as variáveis var swap = nonBasicVariables[enteringVariable]; nonBasicVariables[enteringVariable] = basicVariables[leavingVariable]; basicVariables[leavingVariable] = swap; return(result); }
/// <summary> /// Determina a próxima variável de saída. /// </summary> /// <remarks> /// Esta função permite fazer um pré-cálculo do vector eta, sendo o respectivo contentor de dados /// passado como argumento. /// </remarks> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <param name="inverseBasisMatrix">A matriz das bases inversa.</param> /// <param name="etaVector">O contentor do vector eta.</param> /// <returns>A próxima variável de saída.</returns> private int GetNextLeavingVariable( int enteringVariable, IMathMatrix <CoeffType> constraintsMatrix, CoeffType[] constraintsVector, ISquareMathMatrix <CoeffType> inverseBasisMatrix, CoeffType[] etaVector) { // Calcula os coeficientes e coloca-os no vector eta. this.ComputeVariableCoefficients( enteringVariable, constraintsMatrix, inverseBasisMatrix, etaVector); var result = -1; var value = this.coeffsField.AdditiveUnity; // Estabelece o primeiro valor para futura comparação. var constraintsLength = constraintsMatrix.GetLength(0); var index = 0; while (index < constraintsLength && result == -1) { var currentValue = etaVector[index]; if (this.coeffsComparer.Compare(currentValue, this.coeffsField.AdditiveUnity) > 0) { value = this.coeffsField.Multiply( constraintsVector[index], this.coeffsField.MultiplicativeInverse(currentValue)); result = index; } ++index; } if (result != -1) { for (; index < constraintsLength; ++index) { var currentValue = etaVector[index]; if (this.coeffsComparer.Compare(currentValue, this.coeffsField.AdditiveUnity) > 0) { currentValue = this.coeffsField.Multiply( constraintsVector[index], this.coeffsField.MultiplicativeInverse(currentValue)); if (this.coeffsComparer.Compare(currentValue, value) < 0) { result = index; value = currentValue; } } } } return(result); }
/// <summary> /// Obtém a variável de entrada. /// </summary> /// <param name="dualVector">O vector dual que irá permitir calcular os coeficientes do custo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="objectiveFunction">A função objectivo.</param> /// <param name="nonBasicVariables">As variáveis não básicas.</param> /// <returns>O índice da variável a entrar.</returns> private int GetNextEnteringVariable( CoeffType[] dualVector, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <CoeffType> objectiveFunction, int[] nonBasicVariables) { var result = -1; var value = this.coeffsField.AdditiveUnity; var nonBasicLength = nonBasicVariables.Length; var constraintsLinesLength = dualVector.Length; var syncObject = new object(); // Utilizado para sincronizar as comparações. Parallel.For(0, nonBasicLength, i => { var innerValue = this.coeffsField.AdditiveUnity; var nonBasicVariable = nonBasicVariables[i]; if (nonBasicVariable < nonBasicLength) { for (int j = 0; j < constraintsLinesLength; ++j) { var valueToAdd = this.coeffsField.Multiply(dualVector[j], constraintsMatrix[j, nonBasicVariable]); valueToAdd = this.coeffsField.Add( valueToAdd, objectiveFunction[nonBasicVariable]); innerValue = this.coeffsField.Add(innerValue, valueToAdd); } lock (syncObject) { if (this.coeffsComparer.Compare(innerValue, value) < 0) { result = i; value = innerValue; } } } else { var index = nonBasicVariable - nonBasicLength; innerValue = dualVector[index]; lock (syncObject) { if (this.coeffsComparer.Compare(innerValue, value) < 0) { result = i; value = innerValue; } } } }); return(result); }
/// <summary> /// Estabelece os valores na parte trangular inferior da matriz. /// </summary> /// <param name="matrix">A matriz.</param> private void SetLowerTerms(IMathMatrix <CoeffType> matrix) { var dimension = matrix.GetLength(0); for (int i = 0; i < dimension; ++i) { for (int j = i + 1; j < dimension; ++j) { matrix[j, i] = matrix[i, j]; } } }
/// <summary> /// Cria instâncias de objectos do tipo <see cref="MatrixRowVector{CoeffType}"/>. /// </summary> /// <param name="lineNumber">O número da linha.</param> /// <param name="matrix">A matriz da qual é extraída a linha como sendo um vector.</param> /// <exception cref="ArgumentOutOfRangeException">Se a matriz for nula.</exception> public MatrixRowVector(int lineNumber, IMathMatrix <CoeffType> matrix) { if (lineNumber < 0) { throw new ArgumentOutOfRangeException("matrix"); } else { this.lineNumber = lineNumber; this.matrix = matrix; } }
/// <summary> /// Cria instâncias de objectos do tipo <see cref="MatrixColumnVector{CoeffType}"/>. /// </summary> /// <param name="columnNumber">O número da coluna.</param> /// <param name="matrix">A matriz da qual se considera a coluna como sendo vector.</param> /// <exception cref="ArgumentOutOfRangeException">Se a matriz for nula.</exception> public MatrixColumnVector(int columnNumber, IMathMatrix <CoeffType> matrix) { if (columnNumber < 0) { throw new ArgumentOutOfRangeException("matrix"); } else { this.columnNumber = columnNumber; this.matrix = matrix; } }
/// <summary> /// Calcula as entradas da matriz de multiplicação. /// </summary> /// <param name="data">A matriz.</param> /// <param name="diagonalElement">O elemento na diagonal.</param> /// <param name="subMatrixSequence">A sequência que define a sub-matriz.</param> /// <param name="singleValueSequence">A sequência que define o valor.</param> /// <param name="multiplicator">O objecto responsável pela multiplicação de matrizes.</param> /// <param name="multiplicationMatrix">A matriz que comporta o resultado da multiplicação.</param> private void FillMultiplicationMatrix( IMathMatrix <ElementType> data, ElementType diagonalElement, IntegerSequence subMatrixSequence, IntegerSequence singleValueSequence, MatrixMultiplicationOperation <ElementType> multiplicator, IMatrix <ElementType> multiplicationMatrix) { var dimension = multiplicationMatrix.GetLength(1); var rowSubMatrix = data.GetSubMatrix(singleValueSequence, subMatrixSequence); var columnSubMatrix = data.GetSubMatrix(subMatrixSequence, singleValueSequence); var mainSubMatrix = data.GetSubMatrix(subMatrixSequence, subMatrixSequence); for (int i = 0; i < dimension; ++i) { multiplicationMatrix[i, i] = this.ring.MultiplicativeUnity; } for (int i = 0; i < dimension; ++i) { multiplicationMatrix[i + 1, i] = this.ring.AdditiveInverse(diagonalElement); } var vectorsMultiply = multiplicator.Multiply(rowSubMatrix, columnSubMatrix); for (int i = 0; i < dimension - 1; ++i) { multiplicationMatrix[i + 2, i] = this.ring.AdditiveInverse(vectorsMultiply[0, 0]); } vectorsMultiply = multiplicator.Multiply(rowSubMatrix, mainSubMatrix); vectorsMultiply = multiplicator.Multiply(vectorsMultiply, columnSubMatrix); for (int i = 0; i < dimension - 2; ++i) { multiplicationMatrix[i + 3, i] = this.ring.AdditiveInverse(vectorsMultiply[0, 0]); } var subMatrix = mainSubMatrix; for (int i = 3; i < dimension; ++i) { subMatrix = multiplicator.Multiply(mainSubMatrix, subMatrix); vectorsMultiply = multiplicator.Multiply(rowSubMatrix, subMatrix); vectorsMultiply = multiplicator.Multiply(vectorsMultiply, columnSubMatrix); for (int j = 0; j < dimension - i; ++j) { multiplicationMatrix[j + i + 1, j] = this.ring.AdditiveInverse(vectorsMultiply[0, 0]); } } }
/// <summary> /// Obtém o próximo pivô não nulo da matriz. /// </summary> /// <param name="startLine">A linha onde é iniciada a pesquisa.</param> /// <param name="data">A matriz.</param> /// <returns>A linha cujo pivô seja não nulo e -1 caso não exista.</returns> private int GetNextNonEmptyPivotLineNumber(int startLine, IMathMatrix <ObjectType> data) { var result = -1; var matrixDimension = data.GetLength(0); for (int i = startLine + 1; i < matrixDimension; ++i) { if (!this.ring.IsAdditiveUnity(data[i, startLine])) { result = i; i = matrixDimension; } } return(result); }
/// <summary> /// Obtém o próximo pivô não nulo da matriz. /// </summary> /// <param name="startLine">A linha onde é iniciada a pesquisa.</param> /// <param name="pivotColumn">O coluna pivô.</param> /// <param name="data">A matriz.</param> /// <returns>A linha cujo pivô seja não nulo e -1 caso não exista.</returns> private int GetNextNonEmptyPivotLineNumber(int startLine, int pivotColumn, IMathMatrix <ElementType> data) { var result = -1; var matrixDimension = data.GetLength(0); for (int i = startLine + 1; i < matrixDimension; ++i) { if (!this.field.IsAdditiveUnity(data[i, pivotColumn])) { result = i; i = matrixDimension; } } return(result); }
/// <summary> /// Obtém a próxima variável de saída. /// </summary> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <returns>A variável caso exista e -1 caso contrário.</returns> private int GetNextLeavingVariable( int enteringVariable, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <CoeffType> constraintsVector) { var result = -1; var value = this.coeffsField.AdditiveUnity; // Estabelece o primeiro valor para futura comparação. var index = 0; while (index < constraintsMatrix.GetLength(0) && result == -1) { var currentValue = constraintsMatrix[index, enteringVariable]; if (this.coeffsComparer.Compare(currentValue, this.coeffsField.AdditiveUnity) > 0) { value = this.coeffsField.Multiply( constraintsVector[index], this.coeffsField.MultiplicativeInverse(currentValue)); result = index; } ++index; } if (result != -1) { var constraintsLength = constraintsMatrix.GetLength(0); for (int i = index; i < constraintsLength; ++i) { var currentValue = constraintsMatrix[i, enteringVariable]; if (this.coeffsComparer.Compare(currentValue, this.coeffsField.AdditiveUnity) > 0) { currentValue = this.coeffsField.Multiply( constraintsVector[i], this.coeffsField.MultiplicativeInverse(currentValue)); if (this.coeffsComparer.Compare(currentValue, value) < 0) { result = i; value = currentValue; } } } } return(result); }
/// <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> /// Executa o algoritmo sobre a matriz. /// </summary> /// <param name="data">A matriz.</param> /// <returns>O determinante da matriz.</returns> /// <exception cref="MathematicsException">Se a matriz não for quadrada.</exception> public ElementsType Run(IMathMatrix <ElementsType> data) { if (data == null) { return(this.ring.AdditiveUnity); } else { var lines = data.GetLength(0); var columns = data.GetLength(1); if (lines != columns) { throw new MathematicsException("Determinants can only be applied to square matrices."); } else { return(this.ComputeDeterminant(data)); } } }
/// <summary> /// Resolve o sistema de equações com o auxílio da decomposição LDL. /// </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( IMathMatrix <CoeffType> first, IMathMatrix <CoeffType> second) { if (first == null) { throw new ArgumentNullException("first"); } else if (second == null) { throw new ArgumentNullException("second"); } else { var squareMatrix = this.GetSymmetricMatrix(first); var vec = this.GetTransformedVector(first, second); var solution = this.symmSolvAlg.Run(squareMatrix, vec); this.TestSolution(first, second, solution); return(solution); } }
/// <summary> /// Processa a primeira matriz. /// </summary> /// <param name="upperTriangularMatrix">A matriz triangular superior.</param> /// <param name="independent">O vector independente.</param> /// <param name="size">O tamanho das matrizes.</param> private IMathVector <CoeffType> ProcessFirstMatrix( IMathMatrix <CoeffType> upperTriangularMatrix, IMathMatrix <CoeffType> independent, int size) { var result = this.independentVectorFactory.Invoke(size); var field = this.decompositionAlgorithm.Field; for (var j = 0; j < size; ++j) { var sumValue = field.AdditiveUnity; for (var i = 0; i < j; ++i) { var value = upperTriangularMatrix[i, j]; if (field.IsMultiplicativeUnity(value)) { sumValue = field.Add( sumValue, result[i]); } else { value = field.Multiply( value, result[i]); sumValue = field.Add( sumValue, value); } } sumValue = field.AdditiveInverse(sumValue); result[j] = field.Add( independent[j, 0], sumValue); } return(result); }
/// <summary> /// Cria uma nova instância de um objecto do tipo <see cref="LinearConstraintsInput{ConstraintsType}"/>. /// </summary> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector dos coeficientes independentes das restrições.</param> public LinearConstraintsInput( IMathMatrix <ConstraintsType> constraintsMatrix, IMathVector <ConstraintsType> constraintsVector) { if (constraintsMatrix == null) { throw new ArgumentNullException("constraintsMatrix"); } else if (constraintsVector == null) { throw new ArgumentNullException("constraintsVector"); } else if (constraintsMatrix.GetLength(1) != constraintsVector.Length) { throw new ArgumentException("The vector length must match the constraints matrix second dimension."); } else { this.constraintsMatrix = constraintsMatrix; this.constraintsVector = constraintsVector; } }
/// <summary> /// Vefica se o produto da matriz pelo vector actual resulta no esperado. /// </summary> /// <typeparam name="CoeffType"> /// O tipo de objectos que constituem as entradas das estruturas. /// </typeparam> /// <param name="expected">O vector esperado.</param> /// <param name="matrix">a matriz.</param> /// <param name="field"> /// O objecto responsável pelas operações sobre os coeficientes. /// </param> /// <param name="actual">O vector actual.</param> private void AssertVector <CoeffType>( IMathVector <CoeffType> expected, IMathMatrix <CoeffType> matrix, IMathVector <CoeffType> actual, IField <CoeffType> field) { var lines = matrix.GetLength(0); var columns = matrix.GetLength(1); for (var i = 0; i < lines; ++i) { var sum = field.AdditiveUnity; for (var j = 0; j < columns; ++j) { var value = field.Multiply( matrix[i, j], actual[j]); sum = field.Add(sum, value); } Assert.AreEqual(expected[i], sum); } }
/// <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> /// Permite criar uma instância de entrada para o algoritmo do simplex na forma normal de minimização. /// Esta instância poderá corresponder a um estado intermédio deste 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> /// <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 SimplexInput( int[] basicVariables, int[] nonBasicVariables, IMathVector <ObjectiveCoeffType> objectiveFunction, ObjectiveCoeffType cost, IMathMatrix <ConstraintsType> constraintsMatrix, IMathVector <ConstraintsType> constraintsVector) { if (basicVariables == null) { throw new ArgumentNullException("basicVariables"); } else if (nonBasicVariables == null) { throw new ArgumentNullException("nonBasicVariables"); } else if (objectiveFunction == null) { throw new ArgumentNullException("objectiveFunction"); } else if (cost == null) { throw new ArgumentNullException("cost"); } else if (constraintsMatrix == null) { throw new ArgumentNullException("constraintsMatrix"); } else if (constraintsVector == null) { throw new ArgumentNullException("constraintsVector"); } else { if (constraintsMatrix.GetLength(0) != constraintsVector.Length) { throw new ArgumentException( "Constraints matrix must have the same number of lines as constraints vector."); } else if (nonBasicVariables.Length != constraintsMatrix.GetLength(1)) { throw new ArgumentException( "The number of variables must be equal to the number of columns in constraints matrix."); } else if (nonBasicVariables.Length != objectiveFunction.Length) { throw new ArgumentException( "The number of non basic variables must be equal to the number of coefficients in objective funcion."); } else { // Verifica a validade dos índices contidos nas variáveis básicas e não básicas. this.CheckVariablesIndices(basicVariables, nonBasicVariables); this.basicVariables = basicVariables; this.nonBasicVariables = nonBasicVariables; this.objectiveFunction = objectiveFunction; this.cost = cost; this.constraintsMatrix = constraintsMatrix; this.constraintsVector = constraintsVector; } } }
/// <summary> /// Obtém a variável de entrada. /// </summary> /// <param name="dualVector">O vector dual que irá permitir calcular os coeficientes do custo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="objectiveFunction">A função objectivo.</param> /// <param name="nonBasicVariables">As variáveis não básicas.</param> /// <returns>O índice da variável a entrar.</returns> private int GetNextEnteringVariable( SimplexMaximumNumberField <CoeffType>[] dualVector, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <SimplexMaximumNumberField <CoeffType> > objectiveFunction, int[] nonBasicVariables) { var result = -1; var value = new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveUnity); var nonBasicLength = nonBasicVariables.Length; var constraintsLinesLength = dualVector.Length; var syncObject = new object(); // Utilizado para sincronizar as comparações. Parallel.For(0, nonBasicLength, i => { var finitePart = this.coeffsField.AdditiveUnity; var bigPart = this.coeffsField.AdditiveUnity; var nonBasicVariable = nonBasicVariables[i]; if (nonBasicVariable < nonBasicLength) { for (int j = 0; j < constraintsLinesLength; ++j) { var dualVectorEntry = dualVector[j]; var constraintsMatrixEntry = constraintsMatrix[j, nonBasicVariable]; var finiteValueToAdd = this.coeffsField.Multiply(dualVectorEntry.FinitePart, constraintsMatrixEntry); var bigValueToAdd = this.coeffsField.Multiply(dualVectorEntry.BigPart, constraintsMatrixEntry); var objectiveValue = objectiveFunction[nonBasicVariable]; finiteValueToAdd = this.coeffsField.Add(finiteValueToAdd, objectiveValue.FinitePart); bigValueToAdd = this.coeffsField.Add(bigValueToAdd, objectiveValue.BigPart); finitePart = this.coeffsField.Add(finitePart, finiteValueToAdd); bigPart = this.coeffsField.Add(bigPart, bigValueToAdd); } lock (syncObject) { var comparisionValue = this.coeffsComparer.Compare(bigPart, value.BigPart); if (comparisionValue < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } else if (comparisionValue == 0) { if (this.coeffsComparer.Compare(finitePart, value.FinitePart) < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } } } } else { var index = nonBasicVariable - nonBasicLength; var dualValue = dualVector[index]; finitePart = dualValue.FinitePart; bigPart = dualValue.BigPart; lock (syncObject) { var comparisionValue = this.coeffsComparer.Compare(bigPart, value.BigPart); if (comparisionValue < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } else if (comparisionValue == 0) { if (this.coeffsComparer.Compare(finitePart, value.FinitePart) < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } } } } }); return(result); }
/// <summary> /// Processa as restantes matrizes. /// </summary> /// <param name="upperTriangMatrix">A matriz triangular superior.</param> /// <param name="diagMatrix">A matriz diagonal.</param> /// <param name="independent">O vector independente.</param> /// <param name="size">O tamanho das matrizes.</param> /// <param name="solution">A solução do sistema.</param> private void ProcessRemainingMatrices( IMathMatrix <CoeffType> upperTriangMatrix, IMathMatrix <CoeffType> diagMatrix, IMathVector <CoeffType> independent, int size, LinearSystemSolution <CoeffType> solution) { var field = this.decompositionAlgorithm.Field; var innerSize = size - 1; for (var i = innerSize; i >= 0; --i) { var diagValue = diagMatrix[i, i]; if (field.IsAdditiveUnity(diagValue)) { var basisVector = this.basisVectorFactory.Invoke( size, field.AdditiveUnity); var basisVal = field.MultiplicativeUnity; basisVector[i] = basisVal; for (var j = i - 1; j >= 0; --j) { if (!field.IsAdditiveUnity(diagMatrix[j, j])) { var curr = upperTriangMatrix[j, i]; curr = field.Multiply( curr, basisVal); curr = field.AdditiveInverse(curr); basisVector[j] = field.Add( basisVector[j], curr); } } solution.VectorSpaceBasis.Add(basisVector); } else { var value = independent[i]; if (!field.IsAdditiveUnity(value)) { for (var j = i - 1; j >= 0; --j) { if (!field.IsAdditiveUnity(diagMatrix[j, j])) { var curr = upperTriangMatrix[j, i]; curr = field.Multiply( curr, value); curr = field.AdditiveInverse(curr); independent[j] = field.Add( independent[j], curr); } } } var basis = solution.VectorSpaceBasis; var basisCount = basis.Count; for (var k = 0; k < basisCount; ++k) { var vec = basis[k]; var basisVal = vec[i]; if (!field.IsAdditiveUnity(basisVal)) { for (var j = i - 1; j >= 0; --j) { if (!field.IsAdditiveUnity(diagMatrix[j, j])) { var curr = upperTriangMatrix[j, i]; curr = field.Multiply( curr, basisVal); curr = field.AdditiveInverse(curr); vec[j] = field.Add( vec[j], curr); } } } } } } solution.Vector = independent; }
/// <summary> /// Aplica a condensação a todas as linhas da matriz das restrições. /// </summary> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="leavingVariable">A variável de saída.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> private void ProcessReduction( int enteringVariable, int leavingVariable, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <CoeffType> constraintsVector) { // Actualiza a linha pivô var multiplicativeProduct = constraintsMatrix[leavingVariable, enteringVariable]; var constraintsColumnLength = constraintsMatrix.GetLength(1); if (!this.coeffsField.IsMultiplicativeUnity(multiplicativeProduct)) { multiplicativeProduct = this.coeffsField.MultiplicativeInverse(multiplicativeProduct); Parallel.For(0, enteringVariable, i => { constraintsMatrix[leavingVariable, i] = this.coeffsField.Multiply( constraintsMatrix[leavingVariable, i], multiplicativeProduct); }); Parallel.For(enteringVariable + 1, constraintsColumnLength, i => { constraintsMatrix[leavingVariable, i] = this.coeffsField.Multiply( constraintsMatrix[leavingVariable, i], multiplicativeProduct); }); constraintsVector[leavingVariable] = this.coeffsField.Multiply( constraintsVector[leavingVariable], multiplicativeProduct); constraintsMatrix[leavingVariable, enteringVariable] = multiplicativeProduct; } Parallel.For(0, leavingVariable, line => { var innerMultiplicativeProduct = constraintsMatrix[line, enteringVariable]; if (!this.coeffsField.IsAdditiveUnity(innerMultiplicativeProduct)) { innerMultiplicativeProduct = this.coeffsField.AdditiveInverse( innerMultiplicativeProduct); for (int column = 0; column < enteringVariable; ++column) { constraintsMatrix[line, column] = this.coeffsField.Add( constraintsMatrix[line, column], this.coeffsField.Multiply(constraintsMatrix[leavingVariable, column], innerMultiplicativeProduct)); } var pivotColumnValue = innerMultiplicativeProduct; if (!this.coeffsField.IsMultiplicativeUnity(multiplicativeProduct)) { pivotColumnValue = this.coeffsField.Multiply(innerMultiplicativeProduct, multiplicativeProduct); } constraintsMatrix[line, enteringVariable] = pivotColumnValue; for (int column = enteringVariable + 1; column < constraintsColumnLength; ++column) { constraintsMatrix[line, column] = this.coeffsField.Add( constraintsMatrix[line, column], this.coeffsField.Multiply(constraintsMatrix[leavingVariable, column], innerMultiplicativeProduct)); } constraintsVector[line] = this.coeffsField.Add( constraintsVector[line], this.coeffsField.Multiply(constraintsVector[leavingVariable], innerMultiplicativeProduct)); } }); var constraintsLineLength = constraintsMatrix.GetLength(0); Parallel.For(leavingVariable + 1, constraintsLineLength, line => { var innerMultiplicativeProduct = constraintsMatrix[line, enteringVariable]; if (!this.coeffsField.IsAdditiveUnity(innerMultiplicativeProduct)) { innerMultiplicativeProduct = this.coeffsField.AdditiveInverse( constraintsMatrix[line, enteringVariable]); for (int column = 0; column < enteringVariable; ++column) { constraintsMatrix[line, column] = this.coeffsField.Add( constraintsMatrix[line, column], this.coeffsField.Multiply(constraintsMatrix[leavingVariable, column], innerMultiplicativeProduct)); } var pivotColumnValue = innerMultiplicativeProduct; if (!this.coeffsField.IsMultiplicativeUnity(multiplicativeProduct)) { pivotColumnValue = this.coeffsField.Multiply(innerMultiplicativeProduct, multiplicativeProduct); } constraintsMatrix[line, enteringVariable] = pivotColumnValue; for (int column = enteringVariable + 1; column < constraintsColumnLength; ++column) { constraintsMatrix[line, column] = this.coeffsField.Add( constraintsMatrix[line, column], this.coeffsField.Multiply(constraintsMatrix[leavingVariable, column], innerMultiplicativeProduct)); } constraintsVector[line] = this.coeffsField.Add( constraintsVector[line], this.coeffsField.Multiply(constraintsVector[leavingVariable], innerMultiplicativeProduct)); } }); }
/// <summary> /// Aplica o método de condensação a uma matriz dependente baseando-se na matriz inicial. /// </summary> /// <remarks> /// As matrizes de entrada serão alteradas. No final, a matriz inicial é condensada e as mesmas operações /// são efectuadas sobre todas as linhas da segunda matriz. /// </remarks> /// <param name="initialMatrix">A matriz de coeficientes.</param> /// <param name="finalMatrix">A matriz dependente.</param> /// <returns>Verdadeiro caso tenha sido realizada alguma operação e falso caso contrário.</returns> /// <exception cref="ArgumentNullException">Se pelo menos um dos argumentos for nulo.</exception> /// <exception cref="MathematicsException"> /// Se o número de linhas da matriz não conicidir com o tamanho do vector. /// </exception> public bool Run( IMathMatrix <ElementType> initialMatrix, IMathMatrix <ElementType> finalMatrix) { if (initialMatrix == null) { throw new ArgumentNullException("initialMatrix"); } else if (finalMatrix == null) { throw new ArgumentNullException("finalMatrix"); } else if (initialMatrix.GetLength(0) != finalMatrix.GetLength(0)) { throw new MathematicsException( "Linear system matrix must have the same number of lines as independent vector."); } else if (initialMatrix.GetLength(0) == 0) { return(false); } else { var result = false; var initialMatrixLines = initialMatrix.GetLength(0); var initialMatrixColumns = initialMatrix.GetLength(1); var matrixDimension = Math.Min(initialMatrixLines, initialMatrixColumns); var finalMatrixColumns = finalMatrix.GetLength(1); var i = 0; var currentPivotColumn = 0; while (i < initialMatrixLines - 1 && currentPivotColumn < initialMatrixColumns) { var pivotValue = initialMatrix[i, currentPivotColumn]; if (this.field.IsAdditiveUnity(pivotValue)) { var nextPivotCandidate = this.GetNextNonEmptyPivotLineNumber( i, currentPivotColumn, initialMatrix); if (nextPivotCandidate != -1) { initialMatrix.SwapLines(i, nextPivotCandidate); finalMatrix.SwapLines(i, nextPivotCandidate); pivotValue = initialMatrix[i, currentPivotColumn]; result = true; } } if (!this.field.IsAdditiveUnity(pivotValue)) { if (!this.field.IsMultiplicativeUnity(pivotValue)) { result = true; initialMatrix[i, currentPivotColumn] = this.field.MultiplicativeUnity; for (int j = currentPivotColumn + 1; j < initialMatrix.GetLength(1); ++j) { var value = initialMatrix[i, j]; if (!this.field.IsAdditiveUnity(value)) { value = this.field.Multiply( value, this.field.MultiplicativeInverse(pivotValue)); initialMatrix[i, j] = value; } } for (int j = 0; j < finalMatrixColumns; ++j) { var value = finalMatrix[i, j]; if (!this.field.IsAdditiveUnity(value)) { value = this.field.Multiply( value, this.field.MultiplicativeInverse(pivotValue)); finalMatrix[i, j] = value; } } } for (int j = i + 1; j < initialMatrixLines; ++j) { var value = initialMatrix[j, currentPivotColumn]; if (!this.field.IsAdditiveUnity(value)) { result = true; initialMatrix[j, i] = this.field.AdditiveUnity; for (int k = i + 1; k < matrixDimension; ++k) { var temp = this.field.Multiply(value, initialMatrix[i, k]); initialMatrix[j, k] = this.field.Add( initialMatrix[j, k], this.field.AdditiveInverse(temp)); } for (int k = 0; k < finalMatrixColumns; ++k) { var temp = this.field.Multiply(value, finalMatrix[i, k]); finalMatrix[j, k] = this.field.Add( finalMatrix[j, k], this.field.AdditiveInverse(temp)); } } } ++i; } ++currentPivotColumn; } i = Math.Min(initialMatrixLines - 1, initialMatrixColumns - 1); currentPivotColumn = i; var state = true; while (state) { var currenPivotValue = initialMatrix[i, currentPivotColumn]; if (this.field.IsMultiplicativeUnity(currenPivotValue)) { state = false; } else if (this.field.IsAdditiveUnity(currenPivotValue)) { ++currentPivotColumn; if (currentPivotColumn >= initialMatrixColumns) { --i; if (i < 0) { state = false; } else { currentPivotColumn = i; } } } } while (i > 0 && currentPivotColumn > 0) { var pivotValue = initialMatrix[i, currentPivotColumn]; if (this.field.IsMultiplicativeUnity(pivotValue)) { for (int j = i - 1; j >= 0; --j) { var value = initialMatrix[j, currentPivotColumn]; if (!this.field.IsAdditiveUnity(value)) { result = true; initialMatrix[j, currentPivotColumn] = this.field.AdditiveUnity; for (int k = currentPivotColumn + 1; k < matrixDimension; ++k) { var temp = this.field.Multiply(value, initialMatrix[i, k]); initialMatrix[j, k] = this.field.Add( initialMatrix[j, k], this.field.AdditiveInverse(temp)); } for (int k = 0; k < finalMatrixColumns; ++k) { var temp = this.field.Multiply(value, finalMatrix[i, k]); finalMatrix[j, k] = this.field.Add( finalMatrix[j, k], this.field.AdditiveInverse(temp)); } } } } --i; --currentPivotColumn; } return(result); } }