/// <summary>
        /// Obtém o valor da estimativa a ser adicionada a cada um dos nós durante o algoritmo.
        /// </summary>
        /// <param name="input">Os dados de entrada.</param>
        /// <param name="line">A linha correspondente ao nó de cobertura.</param>
        /// <param name="component">A matriz dos custos.</param>
        /// <returns>O valor da estimativa.</returns>
        private ElementType GetBigDelta(
            DualHeuristicAlgInput <ElementType> input,
            KeyValuePair <int, ILongSparseMatrixLine <ElementType> > line,
            SparseDictionaryMathMatrix <ElementType> component)
        {
            var result = this.ring.Add(input.Gamma, this.ring.AdditiveInverse(input.Taus[line.Key]));

            foreach (var otherLine in component.GetLines())
            {
                if (otherLine.Key != line.Key)
                {
                    if (otherLine.Value.ContainsColumn(line.Key))
                    {
                        var currentCost   = otherLine.Value[line.Key];
                        var currentLambda = input.Lambdas[line.Key];
                        if (this.comparer.Compare(currentLambda, currentCost) >= 0)
                        {
                            var difference = this.ring.Add(
                                input.Gamma,
                                this.ring.AdditiveInverse(input.Taus[otherLine.Key]));
                            if (this.comparer.Compare(difference, result) < 0)
                            {
                                result = difference;
                            }
                        }
                    }
                }
            }

            return(result);
        }
