/// <summary> /// Obtém a solução do problema a partir das variáveis de compatibilidade. /// </summary> /// <param name="resultCosts">Os custos por componente.</param> /// <param name="variables">A lista das variáveis escolhidas.</param> /// <param name="costsMatrices">As matrizes de custos.</param> /// <returns>A solução.</returns> private GreedyAlgSolution <CostsType>[] GetSolution( CostsType[] resultCosts, List <CoordsElement>[] variables, List <ILongSparseMathMatrix <CostsType> > costsMatrices) { var result = new GreedyAlgSolution <CostsType> [variables.Length]; for (int i = 0; i < result.Length; ++i) { var integerSequence = new IntegerSequence(); integerSequence.Add(0, costsMatrices[i].GetLength(0) - 1); var currentVariables = variables[i]; for (int j = 0; j < currentVariables.Count; ++j) { var column = currentVariables[j].Column; integerSequence.Remove(column); } var algSol = new GreedyAlgSolution <CostsType>(integerSequence); algSol.Cost = resultCosts[i]; result[i] = algSol; } return(result); }
public virtual GreedyAlgSolution <CostType> Clone() { var result = new GreedyAlgSolution <CostType>(); result.chosen = this.chosen.Clone(); result.cost = this.cost; return(result); }
/// <summary> /// Inicializa a solução. /// </summary> /// <param name="boards">As linhas condensadas por matriz.</param> /// <returns>A solução inicializada.</returns> private GreedyAlgSolution <ElementType>[] SetupResults(ElementType[][] boards) { var results = new GreedyAlgSolution <ElementType> [boards.Length]; for (int i = 0; i < boards.Length; ++i) { var linesCount = boards[i].Length; results[i] = new GreedyAlgSolution <ElementType>() { Cost = this.ring.AdditiveUnity }; results[i].Chosen.Add(0, linesCount - 1); } return(results); }
/// <summary> /// Obtém uma solução corrigida a partir de uma inicial. /// </summary> /// <param name="refsNumber">O número de referências.</param> /// <param name="matrix">A matriz.</param> /// <param name="initialSolution">A solução inicial.</param> /// <param name="initialLineBoard">A linha condensada inicial.</param> /// <returns> /// A solução obtida. /// </returns> public GreedyAlgSolution <ElementType> Run( int refsNumber, SparseDictionaryMathMatrix <ElementType> matrix, GreedyAlgSolution <ElementType> initialSolution, ElementType[] initialLineBoard) { if (refsNumber < 1) { throw new ArgumentException("The number of references must be at least one."); } else if (matrix == null) { throw new ArgumentNullException("matrix"); } else if (initialSolution == null) { throw new ArgumentNullException("initialSolution"); } else if (initialLineBoard == null) { throw new ArgumentNullException("initialLineBoard"); } else { var greedyAlgResult = initialSolution.Clone(); var initialRefsNumber = greedyAlgResult.Chosen.Count; if (refsNumber < initialRefsNumber) { var refGetAlg = this.inverseRefGetAlgorithm; while (refsNumber < initialRefsNumber) { var nextRef = refGetAlg.Run(greedyAlgResult.Chosen, matrix, initialLineBoard); if (nextRef.Item1 == -1) { return(null); } else { greedyAlgResult.Chosen.Remove(greedyAlgResult.Chosen[nextRef.Item1]); greedyAlgResult.Cost = this.ring.Add(greedyAlgResult.Cost, nextRef.Item2); } } } else if (refsNumber > initialRefsNumber) { var refGetAlg = this.directRefGetAlgorithm; var nextRef = refGetAlg.Run(greedyAlgResult.Chosen, matrix, initialLineBoard); if (nextRef.Item1 == -1) { return(null); } else { greedyAlgResult.Chosen.Remove(greedyAlgResult.Chosen[nextRef.Item1]); greedyAlgResult.Cost = this.ring.Add( greedyAlgResult.Cost, this.ring.AdditiveInverse(nextRef.Item2)); } } return(greedyAlgResult); } }
/// <summary> /// Obtém os valores iniciais das variáveis lambda. /// </summary> /// <param name="matrix">A matriz dos custos.</param> /// <param name="greedySolution">A solução do algoritmo guloso.</param> /// <param name="dualInput">A entrada para o algoritmo dual propriamente dito.</param> /// <returns>Verdadeiro caso o algoritmo seja bem sucedido e falso caso contrário.</returns> public bool Run( SparseDictionaryMathMatrix <ElementType> matrix, GreedyAlgSolution <ElementType> greedySolution, DualHeuristicAlgInput <ElementType> dualInput) { if (matrix == null) { throw new ArgumentNullException("matrix"); } else if (greedySolution == null) { throw new ArgumentNullException("greedySolution"); } else if (dualInput == null) { throw new ArgumentNullException("dualInput"); } else { dualInput.Lambdas.Clear(); var componentEnum = matrix.GetLines().GetEnumerator(); if (componentEnum.MoveNext()) { dualInput.Lambdas.Add(componentEnum.Current.Key, this.ring.AdditiveUnity); foreach (var column in componentEnum.Current.Value.GetColumns()) { if (column.Key != componentEnum.Current.Key) { if (greedySolution.Chosen.Contains(column.Key)) { dualInput.Lambdas.Add(column.Key, this.ring.AdditiveUnity); } else { dualInput.Lambdas.Add(column.Key, column.Value); } } } while (componentEnum.MoveNext()) { if (greedySolution.Chosen.Contains(componentEnum.Current.Key)) { foreach (var column in componentEnum.Current.Value.GetColumns()) { if (column.Key != componentEnum.Current.Key) { var forComponentValue = this.ring.AdditiveUnity; if (dualInput.Lambdas.TryGetValue(column.Key, out forComponentValue)) { if (this.comparer.Compare(column.Value, forComponentValue) < 0) { dualInput.Lambdas[column.Key] = column.Value; } } else { dualInput.Lambdas.Add(column.Key, this.ring.AdditiveUnity); } } } } } } return(true); } }
/// <summary> /// Obtém uma solução a partir duma aproximação inicial. /// </summary> /// <param name="approximateMedians">As medianas.</param> /// <param name="costs">Os custos.</param> /// <param name="niter">O número máximo melhoramentos a serem aplicados à solução encontrada.</param> /// <returns>A solução construída a partir da aproximação.</returns> public GreedyAlgSolution <CoeffType> Run( CoeffType[] approximateMedians, ILongSparseMathMatrix <CoeffType> costs, int niter) { if (approximateMedians == null) { throw new ArgumentNullException("approximateMedians"); } else if (costs == null) { throw new ArgumentNullException("costs"); } else if (approximateMedians.Length != costs.GetLength(1)) { throw new ArgumentException("The number of medians must match the number of columns in costs matrix."); } else { var settedSolutions = new IntegerSequence(); var approximateSolutions = new List <int>(); var sum = this.coeffsField.AdditiveUnity; for (int i = 0; i < approximateMedians.Length; ++i) { var currentMedian = approximateMedians[i]; if (!this.coeffsField.IsAdditiveUnity(currentMedian)) { sum = this.coeffsField.Add(sum, approximateMedians[i]); if (this.converter.CanApplyDirectConversion(currentMedian)) { var converted = this.converter.DirectConversion(currentMedian); if (converted == 1) { settedSolutions.Add(i); } else { throw new OdmpProblemException(string.Format( "The median {0} at position {1} of medians array can't be converted to the unity.", currentMedian, i)); } } else { approximateSolutions.Add(i); } } } if (this.converter.CanApplyDirectConversion(sum)) { var convertedSum = this.converter.DirectConversion(sum); if (convertedSum <= 0 || convertedSum > approximateMedians.Length) { throw new IndexOutOfRangeException(string.Format( "The medians sum {0} is out of bounds. It must be between 1 and the number of elements in medians array.", convertedSum)); } var solutionBoard = new CoeffType[approximateMedians.Length]; var marked = new BitArray(approximateMedians.Length, false); if (settedSolutions.Count == convertedSum) { var result = new GreedyAlgSolution <CoeffType>(settedSolutions); result.Cost = this.ComputeCost(settedSolutions, costs, solutionBoard, marked); return(result); } else { // Partição das mediana em dois conjuntos: as que vão falzer parte da solução e as restantes // entre as soluções aproximadas. var recoveredMedians = new List <int>(); var unrecoveredMedians = new List <int>(); var innerComparer = new InnerComparer(approximateMedians, this.comparer); approximateSolutions.Sort(innerComparer); var count = convertedSum - settedSolutions.Count; var i = 0; for (; i < count; ++i) { recoveredMedians.Add(approximateSolutions[i]); settedSolutions.Add(approximateSolutions[i]); } for (; i < approximateSolutions.Count; ++i) { unrecoveredMedians.Add(approximateSolutions[i]); } var currentCost = this.ComputeCost(settedSolutions, costs, solutionBoard, marked); // Processa as melhorias de uma forma simples caso seja possível if (unrecoveredMedians.Count > 0 && niter > 0) { var exchangeSolutionBoard = new CoeffType[solutionBoard.Length]; var currentBestBoard = new CoeffType[solutionBoard.Length]; for (i = 0; i < niter; ++i) { var itemToExchange = -1; var itemToExchangeIndex = -1; var itemToExchangeWith = -1; var itemToExchangeWithIndex = -1; var minimumCost = this.coeffsField.AdditiveUnity; for (int j = 0; j < recoveredMedians.Count; ++j) { for (int k = 0; k < unrecoveredMedians.Count; ++k) { var replacementCost = this.ComputeReplacementCost( unrecoveredMedians[k], recoveredMedians[j], settedSolutions, costs, solutionBoard, exchangeSolutionBoard); if (this.comparer.Compare(replacementCost, minimumCost) < 0) { // Aceita a troca itemToExchange = recoveredMedians[j]; itemToExchangeIndex = j; itemToExchangeWith = unrecoveredMedians[k]; itemToExchangeWithIndex = k; minimumCost = replacementCost; var swapBestBoard = currentBestBoard; currentBestBoard = exchangeSolutionBoard; exchangeSolutionBoard = swapBestBoard; } } } if (itemToExchange == -1 || itemToExchangeWith == -1) { i = niter - 1; } else { // Efectua a troca var swapSolutionBoard = solutionBoard; solutionBoard = currentBestBoard; currentBestBoard = swapSolutionBoard; currentCost = this.coeffsField.Add(currentCost, minimumCost); settedSolutions.Remove(itemToExchange); settedSolutions.Add(itemToExchangeWith); var swap = recoveredMedians[itemToExchangeIndex]; recoveredMedians[itemToExchangeIndex] = unrecoveredMedians[itemToExchangeWithIndex]; unrecoveredMedians[itemToExchangeWithIndex] = swap; } } } return(new GreedyAlgSolution <CoeffType>(settedSolutions) { Cost = currentCost }); } } else { throw new OdmpProblemException("The sum of medians can't be converted to an integer."); } } }