/// <summary> /// Calculates the quality of the move <paramref name="move"/> by evaluating the changes. /// The runtime complexity of this method is O(N) with N being the size of the permutation. /// </summary> /// <param name="assignment">The current permutation.</param> /// <param name="move">The move that is to be evaluated if it was applied to the current permutation.</param> /// <param name="weights">The weights matrix.</param> /// <param name="distances">The distances matrix.</param> /// <returns>The relative change in quality if <paramref name="move"/> was applied to <paramref name="assignment"/>.</returns> public static double Apply(Permutation assignment, Swap2Move move, DoubleMatrix weights, DoubleMatrix distances) { if (move.Index1 == move.Index2) { return(0); } double moveQuality = 0; int fac1 = move.Index1, fac2 = move.Index2; int loc1 = assignment[fac1], loc2 = assignment[fac2]; for (int j = 0; j < assignment.Length; j++) { if (j == fac1) { moveQuality += weights[fac1, fac1] * (distances[loc2, loc2] - distances[loc1, loc1]); moveQuality += weights[fac1, fac2] * (distances[loc2, loc1] - distances[loc1, loc2]); } else if (j == fac2) { moveQuality += weights[fac2, fac2] * (distances[loc1, loc1] - distances[loc2, loc2]); moveQuality += weights[fac2, fac1] * (distances[loc1, loc2] - distances[loc2, loc1]); } else { int locJ = assignment[j]; moveQuality += weights[fac1, j] * (distances[loc2, locJ] - distances[loc1, locJ]); moveQuality += weights[j, fac1] * (distances[locJ, loc2] - distances[locJ, loc1]); moveQuality += weights[fac2, j] * (distances[loc1, locJ] - distances[loc2, locJ]); moveQuality += weights[j, fac2] * (distances[locJ, loc1] - distances[locJ, loc2]); } } return(moveQuality); }
public static void Improve(Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, CancellationToken cancellation) { double evalSolPerMove = 4.0 / assignment.Length; for (int i = localIterations.Value; i < maxIterations; i++) { Swap2Move bestMove = null; double bestQuality = 0; // we have to make an improvement, so 0 is the baseline double evaluations = 0.0; foreach (Swap2Move move in ExhaustiveSwap2MoveGenerator.Generate(assignment)) { double moveQuality = QAPSwap2MoveEvaluator.Apply(assignment, move, weights, distances); evaluations += evalSolPerMove; if (maximization && moveQuality > bestQuality || !maximization && moveQuality < bestQuality) { bestQuality = moveQuality; bestMove = move; } } evaluatedSolutions.Value += (int)Math.Ceiling(evaluations); if (bestMove == null) { break; } Swap2Manipulator.Apply(assignment, bestMove.Index1, bestMove.Index2); quality.Value += bestQuality; localIterations.Value++; cancellation.ThrowIfCancellationRequested(); } }
public static void ImproveFast(Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, CancellationToken cancellation) { Swap2Move bestMove = null; double evaluations = 0.0; var lastQuality = new double[assignment.Length, assignment.Length]; for (int i = localIterations.Value; i < maxIterations; i++) { double bestQuality = 0; // we have to make an improvement, so 0 is the baseline var lastMove = bestMove; bestMove = null; foreach (Swap2Move move in ExhaustiveSwap2MoveGenerator.Generate(assignment)) { double moveQuality; if (lastMove == null) { moveQuality = QAPSwap2MoveEvaluator.Apply(assignment, move, weights, distances); evaluations += 4.0 / assignment.Length; } else { moveQuality = QAPSwap2MoveEvaluator.Apply(assignment, move, lastQuality[move.Index1, move.Index2], weights, distances, lastMove); if (move.Index1 == lastMove.Index1 || move.Index2 == lastMove.Index1 || move.Index1 == lastMove.Index2 || move.Index2 == lastMove.Index2) { evaluations += 4.0 / assignment.Length; } else { evaluations += 2.0 / (assignment.Length * assignment.Length); } } lastQuality[move.Index1, move.Index2] = moveQuality; if (maximization && moveQuality > bestQuality || !maximization && moveQuality < bestQuality) { bestQuality = moveQuality; bestMove = move; } } if (bestMove == null) { break; } Swap2Manipulator.Apply(assignment, bestMove.Index1, bestMove.Index2); quality.Value += bestQuality; localIterations.Value++; if (cancellation.IsCancellationRequested) { evaluatedSolutions.Value += (int)Math.Round(evaluations); throw new OperationCanceledException(); } } evaluatedSolutions.Value += (int)Math.Round(evaluations); }
public override IOperation Apply() { Swap2Move move = Swap2MoveParameter.ActualValue; if (move == null) { throw new InvalidOperationException("Swap-2 move is not found."); } Permutation assignment = PermutationParameter.ActualValue; DoubleMatrix distances = DistancesParameter.ActualValue; DoubleMatrix weights = WeightsParameter.ActualValue; double moveQuality = QualityParameter.ActualValue.Value; moveQuality += Apply(assignment, move, weights, distances); MoveQualityParameter.ActualValue = new DoubleValue(moveQuality); return(base.Apply()); }
public void Swap2MoveEvaluatorFastEvaluationTest() { for (int i = 0; i < 500; i++) { Swap2Move lastMove = new Swap2Move(random.Next(ProblemSize), random.Next(ProblemSize)); Permutation prevAssignment = (Permutation)assignment.Clone(); Swap2Manipulator.Apply(assignment, lastMove.Index1, lastMove.Index2); Permutation nextAssignment = (Permutation)assignment.Clone(); Swap2Move currentMove = new Swap2Move(random.Next(ProblemSize), random.Next(ProblemSize)); Swap2Manipulator.Apply(nextAssignment, currentMove.Index1, currentMove.Index2); double moveBefore = QAPSwap2MoveEvaluator.Apply(prevAssignment, currentMove, symmetricWeights, symmetricDistances); double moveAfter = QAPSwap2MoveEvaluator.Apply(assignment, currentMove, moveBefore, symmetricWeights, symmetricDistances, lastMove); double before = QAPEvaluator.Apply(assignment, symmetricWeights, symmetricDistances); double after = QAPEvaluator.Apply(nextAssignment, symmetricWeights, symmetricDistances); Assert.IsTrue(moveAfter.IsAlmost(after - before), "Failed on symmetric matrices: " + Environment.NewLine + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveAfter + "."); moveBefore = QAPSwap2MoveEvaluator.Apply(prevAssignment, currentMove, asymmetricWeights, asymmetricDistances); moveAfter = QAPSwap2MoveEvaluator.Apply(assignment, currentMove, moveBefore, asymmetricWeights, asymmetricDistances, lastMove); before = QAPEvaluator.Apply(assignment, asymmetricWeights, asymmetricDistances); after = QAPEvaluator.Apply(nextAssignment, asymmetricWeights, asymmetricDistances); Assert.IsTrue(moveAfter.IsAlmost(after - before), "Failed on asymmetric matrices: " + Environment.NewLine + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveAfter + "."); moveBefore = QAPSwap2MoveEvaluator.Apply(prevAssignment, currentMove, nonZeroDiagonalWeights, nonZeroDiagonalDistances); moveAfter = QAPSwap2MoveEvaluator.Apply(assignment, currentMove, moveBefore, nonZeroDiagonalWeights, nonZeroDiagonalDistances, lastMove); before = QAPEvaluator.Apply(assignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances); after = QAPEvaluator.Apply(nextAssignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances); Assert.IsTrue(moveAfter.IsAlmost(after - before), "Failed on non-zero diagonal matrices: " + Environment.NewLine + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveAfter + "."); } }
/// <summary> /// Is able to compute the move qualities faster O(1) in some cases if it knows the quality of /// performing the move <paramref name="move"/> previously. In other cases it performs a /// standard move quality calculation with runtime complexity O(N). /// </summary> /// <remarks> /// The number of cases that the calculation can be performed faster grows with N^2 /// while the number of cases which require a larger recalculation grows linearly with N. /// Larger problem instances thus benefit from this faster method to a larger degree. /// </remarks> /// <param name="assignment">The current permutation.</param> /// <param name="move">The current move that is to be evaluated.</param> /// <param name="previousQuality">The quality of that move as evaluated for the previous permutation.</param> /// <param name="weights">The weigths matrix.</param> /// <param name="distances">The distances matrix.</param> /// <param name="lastMove">The move that was applied to transform the permutation from the previous to the current one.</param> /// <returns>The relative change in quality if <paramref name="move"/> was applied to <paramref name="assignment"/>.</returns> public static double Apply(Permutation assignment, Swap2Move move, double previousQuality, DoubleMatrix weights, DoubleMatrix distances, Swap2Move lastMove) { bool overlapsLastMove = move.Index1 == lastMove.Index1 || move.Index2 == lastMove.Index1 || move.Index1 == lastMove.Index2 || move.Index2 == lastMove.Index2; if (!overlapsLastMove) { int r = lastMove.Index1, u = move.Index1, s = lastMove.Index2, v = move.Index2; int pR = assignment[lastMove.Index1], pU = assignment[move.Index1], pS = assignment[lastMove.Index2], pV = assignment[move.Index2]; return(previousQuality + (weights[r, u] - weights[r, v] + weights[s, v] - weights[s, u]) * (distances[pS, pU] - distances[pS, pV] + distances[pR, pV] - distances[pR, pU]) + (weights[u, r] - weights[v, r] + weights[v, s] - weights[u, s]) * (distances[pU, pS] - distances[pV, pS] + distances[pV, pR] - distances[pU, pR])); } else { return(Apply(assignment, move, weights, distances)); } }
public override IOperation Apply() { IRandom random = RandomParameter.ActualValue; int iteration = IterationsParameter.ActualValue.Value; IntMatrix shortTermMemory = ShortTermMemoryParameter.ActualValue; DoubleMatrix weights = WeightsParameter.ActualValue; DoubleMatrix distances = DistancesParameter.ActualValue; DoubleMatrix moveQualityMatrix = MoveQualityMatrixParameter.ActualValue; DoubleValue quality = QualityParameter.ActualValue; DoubleValue bestQuality = BestQualityParameter.ActualValue; if (bestQuality == null) { BestQualityParameter.ActualValue = (DoubleValue)quality.Clone(); bestQuality = BestQualityParameter.ActualValue; } bool allMovesTabu = false; if (AllMovesTabuParameter.ActualValue == null) { AllMovesTabuParameter.ActualValue = new BoolValue(false); } else { allMovesTabu = AllMovesTabuParameter.ActualValue.Value; } int minTenure = MinimumTabuTenureParameter.ActualValue.Value; int maxTenure = MaximumTabuTenureParameter.ActualValue.Value; int alternativeAspirationTenure = AlternativeAspirationTenureParameter.ActualValue.Value; bool useAlternativeAspiration = UseAlternativeAspirationParameter.ActualValue.Value; Permutation solution = PermutationParameter.ActualValue; Swap2Move lastMove = LastMoveParameter.ActualValue; double bestMoveQuality = double.MaxValue; Swap2Move bestMove = null; bool already_aspired = false; double evaluations = EvaluatedSolutionEquivalentsParameter.ActualValue.Value; foreach (Swap2Move move in ExhaustiveSwap2MoveGenerator.Generate(solution)) { double moveQuality; if (lastMove == null) { moveQuality = QAPSwap2MoveEvaluator.Apply(solution, move, weights, distances); evaluations += 4.0 / solution.Length; } else if (allMovesTabu) { moveQuality = moveQualityMatrix[move.Index1, move.Index2]; } else { moveQuality = QAPSwap2MoveEvaluator.Apply(solution, move, moveQualityMatrix[move.Index1, move.Index2], weights, distances, lastMove); if (move.Index1 == lastMove.Index1 || move.Index2 == lastMove.Index1 || move.Index1 == lastMove.Index2 || move.Index2 == lastMove.Index2) { evaluations += 4.0 / solution.Length; } else { evaluations += 2.0 / (solution.Length * solution.Length); } } moveQualityMatrix[move.Index1, move.Index2] = moveQuality; moveQualityMatrix[move.Index2, move.Index1] = moveQuality; bool autorized = shortTermMemory[move.Index1, solution[move.Index2]] < iteration || shortTermMemory[move.Index2, solution[move.Index1]] < iteration; bool aspired = (shortTermMemory[move.Index1, solution[move.Index2]] < iteration - alternativeAspirationTenure && shortTermMemory[move.Index2, solution[move.Index1]] < iteration - alternativeAspirationTenure) || quality.Value + moveQuality < bestQuality.Value; if ((aspired && !already_aspired) || // the first alternative move is aspired (aspired && already_aspired && moveQuality < bestMoveQuality) || // an alternative move was already aspired, but this is better (autorized && !aspired && !already_aspired && moveQuality < bestMoveQuality)) // a regular better move is found { bestMove = move; bestMoveQuality = moveQuality; if (aspired) { already_aspired = true; } } } ResultCollection results = ResultsParameter.ActualValue; if (results != null) { IntValue aspiredMoves = null; if (!results.ContainsKey("AspiredMoves")) { aspiredMoves = new IntValue(already_aspired ? 1 : 0); results.Add(new Result("AspiredMoves", "Counts the number of moves that were selected because of the aspiration criteria.", aspiredMoves)); } else if (already_aspired) { aspiredMoves = (IntValue)results["AspiredMoves"].Value; aspiredMoves.Value++; } } EvaluatedSolutionEquivalentsParameter.ActualValue.Value = evaluations; EvaluatedSolutionsParameter.ActualValue.Value = (int)Math.Ceiling(evaluations); allMovesTabu = bestMove == null; if (!allMovesTabu) { LastMoveParameter.ActualValue = bestMove; } AllMovesTabuParameter.ActualValue.Value = allMovesTabu; if (allMovesTabu) { return(base.Apply()); } bool useNewAdaptionScheme = UseNewTabuTenureAdaptionSchemeParameter.ActualValue.Value; if (useNewAdaptionScheme) { double r = random.NextDouble(); if (r == 0) { r = 1; // transform to (0;1] } shortTermMemory[bestMove.Index1, solution[bestMove.Index1]] = (int)(iteration + r * r * r * maxTenure); r = random.NextDouble(); if (r == 0) { r = 1; // transform to (0;1] } shortTermMemory[bestMove.Index2, solution[bestMove.Index2]] = (int)(iteration + r * r * r * maxTenure); } else { shortTermMemory[bestMove.Index1, solution[bestMove.Index1]] = iteration + random.Next(minTenure, maxTenure); shortTermMemory[bestMove.Index2, solution[bestMove.Index2]] = iteration + random.Next(minTenure, maxTenure); } Swap2Manipulator.Apply(solution, bestMove.Index1, bestMove.Index2); quality.Value += bestMoveQuality; if (quality.Value < bestQuality.Value) { bestQuality.Value = quality.Value; } return(base.Apply()); }