Exemple #2
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>
        /// 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);
            }
        }
        /// <summary>
        /// Realiza as iterações de melhoramento sobre os dados aproximados inicialmente.
        /// </summary>
        /// <param name="refsNumber">O número de referências.</param>
        /// <param name="matrix">A matriz dos custos.</param>
        /// <param name="input">Os dados de entrada.</param>
        /// <returns>O valor do custo dual.</returns>
        private ElementType Process(
            int refsNumber,
            SparseDictionaryMathMatrix <ElementType> matrix,
            DualHeuristicAlgInput <ElementType> input)
        {
            var multiplicativeSymmetric = this.ring.AdditiveInverse(this.ring.MultiplicativeUnity);
            var delta = this.ring.AdditiveUnity;

            while (!this.ring.IsMultiplicativeUnity(delta))
            {
                foreach (var line in matrix.GetLines())
                {
                    var bigDelta = this.GetBigDelta(
                        input,
                        line,
                        matrix);

                    var currentLambda = input.Lambdas[line.Key];
                    if (input.Cbar.ContainsKey(line.Key))
                    {
                        var value = this.ring.Add(
                            input.Cbar[line.Key],
                            this.ring.AdditiveInverse(currentLambda));
                        if (this.comparer.Compare(value, bigDelta) < 0)
                        {
                            bigDelta = value;
                            delta    = this.ring.MultiplicativeUnity;
                            input.Cbar.Remove(line.Key);

                            // TODO: cbar = min(u que cobre line tal que o custo é maior que lambda[line]
                            foreach (var coverLine in matrix.GetLines())
                            {
                                if (coverLine.Key != line.Key)
                                {
                                    if (coverLine.Value.ContainsColumn(line.Key))
                                    {
                                        var currentCost = coverLine.Value[line.Key];
                                        var compareCost = this.ring.Add(currentLambda, bigDelta);
                                        if (this.comparer.Compare(compareCost, currentCost) < 0)
                                        {
                                            var currentCbar = this.ring.AdditiveUnity;
                                            if (input.Cbar.TryGetValue(line.Key, out currentCbar))
                                            {
                                                if (this.comparer.Compare(currentCost, currentCbar) < 0)
                                                {
                                                    input.Cbar[line.Key] = currentCost;
                                                }
                                            }
                                            else
                                            {
                                                input.Cbar.Add(line.Key, currentCost);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (this.comparer.Compare(this.ring.AdditiveUnity, bigDelta) < 0)
                    {
                        foreach (var coveringLine in matrix.GetLines())
                        {
                            if (coveringLine.Key != line.Key)
                            {
                                if (coveringLine.Value.ContainsColumn(line.Key))
                                {
                                    if (this.comparer.Compare(coveringLine.Value[line.Key], currentLambda) <= 0)
                                    {
                                        input.Taus[coveringLine.Key] = this.ring.Add(
                                            input.Taus[coveringLine.Key],
                                            bigDelta);
                                    }
                                }
                            }
                        }

                        input.Lambdas[line.Key] = this.ring.Add(input.Lambdas[line.Key], bigDelta);
                        input.Taus[line.Key]    = this.ring.Add(input.Taus[line.Key], bigDelta);
                    }
                }
            }

            var result = this.ring.AdditiveUnity;
            var prod   = this.ring.AddRepeated(input.Gamma, refsNumber);

            foreach (var line in matrix.GetLines())
            {
                result = this.ring.Add(result, input.Lambdas[line.Key]);
            }

            result = this.ring.Add(result, this.ring.AdditiveInverse(prod));
            return(result);
        }
Exemple #5
0
        public ElementType Run(
            SparseDictionaryMathMatrix <ElementType> matrix,
            DualHeuristicAlgInput <ElementType> input)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }
            else if (input == null)
            {
                throw new ArgumentNullException("input");
            }
            else
            {
                input.Taus.Clear();
                var result = new Dictionary <int, ElementType>();
                input.Gamma = this.ring.AdditiveUnity;
                var currentGamma = this.ring.AdditiveUnity;
                foreach (var line in matrix.GetLines())
                {
                    // Setup the tau and cbar values
                    var tempTau = input.Lambdas[line.Key];
                    foreach (var coveredLine in line.Value.GetColumns())
                    {
                        if (coveredLine.Key != line.Key)
                        {
                            var difference = this.ring.Add(
                                input.Lambdas[coveredLine.Key],
                                this.ring.AdditiveInverse(coveredLine.Value));
                            if (this.comparer.Compare(difference, this.ring.AdditiveUnity) < 0)
                            {
                                tempTau = this.ring.Add(tempTau, difference);
                            }
                        }
                    }

                    if (this.comparer.Compare(input.Gamma, tempTau) < 0)
                    {
                        input.Gamma = tempTau;
                    }

                    if (this.comparer.Compare(currentGamma, tempTau) < 0)
                    {
                        currentGamma = tempTau;
                    }

                    input.Taus.Add(line.Key, tempTau);
                }

                foreach (var line in matrix.GetLines())
                {
                    foreach (var coveredLine in line.Value.GetColumns())
                    {
                        if (coveredLine.Key != line.Key)
                        {
                            var tempCbarValue = this.ring.Add(
                                coveredLine.Value,
                                this.ring.AdditiveInverse(input.Lambdas[coveredLine.Key]));
                            if (this.comparer.Compare(this.ring.AdditiveUnity, tempCbarValue) < 0)
                            {
                                var currentCbarInCoveredVertice = this.ring.AdditiveUnity;
                                if (input.Cbar.TryGetValue(coveredLine.Key, out currentCbarInCoveredVertice))
                                {
                                    if (this.comparer.Compare(tempCbarValue, currentCbarInCoveredVertice) < 0)
                                    {
                                        input.Cbar[coveredLine.Key] = coveredLine.Value;
                                    }
                                }
                                else
                                {
                                    input.Cbar.Add(coveredLine.Key, coveredLine.Value);
                                }
                            }
                        }
                    }
                }

                return(currentGamma);
            }
        }
        /// <summary>
        /// Escolhe a referência que minimiza a perda.
        /// </summary>
        /// <param name="chosenReferences">As referências escolhidas anteriormente.</param>
        /// <param name="currentMatrix">A matriz dos custos.</param>
        /// <param name="currentLineBoard">A linha que contém a condensação dos custos das linhas escolhidas.</param>
        /// <returns>O índice da linha correspondente à próxima referência bem como a perda respectiva.</returns>
        public Tuple <int, ElementType> Run(
            IntegerSequence chosenReferences,
            SparseDictionaryMathMatrix <ElementType> currentMatrix,
            ElementType[] currentLineBoard)
        {
            var result             = -1;
            var currentMinimumLost = default(ElementType);
            var lines = currentMatrix.GetLines();

            if (chosenReferences.Count > 2)
            {
                currentMinimumLost = this.GetMinimumSum(
                    chosenReferences,
                    currentMatrix,
                    currentLineBoard,
                    lines,
                    2);
                result = 2;
            }

            Parallel.For(2, chosenReferences.Count,
                         chosenSolution =>
            {
                var sum = this.GetMinimumSum(
                    chosenReferences,
                    currentMatrix,
                    currentLineBoard,
                    lines,
                    chosenSolution);

                lock (this.lockObject)
                {
                    if (this.comparer.Compare(sum, currentMinimumLost) < 0)
                    {
                        currentMinimumLost = sum;
                        result             = chosenSolution;
                    }
                }
            });

            if (result != -1)
            {
                var solutionValue = chosenReferences[result];
                var minimumCover  = this.GetMinimumCover(
                    chosenReferences,
                    lines,
                    solutionValue);

                currentLineBoard[solutionValue] = minimumCover;

                var columns = currentMatrix.GetColumns(solutionValue);
                foreach (var column in columns)
                {
                    if (column.Key != solutionValue)
                    {
                        var currentValue = currentMatrix[solutionValue, column.Key];
                        if (this.ring.Equals(currentValue, currentLineBoard[column.Key]))
                        {
                            minimumCover = this.GetMinimumCover(
                                chosenReferences,
                                lines,
                                solutionValue);

                            currentLineBoard[column.Key] = minimumCover;
                        }
                    }
                }
            }

            return(Tuple.Create(result, currentMinimumLost));
        }