/// <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);
        }
Exemplo n.º 2
0
        public virtual GreedyAlgSolution <CostType> Clone()
        {
            var result = new GreedyAlgSolution <CostType>();

            result.chosen = this.chosen.Clone();
            result.cost   = this.cost;
            return(result);
        }
Exemplo n.º 3
0
        /// <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);
        }
Exemplo n.º 4
0
        /// <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);
            }
        }
Exemplo n.º 5
0
        /// <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.");
                }
            }
        }