#region License Information /* HeuristicLab * Copyright (C) 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.Parameters; using HEAL.Attic; namespace HeuristicLab.Problems.PTSP { [Item("PTSP Estimated Insertion Move Evaluator", "Evaluates an insertion move (1-shift)")] [StorableType("DAC1CBD1-BF27-4BB4-B7C5-82EC58F7F5C9")] public class PTSPEstimatedInsertionMoveEvaluator : EstimatedPTSPMoveEvaluator, IPermutationTranslocationMoveOperator { public ILookupParameter TranslocationMoveParameter { get { return (ILookupParameter)Parameters["TranslocationMove"]; } } [StorableConstructor] protected PTSPEstimatedInsertionMoveEvaluator(StorableConstructorFlag _) : base(_) { } protected PTSPEstimatedInsertionMoveEvaluator(PTSPEstimatedInsertionMoveEvaluator original, Cloner cloner) : base(original, cloner) { } public PTSPEstimatedInsertionMoveEvaluator() : base() { Parameters.Add(new LookupParameter("TranslocationMove", "The move to evaluate.")); } public override IDeepCloneable Clone(Cloner cloner) { return new PTSPEstimatedInsertionMoveEvaluator(this, cloner); } public static double EvaluateMove(Permutation tour, TranslocationMove move, Func distance, ItemList realizations) { var afterMove = (Permutation)tour.Clone(); TranslocationManipulator.Apply(afterMove, move.Index1, move.Index1, move.Index3); double moveQuality = 0; var edges = new int[12]; var indices = new int[12]; edges[0] = tour.GetCircular(move.Index1 - 1); indices[0] = DecreaseCircularIndex(tour.Length, move.Index1); edges[1] = tour[move.Index1]; indices[1] = move.Index1; edges[2] = tour[move.Index1]; indices[2] = move.Index1; edges[3] = tour.GetCircular(move.Index1 + 1); indices[3] = IncreaseCircularIndex(tour.Length, move.Index1); edges[6] = afterMove.GetCircular(move.Index3 - 1); indices[6] = DecreaseCircularIndex(afterMove.Length, move.Index3); edges[7] = afterMove[move.Index3]; indices[7] = move.Index3; edges[8] = afterMove[move.Index3]; indices[8] = move.Index3; edges[9] = afterMove.GetCircular(move.Index3 + 1); indices[9] = IncreaseCircularIndex(afterMove.Length, move.Index3); if (move.Index3 > move.Index1) { edges[4] = tour[move.Index3]; indices[4] = move.Index3; edges[5] = tour.GetCircular(move.Index3 + 1); indices[5] = indices[9]; edges[10] = afterMove.GetCircular(move.Index1 - 1); indices[10] = indices[0]; edges[11] = afterMove[move.Index1]; indices[11] = move.Index1; } else { edges[4] = tour.GetCircular(move.Index3 - 1); indices[4] = indices[6]; edges[5] = tour[move.Index3]; indices[5] = move.Index3; edges[10] = afterMove[move.Index1]; indices[10] = move.Index1; edges[11] = afterMove.GetCircular(move.Index1 + 1); indices[11] = indices[3]; } int[] aPosteriori = new int[12]; foreach (var realization in realizations) { for (int i = 0; i < edges.Length; i++) { Permutation tempPermutation; if (i < 6) { tempPermutation = tour; } else { tempPermutation = afterMove; } if (realization[edges[i]]) { aPosteriori[i] = edges[i]; } else { int j = 1; if (i % 2 == 0) { // find nearest predecessor in realization if source edge while (!realization[tempPermutation.GetCircular(indices[i] - j)]) { j++; } aPosteriori[i] = tempPermutation.GetCircular(indices[i] - j); } else { // find nearest successor in realization if target edge while (!realization[tempPermutation.GetCircular(indices[i] + j)]) { j++; } aPosteriori[i] = tempPermutation.GetCircular(indices[i] + j); } } } if (!(aPosteriori[0] == aPosteriori[2] && aPosteriori[1] == aPosteriori[3]) && !(aPosteriori[0] == aPosteriori[4] && aPosteriori[1] == aPosteriori[5]) && !(aPosteriori[2] == aPosteriori[4] && aPosteriori[3] == aPosteriori[5])) { // compute cost difference between the two a posteriori solutions moveQuality = moveQuality + distance(aPosteriori[6], aPosteriori[7]) + distance(aPosteriori[8], aPosteriori[9]) + distance(aPosteriori[10], aPosteriori[11]); moveQuality = moveQuality - distance(aPosteriori[0], aPosteriori[1]) - distance(aPosteriori[2], aPosteriori[3]) - distance(aPosteriori[4], aPosteriori[5]); } Array.Clear(aPosteriori, 0, aPosteriori.Length); } // return average of cost differences return moveQuality / realizations.Count; } private static int DecreaseCircularIndex(int length, int index) { var result = index - 1; if (result == -1) { result = length - 1; } return result; } private static int IncreaseCircularIndex(int length, int index) { var result = index + 1; if (result == length + 1) { result = 0; } return result; } protected override double EvaluateMove(Permutation tour, Func distance, ItemList realizations) { return EvaluateMove(tour, TranslocationMoveParameter.ActualValue, distance, realizations); } } }