/// <summary>
        /// Obtém um vector cujas entradas são nulas.
        /// </summary>
        /// <param name="integerDomain">
        /// O objecto responsável pelas operações sobre os números inteiros.
        /// </param>
        /// <returns>O vector.</returns>
        private ArrayMathMatrix <Fraction <int> > GetZeroFilledVector(
            IntegerDomain integerDomain)
        {
            var result = new ArrayMathMatrix <Fraction <int> >(
                6,
                1,
                new Fraction <int>(0, 1, integerDomain));

            return(result);
        }
        /// <summary>
        /// Obtém o vector independente para tetar a matriz geral.
        /// </summary>
        /// <param name="domain">O objecto responsável pelas operações sobre inteiros.</param>
        private ArrayMathMatrix <Fraction <int> > GetIndVectorForGenMatrix(
            IntegerDomain domain)
        {
            var result = new ArrayMathMatrix <Fraction <int> >(2, 1);

            result[0, 0] = new Fraction <int>(2, 1, domain);
            result[1, 0] = new Fraction <int>(5, 1, domain);

            return(result);
        }
        /// <summary>
        /// Obtém o vector independente para utilizar com a matriz singular.
        /// </summary>
        /// <param name="domain">O objecto responsável pelas operações sobre os números inteiros.</param>
        /// <returns>O vector.</returns>
        private ArrayMathMatrix <Fraction <int> > GetIndtVectorForSingularMatrix(
            IntegerDomain domain)
        {
            var result = new ArrayMathMatrix <Fraction <int> >(6, 1);

            result[0, 0] = new Fraction <int>(3, 1, domain);
            result[1, 0] = new Fraction <int>(-3, 1, domain);
            result[2, 0] = new Fraction <int>(-8, 1, domain);
            result[3, 0] = new Fraction <int>(-5, 1, domain);
            result[4, 0] = new Fraction <int>(-5, 1, domain);
            result[5, 0] = new Fraction <int>(8, 1, domain);

            return(result);
        }
        /// <summary>
        /// Obtém uma matriz para testar o sistema de equações geral.
        /// </summary>
        /// <param name="integerDomain">
        /// O objecto responsável pelas operações sobre inteiros.
        /// </param>
        /// <returns>A matriz de teste.</returns>
        private ArrayMathMatrix <Fraction <int> > GetGeneralMatrix(
            IntegerDomain integerDomain)
        {
            var result = new ArrayMathMatrix <Fraction <int> >(2, 3);

            result[0, 0] = new Fraction <int>(1, 1, integerDomain);
            result[0, 1] = new Fraction <int>(0, 1, integerDomain);
            result[0, 2] = new Fraction <int>(1, 1, integerDomain);

            result[1, 0] = new Fraction <int>(2, 1, integerDomain);
            result[1, 1] = new Fraction <int>(1, 1, integerDomain);
            result[1, 2] = new Fraction <int>(1, 1, integerDomain);

            return(result);
        }
        public void Run_TriangDiagSymmDecompNoInverse()
        {
            // Definição dos domínios e fábricas.
            var integerDomain = new IntegerDomain();
            var fractionField = new FractionField <int>(integerDomain);

            // Definição dos algoritmos.
            var target       = new TriangDiagSymmDecompInverseAlg <Fraction <int> >();
            var triangDecomp = new ParallelTriangDiagSymmMatrixDecomp <Fraction <int> >(fractionField);

            var arraySquareMatrixFactory = new ArraySquareMatrixFactory <Fraction <int> >();
            var arrayMatrixFactory       = new ArrayMathMatrixFactory <Fraction <int> >();

            // A matriz
            var matrix = this.GetSingularMatrix(integerDomain);

            // Cálculos
            var triangDiagDecomp = triangDecomp.Run(
                matrix);
            var inverseMatrix = target.Run(
                triangDiagDecomp,
                arraySquareMatrixFactory,
                fractionField);

            // Verificação dos valores.
            var expected = ArrayMathMatrix <Fraction <int> > .GetIdentity(3, fractionField);

            var matrixMultiplication = new MatrixMultiplicationOperation <Fraction <int> >(
                arrayMatrixFactory,
                fractionField,
                fractionField);
            var actual = matrixMultiplication.Multiply(inverseMatrix, matrix);

            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    Assert.AreEqual(expected[i, j], actual[i, j]);
                }
            }
        }
        /// <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);
            }
        }