#region License Information /* HeuristicLab * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.PermutationEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.QuadraticAssignment.Algorithms { [Item("QAPRandomizedRobustTabooSeachOperator", "Performs an iteration of a modified robust taboo search algorithm based on Taillard 1991.")] public sealed class QAPRandomizedRobustTabooSeachOperator : SingleSuccessorOperator, IIterationBasedOperator, IStochasticOperator { #region Parameter Properties public ILookupParameter IterationsParameter { get { return (ILookupParameter)Parameters["Iterations"]; } } public ILookupParameter TabuTenureParameter { get { return (ILookupParameter)Parameters["TabuTenure"]; } } public ILookupParameter PermutationParameter { get { return (ILookupParameter)Parameters["Permutation"]; } } public ILookupParameter WeightsParameter { get { return (ILookupParameter)Parameters["Weights"]; } } public ILookupParameter DistancesParameter { get { return (ILookupParameter)Parameters["Distances"]; } } public ILookupParameter ShortTermMemoryParameter { get { return (ILookupParameter)Parameters["ShortTermMemory"]; } } public ILookupParameter ShortTermMemory2Parameter { get { return (ILookupParameter)Parameters["ShortTermMemory2"]; } } public ILookupParameter LongTermMemoryParameter { get { return (ILookupParameter)Parameters["LongTermMemory"]; } } public ILookupParameter QualityParameter { get { return (ILookupParameter)Parameters["Quality"]; } } public ILookupParameter BestQualityParameter { get { return (ILookupParameter)Parameters["BestQuality"]; } } public ILookupParameter ResultsParameter { get { return (ILookupParameter)Parameters["Results"]; } } public ILookupParameter LastGlobalImprovementParameter { get { return (ILookupParameter)Parameters["LastGlobalImprovement"]; } } public ILookupParameter BestKnownQualityParameter { get { return (ILookupParameter)Parameters["BestKnownQuality"]; } } public ILookupParameter RandomParameter { get { return (ILookupParameter)Parameters["Random"]; } } public IValueLookupParameter MaximumIterationsParameter { get { return (IValueLookupParameter)Parameters["MaximumIterations"]; } } public IValueLookupParameter MinimumTabuTenureParameter { get { return (IValueLookupParameter)Parameters["MinimumTabuTenure"]; } } public IValueLookupParameter MaximumTabuTenureParameter { get { return (IValueLookupParameter)Parameters["MaximumTabuTenure"]; } } public IValueLookupParameter TabuTenureAdaptionIntervalParameter { get { return (IValueLookupParameter)Parameters["TabuTenureAdaptionInterval"]; } } #endregion [StorableConstructor] private QAPRandomizedRobustTabooSeachOperator(bool deserializing) : base(deserializing) { } private QAPRandomizedRobustTabooSeachOperator(QAPRandomizedRobustTabooSeachOperator original, Cloner cloner) : base(original, cloner) { } public QAPRandomizedRobustTabooSeachOperator() { Parameters.Add(new LookupParameter("Iterations", "The current iteration.")); Parameters.Add(new LookupParameter("TabuTenure", "The current tabu tenure.")); Parameters.Add(new LookupParameter("Random", "The random number generator to use.")); Parameters.Add(new LookupParameter("Permutation", "The permutation solution.")); Parameters.Add(new LookupParameter("Weights", "The weights matrix.")); Parameters.Add(new LookupParameter("Distances", "The distances matrix.")); Parameters.Add(new LookupParameter("ShortTermMemory", "The table that stores the iteration at which a certain facility has been assigned to a certain location.")); Parameters.Add(new LookupParameter("ShortTermMemory2", "The table that stores the quality at which a certain facility has been assigned to a certain location.")); Parameters.Add(new LookupParameter("LongTermMemory", "Same as the tabu table, but constantly updates the information given the current solution.")); Parameters.Add(new LookupParameter("Quality", "The quality value.")); Parameters.Add(new LookupParameter("BestQuality", "The best quality value.")); Parameters.Add(new ValueLookupParameter("MaximumIterations", "The number of iterations that the algorithm should run.")); Parameters.Add(new ValueLookupParameter("MinimumTabuTenure", "The minimum tabu tenure.")); Parameters.Add(new ValueLookupParameter("MaximumTabuTenure", "The maximum tabu tenure.")); Parameters.Add(new ValueLookupParameter("TabuTenureAdaptionInterval", "The amount of iterations that have to pass before the tabu tenure is adapted.")); Parameters.Add(new LookupParameter("LastGlobalImprovement", "The iteration at which the best solution so far has been improved.")); Parameters.Add(new LookupParameter("BestKnownQuality", "The best known quality is just used to store the iteration at which it was found.")); Parameters.Add(new LookupParameter("Results", "The collection to store results to.")); } public override IDeepCloneable Clone(Cloner cloner) { return new QAPRandomizedRobustTabooSeachOperator(this, cloner); } public override IOperation Apply() { ResultCollection results = ResultsParameter.ActualValue; IRandom random = RandomParameter.ActualValue; int iteration = IterationsParameter.ActualValue.Value; IntMatrix longTermMemory = LongTermMemoryParameter.ActualValue; IntMatrix shortTermMemory = ShortTermMemoryParameter.ActualValue; DoubleMatrix shortTermMemory2 = ShortTermMemory2Parameter.ActualValue; DoubleMatrix weights = WeightsParameter.ActualValue; DoubleMatrix distances = DistancesParameter.ActualValue; DoubleValue quality = QualityParameter.ActualValue; DoubleValue bestQuality = BestQualityParameter.ActualValue; if (bestQuality == null) { BestQualityParameter.ActualValue = (DoubleValue)quality.Clone(); bestQuality = BestQualityParameter.ActualValue; } Permutation solution = PermutationParameter.ActualValue; for (int i = 0; i < solution.Length; i++) longTermMemory[i, solution[i]] = iteration; double minQuality = double.MaxValue, maxQuality = double.MinValue, minImprovement = double.MaxValue, maxImprovement = double.MinValue, minRevist = double.MaxValue, maxRevist = double.MinValue; Swap2Move[] moves = ExhaustiveSwap2MoveGenerator.Apply(solution); double[] moveQualities = new double[moves.Length]; for (int i = 0; i < moves.Length; i++) { Swap2Move move = moves[i]; double moveQuality = QAPSwap2MoveEvaluator.Apply(solution, move, weights, distances); moveQualities[i] = moveQuality; if (moveQuality < minQuality) minQuality = moveQuality; if (moveQuality > maxQuality) maxQuality = moveQuality; double improvement = 0; if (shortTermMemory[move.Index1, solution[move.Index2]] > 0) improvement += Math.Max(0, shortTermMemory2[move.Index1, solution[move.Index2]] - quality.Value + moveQuality); if (shortTermMemory[move.Index2, solution[move.Index1]] > 0) improvement += Math.Max(0, shortTermMemory2[move.Index2, solution[move.Index1]] - quality.Value + moveQuality); if (improvement > 0) { if (improvement < minImprovement) minImprovement = improvement; if (improvement > maxImprovement) maxImprovement = improvement; } double revisit = 0; revisit += Math.Max(0, quality.Value - shortTermMemory2[move.Index1, solution[move.Index2]]); revisit += Math.Max(0, quality.Value - shortTermMemory2[move.Index2, solution[move.Index1]]); if (revisit > 0) { if (revisit < minRevist) minRevist = revisit; if (revisit > maxRevist) maxRevist = revisit; } } Swap2Move selectedMove = null; double bestInterestingness = double.MinValue, selectedMoveQuality = 0; int equalInterestingCount = 0; for (int i = 0; i < moves.Length; i++) { Swap2Move move = moves[i]; double interestingness = 0; if (maxQuality > minQuality) interestingness += 4 * (maxQuality - moveQualities[i]) / (maxQuality - minQuality); if (maxImprovement > minImprovement) { double improvement = 0; if (shortTermMemory[move.Index1, solution[move.Index2]] > 0) improvement += Math.Max(0, shortTermMemory2[move.Index1, solution[move.Index2]] - quality.Value + moveQualities[i]); if (shortTermMemory[move.Index2, solution[move.Index1]] > 0) improvement += Math.Max(0, shortTermMemory2[move.Index2, solution[move.Index1]] - quality.Value + moveQualities[i]); if (improvement > 0) interestingness += 2 * (improvement - minImprovement) / (maxImprovement - minImprovement); } if (iteration > 0) { interestingness += ((double)(iteration - longTermMemory[move.Index1, solution[move.Index2]]) / (double)iteration) + ((double)(iteration - longTermMemory[move.Index2, solution[move.Index1]]) / (double)iteration); } if (maxRevist > minRevist) { double revisit = 0; revisit += Math.Max(0, quality.Value - shortTermMemory2[move.Index1, solution[move.Index2]]); revisit += Math.Max(0, quality.Value - shortTermMemory2[move.Index2, solution[move.Index1]]); if (revisit > 0) interestingness += (revisit - minRevist) / (maxRevist - minRevist); } if (quality.Value + moveQualities[i] < bestQuality.Value) interestingness = double.MaxValue; if (interestingness > bestInterestingness) { bestInterestingness = interestingness; selectedMove = moves[i]; selectedMoveQuality = moveQualities[i]; equalInterestingCount = 1; } else if (interestingness == bestInterestingness) { equalInterestingCount++; if (random.NextDouble() < 1.0 / equalInterestingCount) { selectedMove = moves[i]; selectedMoveQuality = moveQualities[i]; } } } shortTermMemory[selectedMove.Index1, solution[selectedMove.Index1]] = iteration; shortTermMemory[selectedMove.Index2, solution[selectedMove.Index2]] = iteration; if (shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index2]] > 0) shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index2]] = Math.Min(quality.Value + selectedMoveQuality, shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index2]]); else shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index2]] = quality.Value + selectedMoveQuality; if (shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index1]] > 0) shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index1]] = Math.Min(quality.Value, shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index1]]); else shortTermMemory2[selectedMove.Index1, solution[selectedMove.Index1]] = quality.Value; if (shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index1]] > 0) shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index1]] = Math.Min(quality.Value + selectedMoveQuality, shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index1]]); else shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index1]] = quality.Value + selectedMoveQuality; if (shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index2]] > 0) shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index2]] = Math.Min(quality.Value, shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index2]]); else shortTermMemory2[selectedMove.Index2, solution[selectedMove.Index2]] = quality.Value; Swap2Manipulator.Apply(solution, selectedMove.Index1, selectedMove.Index2); quality.Value += selectedMoveQuality; if (quality.Value < bestQuality.Value) { bestQuality.Value = quality.Value; if (LastGlobalImprovementParameter.ActualValue == null) LastGlobalImprovementParameter.ActualValue = new IntValue(iteration); else LastGlobalImprovementParameter.ActualValue.Value = iteration; } if (!results.ContainsKey("GlobalBestFound")) results.Add(new Result("GlobalBestFound", new IntValue(-1))); if (BestKnownQualityParameter.ActualValue.Value == bestQuality.Value && ((IntValue)results["GlobalBestFound"].Value).Value < 0) { ((IntValue)results["GlobalBestFound"].Value).Value = iteration; } return base.Apply(); } } }