Beispiel #1
0
        /// <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);
        }
Beispiel #4
0
        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());
        }
Beispiel #5
0
        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 + ".");
            }
        }
Beispiel #6
0
        /// <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));
            }
        }
Beispiel #7
0
        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());
        }