/// <summary> /// Constrói a solução a partir da iteração actual. /// </summary> /// <param name="basicVariables">As variáveis básicas.</param> /// <param name="nonBasicVariables">As variáveis não-básicas.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <param name="cost">O custo actual.</param> /// <returns>A solução.</returns> private SimplexOutput <CoeffType> BuildSolution( int[] basicVariables, int[] nonBasicVariables, IMathVector <CoeffType> constraintsVector, SimplexMaximumNumberField <CoeffType> cost ) { var solution = default(CoeffType[]); var hasSolution = false; if (this.coeffsField.IsAdditiveUnity(cost.BigPart)) { hasSolution = true; solution = new CoeffType[nonBasicVariables.Length]; for (int i = 0; i < solution.Length; ++i) { solution[i] = this.coeffsField.AdditiveUnity; } for (int i = 0; i < basicVariables.Length; ++i) { var basicVariable = basicVariables[i]; if (basicVariable < solution.Length) { solution[basicVariable] = constraintsVector[i]; } } } return(new SimplexOutput <CoeffType>(solution, cost.FinitePart, hasSolution)); }
/// <summary> /// Obtém o vector dual. /// </summary> /// <param name="nonBasicCostsIndices">Os índices dos valores com custos relativos às variáveis básicas.</param> /// <param name="inverseMatrix">A matriz da base inversa.</param> /// <param name="objectiveFunction">O vector que representa a função objectivo.</param> /// <param name="basicVariables">As variáveis básicas.</param> /// <returns>O vector dual utilizado para determinar os valores dos custos.</returns> private SimplexMaximumNumberField <CoeffType>[] ComputeDualVector( SortedSet <int> nonBasicCostsIndices, ISquareMathMatrix <CoeffType> inverseMatrix, IMathVector <SimplexMaximumNumberField <CoeffType> > objectiveFunction, int[] basicVariables) { var result = new SimplexMaximumNumberField <CoeffType> [basicVariables.Length]; var dimension = basicVariables.Length; Parallel.For(0, dimension, i => { var sum = new SimplexMaximumNumberField <CoeffType>(this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveUnity); foreach (var index in nonBasicCostsIndices) { var objectiveValue = objectiveFunction[basicVariables[index]]; var finitePart = objectiveValue.FinitePart; var bigPart = objectiveValue.BigPart; var inverseMatrixEntry = inverseMatrix[index, i]; finitePart = this.coeffsField.Multiply( inverseMatrixEntry, this.coeffsField.AdditiveInverse(objectiveValue.FinitePart)); bigPart = this.coeffsField.Multiply( inverseMatrixEntry, this.coeffsField.AdditiveInverse(objectiveValue.BigPart)); sum.Add(finitePart, bigPart, this.coeffsField); } result[i] = sum; }); return(result); }
/// <summary> /// Otbém o simétrico aditivo de um número enorme. /// </summary> /// <param name="maxNumberField">O número.</param> /// <returns>O simétrico aditivo.</returns> private SimplexMaximumNumberField <CoeffType> GetAdditiveInverse( SimplexMaximumNumberField <CoeffType> maxNumberField) { return(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveInverse(maxNumberField.FinitePart), this.coeffsField.AdditiveInverse(maxNumberField.BigPart))); }
/// <summary> /// Adiciona dois números enormes. /// </summary> /// <param name="firstNumber">O primeiro número.</param> /// <param name="secondNumber">O segundo número.</param> /// <returns>O resultado da soma.</returns> private SimplexMaximumNumberField <CoeffType> Add( SimplexMaximumNumberField <CoeffType> firstNumber, SimplexMaximumNumberField <CoeffType> secondNumber) { return(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.Add(firstNumber.FinitePart, secondNumber.FinitePart), this.coeffsField.Add(firstNumber.BigPart, secondNumber.BigPart))); }
/// <summary> /// Processa a função objectivo. /// </summary> /// <param name="enteringVariable">A variável de entrada.</param> /// <param name="leavingVariable">a variável de saída.</param> /// <param name="basicVariables">O conjunto de variáveis básicas.</param> /// <param name="nonBasicVariables">O conjunto de variáveis não-básicas.</param> /// <param name="currentCost">O custo actual.</param> /// <param name="objective">A função objectivo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <returns>O resultado.</returns> private SimplexMaximumNumberField <CoeffType> ProcessObjectiveFunction( int enteringVariable, int leavingVariable, int[] basicVariables, int[] nonBasicVariables, SimplexMaximumNumberField <CoeffType> currentCost, IMathVector <SimplexMaximumNumberField <CoeffType> > objective, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <CoeffType> constraintsVector) { var result = currentCost; var multiplicativeProduct = this.GetAdditiveInverse(objective[enteringVariable]); if (!this.IsAdditiveUnity(multiplicativeProduct)) { Parallel.For(0, enteringVariable, column => { objective[column] = this.Add( objective[column], this.Multiply(constraintsMatrix[leavingVariable, column], multiplicativeProduct)); }); var constraintsEntry = constraintsMatrix[leavingVariable, enteringVariable]; if (this.coeffsField.IsAdditiveUnity(constraintsEntry)) { objective[enteringVariable] = multiplicativeProduct; } else { objective[enteringVariable] = this.Multiply( constraintsEntry, multiplicativeProduct); } Parallel.For(enteringVariable + 1, objective.Length, column => { objective[column] = this.Add( objective[column], this.Multiply(constraintsMatrix[leavingVariable, column], multiplicativeProduct)); }); result = this.Add( result, this.Multiply(constraintsVector[leavingVariable], multiplicativeProduct)); } // Troca as variáveis var swap = nonBasicVariables[enteringVariable]; nonBasicVariables[enteringVariable] = basicVariables[leavingVariable]; basicVariables[leavingVariable] = swap; return(result); }
/// <summary> /// Compara dois números enormes. /// </summary> /// <param name="firstNumber">O primeiro número a ser comparado.</param> /// <param name="secondNumber">O segundo número a ser comparado.</param> /// <returns> /// Os valores -1, 0 e 1 caso o primeiro número seja respectivamente menor, igual ou maior /// do que o segundo número. /// </returns> private int ComapareBigNumbers( SimplexMaximumNumberField <CoeffType> firstNumber, SimplexMaximumNumberField <CoeffType> secondNumber) { return(SimplexMaximumNumberField <CoeffType> .UncheckedCompare( firstNumber, secondNumber, this.coeffsComparer)); }
/// <summary> /// Constrói a soução final a partir dos dados. /// </summary> /// <param name="nonBasicVariables">As variáveis não básicas.</param> /// <param name="basicVariables">As variáveis básicas.</param> /// <param name="dataCost">O custo inicial.</param> /// <param name="dualVector">O vector dual.</param> /// <param name="computedConstraintsVector">O vector das restrições calculado.</param> /// <param name="constraintsVector">O vector das restrições.</param> /// <returns>A solução.</returns> private SimplexOutput <CoeffType> BuildSolution( int[] nonBasicVariables, int[] basicVariables, SimplexMaximumNumberField <CoeffType> dataCost, SimplexMaximumNumberField <CoeffType>[] dualVector, CoeffType[] computedConstraintsVector, IMathVector <CoeffType> constraintsVector) { var nonBasicLength = nonBasicVariables.Length; var basicLength = basicVariables.Length; // Constrói a solução. CoeffType[] solution = new CoeffType[nonBasicLength]; Parallel.For(0, basicLength, i => { var basicVariable = basicVariables[i]; if (basicVariable < nonBasicLength) { solution[basicVariable] = computedConstraintsVector[i]; } }); // Calcula o custo. var finiteCost = this.coeffsField.AdditiveUnity; var bigCost = this.coeffsField.AdditiveUnity; var length = dualVector.Length; for (int i = 0; i < length; ++i) { var constraintsVectorValue = constraintsVector[i]; var dualValue = dualVector[i]; var finiteValueToAdd = dualValue.FinitePart; var bigValueToAdd = dualValue.BigPart; finiteValueToAdd = this.coeffsField.Multiply(finiteValueToAdd, constraintsVectorValue); bigValueToAdd = this.coeffsField.Multiply(bigValueToAdd, constraintsVectorValue); finiteCost = this.coeffsField.Add(finiteCost, finiteValueToAdd); bigCost = this.coeffsField.Add(bigCost, bigValueToAdd); } finiteCost = this.coeffsField.Add(finiteCost, dataCost.FinitePart); bigCost = this.coeffsField.Add(bigCost, dataCost.BigPart); if (this.coeffsField.IsAdditiveUnity(bigCost)) { return(new SimplexOutput <CoeffType>(solution, finiteCost, true)); } else { // A solução corresponde a um valor inifinito para o custo. return(new SimplexOutput <CoeffType>(solution, default(CoeffType), false)); } }
/// <summary> /// Permite comparar dois números grandes sem efectuar qualquer verificação dos argumentos. /// </summary> /// <remarks> /// A utilização é destinada aos processo internos da livraria. /// </remarks> /// <param name="first">O primeiro número a ser comparado.</param> /// <param name="second">O segundo número a ser comparado.</param> /// <param name="comparer">O comparador de coeficientes.</param> /// <returns> /// O valor 1 caso o primeiro número seja superior ao segundo, 0 se ambos forem iguais e -1 se o /// primeiro número for inferior ao segundo. /// </returns> internal static int UncheckedCompare( SimplexMaximumNumberField <ObjectType> first, SimplexMaximumNumberField <ObjectType> second, IComparer <ObjectType> comparer) { var compareValue = comparer.Compare(first.bigPart, second.bigPart); if (compareValue == 0) { return(comparer.Compare(first.finitePart, second.finitePart)); } else { return(compareValue); } }
/// <summary> /// Obtém o produto de um coeficiente por um número enorme. /// </summary> /// <param name="coeff">O coeficiente.</param> /// <param name="number">O número enorme.</param> /// <returns>O número enorme que resulta do produto.</returns> private SimplexMaximumNumberField <CoeffType> Multiply( CoeffType coeff, SimplexMaximumNumberField <CoeffType> number) { if (this.coeffsField.IsAdditiveUnity(coeff)) { return(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveUnity)); } else { return(new SimplexMaximumNumberField <CoeffType>( this.coeffsField.Multiply(coeff, number.FinitePart), this.coeffsField.Multiply(coeff, number.BigPart))); } }
/// <summary> /// Permite comparar dois números grandes. /// </summary> /// <param name="first">O primeiro número a ser comparado.</param> /// <param name="second">O segundo número a ser comparado.</param> /// <param name="comparer">O comparador de coeficientes.</param> /// <returns> /// O valor 1 caso o primeiro número seja superior ao segundo, 0 se ambos forem iguais e -1 se o /// primeiro número for inferior ao segundo. /// </returns> /// <exception cref="ArgumentNullException"> /// Se algum dos dois primeiros argumentos for nulo. /// </exception> public static int Compare( SimplexMaximumNumberField <ObjectType> first, SimplexMaximumNumberField <ObjectType> second, IComparer <ObjectType> comparer) { if (first == null) { throw new ArgumentNullException("first"); } else if (second == null) { throw new ArgumentNullException("second"); } else if (comparer == null) { return(UncheckedCompare(first, second, Comparer <ObjectType> .Default)); } else { return(UncheckedCompare(first, second, comparer)); } }
/// <summary> /// Obtém a próxima variável de entrada. /// </summary> /// <param name="data">Os dados de entrada.</param> /// <returns>A variável caso exista e -1 caso contrário.</returns> private int GetNextEnteringVariable(SimplexInput <CoeffType, SimplexMaximumNumberField <CoeffType> > data) { var result = -1; var value = new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveUnity); var length = data.ObjectiveFunction.Length; for (int i = 0; i < length; ++i) { var current = data.ObjectiveFunction[i]; if (this.coeffsComparer.Compare(current.BigPart, this.coeffsField.AdditiveUnity) <= 0) { if (this.ComapareBigNumbers(current, value) < 0) { result = i; value = current; } } } return(result); }
/// <summary> /// Obtém a variável de entrada. /// </summary> /// <param name="dualVector">O vector dual que irá permitir calcular os coeficientes do custo.</param> /// <param name="constraintsMatrix">A matriz das restrições.</param> /// <param name="objectiveFunction">A função objectivo.</param> /// <param name="nonBasicVariables">As variáveis não básicas.</param> /// <returns>O índice da variável a entrar.</returns> private int GetNextEnteringVariable( SimplexMaximumNumberField <CoeffType>[] dualVector, IMathMatrix <CoeffType> constraintsMatrix, IMathVector <SimplexMaximumNumberField <CoeffType> > objectiveFunction, int[] nonBasicVariables) { var result = -1; var value = new SimplexMaximumNumberField <CoeffType>( this.coeffsField.AdditiveUnity, this.coeffsField.AdditiveUnity); var nonBasicLength = nonBasicVariables.Length; var constraintsLinesLength = dualVector.Length; var syncObject = new object(); // Utilizado para sincronizar as comparações. Parallel.For(0, nonBasicLength, i => { var finitePart = this.coeffsField.AdditiveUnity; var bigPart = this.coeffsField.AdditiveUnity; var nonBasicVariable = nonBasicVariables[i]; if (nonBasicVariable < nonBasicLength) { for (int j = 0; j < constraintsLinesLength; ++j) { var dualVectorEntry = dualVector[j]; var constraintsMatrixEntry = constraintsMatrix[j, nonBasicVariable]; var finiteValueToAdd = this.coeffsField.Multiply(dualVectorEntry.FinitePart, constraintsMatrixEntry); var bigValueToAdd = this.coeffsField.Multiply(dualVectorEntry.BigPart, constraintsMatrixEntry); var objectiveValue = objectiveFunction[nonBasicVariable]; finiteValueToAdd = this.coeffsField.Add(finiteValueToAdd, objectiveValue.FinitePart); bigValueToAdd = this.coeffsField.Add(bigValueToAdd, objectiveValue.BigPart); finitePart = this.coeffsField.Add(finitePart, finiteValueToAdd); bigPart = this.coeffsField.Add(bigPart, bigValueToAdd); } lock (syncObject) { var comparisionValue = this.coeffsComparer.Compare(bigPart, value.BigPart); if (comparisionValue < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } else if (comparisionValue == 0) { if (this.coeffsComparer.Compare(finitePart, value.FinitePart) < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } } } } else { var index = nonBasicVariable - nonBasicLength; var dualValue = dualVector[index]; finitePart = dualValue.FinitePart; bigPart = dualValue.BigPart; lock (syncObject) { var comparisionValue = this.coeffsComparer.Compare(bigPart, value.BigPart); if (comparisionValue < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } else if (comparisionValue == 0) { if (this.coeffsComparer.Compare(finitePart, value.FinitePart) < 0) { result = i; value.FinitePart = finitePart; value.BigPart = bigPart; } } } } }); return(result); }
/// <summary> /// Verifica se um número enorme constitui uma unidade aditiva. /// </summary> /// <param name="number">O número enorme.</param> /// <returns>Verdadeiro caso o número seja uma unidade aditiva e falso caso contrário.</returns> private bool IsAdditiveUnity(SimplexMaximumNumberField <CoeffType> number) { return(this.coeffsField.IsAdditiveUnity(number.FinitePart) && this.coeffsField.IsAdditiveUnity(number.BigPart)); }