/// <summary> /// Obtém um vector com todos os elementos de uma linha, incluindo os valores por defeito. /// </summary> /// <typeparam name="T">O tipo de objectos que constituem as entradas da matriz.</typeparam> /// <param name="line">A linha.</param> /// <param name="matrix">A matriz.</param> /// <returns>O vector com as entradas correspondentes à linha da matriz especificada.</returns> private T[] GetLineAsArray <T>(int line, SparseDictionaryMathMatrix <T> matrix) { var matrixColumnsNumber = matrix.GetLength(1); var currentMatrixLine = default(ILongSparseMatrixLine <T>); var result = new T[matrixColumnsNumber]; if (matrix.TryGetLine(line, out currentMatrixLine)) { for (int i = 0; i < matrixColumnsNumber; ++i) { var currentValue = default(T); if (currentMatrixLine.TryGetColumnValue(i, out currentValue)) { result[i] = currentMatrixLine[i]; } else { result[i] = matrix.DefaultValue; } } } else { for (int i = 0; i < result.Length; ++i) { result[i] = matrix.DefaultValue; } } return(result); }
/// <summary> /// Verifica a validade da combinação de uma linha com a próxima tendo em conta os factores proporcionados. /// </summary> /// <typeparam name="T">O tipo de objectos que constituem as entradas das matrizes.</typeparam> /// <param name="target">A matriz.</param> /// <param name="firstFactor">O factor afecto à linha a ser substituída.</param> /// <param name="secondFactor">O factor afecto à linha a ser combinada.</param> /// <param name="ring">O anel responsável pelas operações sobre os coeficientes.</param> private void AssertTarget <T>( SparseDictionaryMathMatrix <T> target, T firstFactor, T secondFactor, IRing <T> ring) { var numberOfLines = target.GetLength(0); var numberOfColumns = target.GetLength(1); var firstLine = 0; var secondLine = 1; while (secondLine < numberOfLines) { var firstArray = this.GetLineAsArray(firstLine, target); var secondArray = this.GetLineAsArray(secondLine, target); this.CombineArrays(firstArray, secondArray, firstFactor, secondFactor, ring); target.CombineLines(firstLine, secondLine, firstFactor, secondFactor, ring); var targetLine = default(ILongSparseMatrixLine <T>); if (target.TryGetLine(firstLine, out targetLine)) { for (int i = 0; i < numberOfColumns; ++i) { var targetValue = default(T); if (!targetLine.TryGetColumnValue(i, out targetValue)) { targetValue = target.DefaultValue; } Assert.AreEqual(firstArray[i], targetValue); } } else { for (int i = 0; i < numberOfColumns; ++i) { Assert.AreEqual(firstArray[i], target.DefaultValue); } } ++firstLine; ++secondLine; } }
/// <summary> /// Verifica a validade de todas as linhas com excepção da linha especificada. /// </summary> /// <param name="line">A linha a ser ignorada.</param> /// <param name="matrix">A matriz a ser verificada.</param> private void AssertLinesExcept(int line, SparseDictionaryMathMatrix <Fraction <int> > matrix) { var lineDimension = matrix.GetLength(0); var columnDimension = matrix.GetLength(1); var assertMatrix = this.GetDefaultMatrix(matrix.DefaultValue); for (int i = 0; i < line; ++i) { for (int j = 0; j < columnDimension; ++j) { Assert.AreEqual(assertMatrix[i, j], matrix[i, j]); } } for (int i = line + 1; i < lineDimension; ++i) { for (int j = 0; j < columnDimension; ++j) { Assert.AreEqual(assertMatrix[i, j], matrix[i, j]); } } }
/// <summary> /// Obtém o custo inicial da matriz especificada. /// </summary> /// <param name="matrix">A matriz.</param> /// <returns>O custo.</returns> private ElementType GetMatrixInitialCost(SparseDictionaryMathMatrix <ElementType> matrix) { var result = this.ring.AdditiveUnity; if (matrix.GetLength(0) > 0) { var firstLine = matrix[0]; var coverColumns = firstLine.GetColumns(); foreach (var column in coverColumns) { result = this.ring.Add(result, column.Value); } } return(result); }
/// <summary> /// Aplica o algoritmo sobre a matriz dos custos. /// </summary> /// <param name="costs">A matriz dos custos.</param> /// <param name="numberOfMedians">O número de medianas a serem escolhidas.</param> /// <returns>O resultado da relaxação.</returns> public CoeffType[] Run(SparseDictionaryMathMatrix <CoeffType> costs, int numberOfMedians) { if (costs == null) { throw new ArgumentNullException("costs"); } else { var numberOfVertices = costs.GetLength(1); var objectiveFunction = new List <SimplexMaximumNumberField <CoeffType> >(); // A mediana que cobre todas as outras é ligeiramente diferente objectiveFunction.Add(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveInverse(this.coeffsField.MultiplicativeUnity))); for (int i = 1; i < numberOfVertices; ++i) { objectiveFunction.Add(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AddRepeated( this.coeffsField.AdditiveInverse(this.coeffsField.MultiplicativeUnity), 2))); } // Adiciona as variáveis x à função objectivo. var numberXVars = 0; foreach (var line in costs.GetLines()) { foreach (var column in line.Value.GetColumns()) { if (line.Key != column.Key) { ++numberXVars; var valueToAdd = new SimplexMaximumNumberField <CoeffType>( column.Value, this.coeffsField.AdditiveInverse(this.coeffsField.MultiplicativeUnity)); objectiveFunction.Add(valueToAdd); } } } // Cria a matriz das restrições e preenche-a com os valores correctos var constraintsNumber = numberXVars + numberOfVertices; var nonBasicVariables = new int[objectiveFunction.Count]; var basicVariables = new int[constraintsNumber]; var linesLength = nonBasicVariables.Length + basicVariables.Length; // Preence os vectores que permitem seleccionar as variáveis. this.FillVariablesSelectors(nonBasicVariables, basicVariables, linesLength); // Preencimento da matriz das restrições var constraintsMatrix = new ArrayMathMatrix <CoeffType>( constraintsNumber, constraintsNumber, this.coeffsField.AdditiveUnity); var constraintLineNumber = 0; var constraintXYLineNumber = 0; var unity = this.coeffsField.MultiplicativeUnity; var inverseAdditive = this.coeffsField.AdditiveInverse(unity); foreach (var line in costs.GetLines()) { foreach (var column in line.Value.GetColumns()) { if (line.Key != column.Key) { constraintsMatrix[constraintXYLineNumber, constraintLineNumber] = inverseAdditive; constraintsMatrix[constraintXYLineNumber, constraintXYLineNumber + numberOfVertices] = unity; ++constraintXYLineNumber; } } ++constraintLineNumber; } var lastLine = constraintsNumber - 1; constraintsMatrix[lastLine, 0] = unity; constraintLineNumber = numberXVars; for (int i = 1; i < numberOfVertices; ++i) { constraintsMatrix[constraintLineNumber, i] = unity; constraintsMatrix[lastLine, i] = unity; constraintXYLineNumber = numberOfVertices; foreach (var lines in costs.GetLines()) { foreach (var column in lines.Value.GetColumns()) { if (lines.Key != column.Key) { if (column.Key == i) { constraintsMatrix[constraintLineNumber, constraintXYLineNumber] = unity; } ++constraintXYLineNumber; } } } ++constraintLineNumber; } // Preenchimento do vector independente das restrições var vector = new ArrayMathVector <CoeffType>(constraintsNumber, this.coeffsField.AdditiveUnity); lastLine = constraintsNumber - 1; for (int i = numberXVars; i < lastLine; ++i) { vector[i] = unity; } vector[lastLine] = this.conversion.InverseConversion(numberOfMedians); var sumVector = this.coeffsField.AdditiveUnity; for (int i = 0; i < vector.Length; ++i) { sumVector = this.coeffsField.Add(sumVector, vector[i]); } sumVector = this.coeffsField.AdditiveInverse(sumVector); var simplexInput = new SimplexInput <CoeffType, SimplexMaximumNumberField <CoeffType> >( basicVariables, nonBasicVariables, new ArrayMathVector <SimplexMaximumNumberField <CoeffType> >(objectiveFunction.ToArray()), new SimplexMaximumNumberField <CoeffType>(this.coeffsField.AdditiveUnity, sumVector), constraintsMatrix, vector); var resultSimplexSol = this.simplexAlg.Run(simplexInput); var result = new CoeffType[numberOfVertices]; Array.Copy(resultSimplexSol.Solution, result, numberOfVertices); return(result); } }