#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();
}
}
}