public static void Improve(IRandom random, Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, int neighborhoodSize, CancellationToken cancellation) { for (int i = localIterations.Value; i < maxIterations; i++) { ScrambleMove bestMove = null; double bestQuality = 0; // we have to make an improvement, so 0 is the baseline double evaluations = 0.0; for (int j = 0; j < neighborhoodSize; j++) { var move = StochasticScrambleMultiMoveGenerator.GenerateRandomMove(assignment, random); double moveQuality = QAPScrambleMoveEvaluator.Apply(assignment, move, weights, distances); evaluations += 2.0 * move.ScrambledIndices.Length / assignment.Length; if (maximization && moveQuality > bestQuality || !maximization && moveQuality < bestQuality) { bestQuality = moveQuality; bestMove = move; } } evaluatedSolutions.Value += (int)Math.Ceiling(evaluations); if (bestMove == null) { break; } ScrambleManipulator.Apply(assignment, bestMove.StartIndex, bestMove.ScrambledIndices); quality.Value += bestQuality; localIterations.Value++; cancellation.ThrowIfCancellationRequested(); } }
public void ScrambleMoveEvaluatorTest() { for (int i = 0; i < 500; i++) { ScrambleMove scramble = StochasticScrambleMultiMoveGenerator.GenerateRandomMove(assignment, random); // SYMMETRIC MATRICES double before = QAPEvaluator.Apply(assignment, symmetricWeights, symmetricDistances); double move = QAPScrambleMoveEvaluator.Apply(assignment, scramble, symmetricWeights, symmetricDistances); ScrambleManipulator.Apply(assignment, scramble.StartIndex, scramble.ScrambledIndices); double after = QAPEvaluator.Apply(assignment, symmetricWeights, symmetricDistances); Assert.IsTrue(move.IsAlmost(after - before), "Failed on symmetric matrices"); // ASYMMETRIC MATRICES before = QAPEvaluator.Apply(assignment, asymmetricWeights, asymmetricDistances); move = QAPScrambleMoveEvaluator.Apply(assignment, scramble, asymmetricWeights, asymmetricDistances); ScrambleManipulator.Apply(assignment, scramble.StartIndex, scramble.ScrambledIndices); after = QAPEvaluator.Apply(assignment, asymmetricWeights, asymmetricDistances); Assert.IsTrue(move.IsAlmost(after - before), "Failed on asymmetric matrices"); // NON-ZERO DIAGONAL ASYMMETRIC MATRICES before = QAPEvaluator.Apply(assignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances); move = QAPScrambleMoveEvaluator.Apply(assignment, scramble, nonZeroDiagonalWeights, nonZeroDiagonalDistances); ScrambleManipulator.Apply(assignment, scramble.StartIndex, scramble.ScrambledIndices); after = QAPEvaluator.Apply(assignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances); Assert.IsTrue(move.IsAlmost(after - before), "Failed on non-zero diagonal matrices"); } }
public override IOperation Apply() { ScrambleMove move = ScrambleMoveParameter.ActualValue; if (move == null) { throw new InvalidOperationException("Scramble 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()); }
/// <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, ScrambleMove move, DoubleMatrix weights, DoubleMatrix distances) { double moveQuality = 0; int min = move.StartIndex; int max = min + move.ScrambledIndices.Length - 1; for (int i = min; i <= max; i++) { int locI = assignment[i]; int newlocI = assignment[min + move.ScrambledIndices[i - min]]; if (locI == newlocI) { continue; } for (int j = 0; j < assignment.Length; j++) { int locJ = assignment[j]; if (j >= min && j <= max) { int newlocJ = assignment[min + move.ScrambledIndices[j - min]]; moveQuality += weights[i, j] * (distances[newlocI, newlocJ] - distances[locI, locJ]); if (locJ == newlocJ) { moveQuality += weights[j, i] * (distances[newlocJ, newlocI] - distances[locJ, locI]); } } else { moveQuality += weights[i, j] * (distances[newlocI, locJ] - distances[locI, locJ]); moveQuality += weights[j, i] * (distances[locJ, newlocI] - distances[locJ, locI]); } } } return(moveQuality); }