/// <summary> /// Calcula o custo da substituição de uma mediana por outra. /// </summary> /// <param name="replacementMedian">A mediana que substitui.</param> /// <param name="medianToBeReplaced">A mediana que é substituída.</param> /// <param name="existingMedians">As medianas que forma escolhidas.</param> /// <param name="costs">A matriz dos custos.</param> /// <param name="currentSolutionBoard">O quadro de solução actual.</param> /// <param name="replacementSolutionBoard">O quadro da solução substituída.</param> /// <returns>O valor do mínimo.</returns> private CoeffType ComputeReplacementCost( int replacementMedian, int medianToBeReplaced, IntegerSequence existingMedians, ILongSparseMathMatrix <CoeffType> costs, CoeffType[] currentSolutionBoard, CoeffType[] replacementSolutionBoard) { Array.Copy(currentSolutionBoard, replacementSolutionBoard, currentSolutionBoard.Length); var result = this.coeffsField.AdditiveUnity; var minimum = this.GetMinimumFromColumn( existingMedians, medianToBeReplaced, medianToBeReplaced, costs); replacementSolutionBoard[medianToBeReplaced] = minimum; result = this.coeffsField.Add(result, minimum); var boardValue = currentSolutionBoard[replacementMedian]; replacementSolutionBoard[replacementMedian] = this.coeffsField.AdditiveUnity; result = this.coeffsField.Add( result, this.coeffsField.AdditiveInverse(boardValue)); // Remove a linha a ser substituída. var currentRow = default(ILongSparseMatrixLine <CoeffType>); if (costs.TryGetLine(medianToBeReplaced, out currentRow)) { foreach (var column in currentRow.GetColumns()) { if (column.Key != medianToBeReplaced && column.Key != replacementMedian) { if (this.coeffsField.Equals(column.Value, replacementSolutionBoard[column.Key])) { var current = replacementSolutionBoard[column.Key]; minimum = this.GetMinimumFromColumn( existingMedians, medianToBeReplaced, column.Key, costs); replacementSolutionBoard[column.Key] = minimum; var temp = this.coeffsField.Add( minimum, this.coeffsField.AdditiveInverse(current)); result = this.coeffsField.Add(result, temp); } } } } // Insere a linha a substituir. if (costs.TryGetLine(replacementMedian, out currentRow)) { foreach (var column in currentRow.GetColumns()) { if (column.Key != replacementMedian) { var current = replacementSolutionBoard[column.Key]; if (this.comparer.Compare(column.Value, current) < 0) { replacementSolutionBoard[column.Key] = column.Value; var temp = this.coeffsField.Add( column.Value, this.coeffsField.AdditiveInverse(current)); result = this.coeffsField.Add(result, temp); } } } } return(result); }
/// <summary> /// Permite obter o valor mínimo entre as colunas da matriz para as linhas escolhidas com excepção /// de uma delas. /// </summary> /// <param name="chosen">As linhas escolhidas.</param> /// <param name="exceptLine"> /// A linha que não vai ser considerada.</param> /// <param name="column">A coluna sobre a qual é calculado o mínimo.</param> /// <param name="costs">A matriz dos custos.</param> /// <returns>O valor do custo mínimo.</returns> private CoeffType GetMinimumFromColumn( IntegerSequence chosen, int exceptLine, int column, ILongSparseMathMatrix <CoeffType> costs) { var result = default(CoeffType); var chosenEnumerator = chosen.GetEnumerator(); var state = chosenEnumerator.MoveNext(); var keep = true; while (state && keep) { // Pesquisa pelo primeiro elemento. var currentChosen = chosenEnumerator.Current; if (currentChosen != exceptLine) { var currentLine = default(ILongSparseMatrixLine <CoeffType>); if (costs.TryGetLine(currentChosen, out currentLine)) { var columnValue = default(CoeffType); if (currentLine.TryGetColumnValue(column, out columnValue)) { if (this.coeffsField.IsAdditiveUnity(columnValue)) { return(columnValue); } else { result = columnValue; keep = false; } } } } state = chosenEnumerator.MoveNext(); } if (keep) { throw new OdmpProblemException("Something went very wrong. Check if costs matrix is valid."); } else { while (state) { var currentChosen = chosenEnumerator.Current; if (currentChosen != exceptLine) { var currentLine = default(ILongSparseMatrixLine <CoeffType>); if (costs.TryGetLine(currentChosen, out currentLine)) { var columnValue = default(CoeffType); if (currentLine.TryGetColumnValue(column, out columnValue)) { if (this.coeffsField.IsAdditiveUnity(columnValue)) { return(columnValue); } else { if (this.comparer.Compare(columnValue, result) < 0) { result = columnValue; } } } } } state = chosenEnumerator.MoveNext(); } } return(result); }
/// <summary> /// Permite calcular o custo associado à escolha de um conjunto de medianas escolhidas. /// </summary> /// <param name="chosen">O conjunto de medianas escolhidas.</param> /// <param name="costs">A matriz dos custos.</param> /// <param name="solutionBoard">A linha que mantém os mínimos por mediana.</param> /// <returns>O valor do custo associado à escolha.</returns> private CoeffType ComputeCost( IntegerSequence chosen, ILongSparseMathMatrix <CoeffType> costs, CoeffType[] solutionBoard, BitArray marked) { var resultCost = this.coeffsField.AdditiveUnity; foreach (var item in chosen) { var currentCostLine = default(ILongSparseMatrixLine <CoeffType>); if (costs.TryGetLine(item, out currentCostLine)) { foreach (var column in currentCostLine.GetColumns()) { if (column.Key == item) { if (marked[item]) { resultCost = this.coeffsField.Add( resultCost, this.coeffsField.AdditiveInverse(solutionBoard[item])); } else { marked[item] = true; } solutionBoard[item] = this.coeffsField.AdditiveUnity; } else { if (marked[column.Key]) { var boardCost = solutionBoard[column.Key]; if (this.comparer.Compare(column.Value, boardCost) < 0) { solutionBoard[column.Key] = column.Value; var difference = this.coeffsField.Add( column.Value, this.coeffsField.AdditiveInverse(boardCost)); resultCost = this.coeffsField.Add( resultCost, difference); } } else { resultCost = this.coeffsField.Add( resultCost, column.Value); solutionBoard[column.Key] = column.Value; marked[column.Key] = true; } } } } else { marked[item] = true; solutionBoard[item] = this.coeffsField.AdditiveUnity; } } for (int i = 0; i < marked.Length; ++i) { if (!marked[i] && !chosen.Contains(i)) { throw new OdmpProblemException("Not all nodes are covered by some median."); } } return(resultCost); }