Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Problems.Orienteering/3.3/Shakers/OrienteeringShakingOperator.cs @ 11319

Last change on this file since 11319 was 11319, checked in by pfleck, 10 years ago

#2208 Renamed TerminusPoint to TerminalPoint

File size: 11.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System.Collections.Generic;
23using System.Linq;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Data;
27using HeuristicLab.Encodings.IntegerVectorEncoding;
28using HeuristicLab.Operators;
29using HeuristicLab.Optimization;
30using HeuristicLab.Parameters;
31using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
32
33namespace HeuristicLab.Problems.Orienteering {
34  [Item("OrienteeringShakingOperator", @"The used neighborhood operator is based on a two point exchange move. A move in
35the k-th neighborhood consists of removing k consecutive vertices from the tour, starting
36at a randomly selected position. Afterwards, a sorted list of all vertices not yet included
37in the current tour is built. The vertices are sorted in descending order with respect to the
38objective value increase using the current weights. Out of the first three entries with the
39highest ranking in this list, one randomly selected vertex is reinserted into the current tour
40at the same position as the removed vertices. This way, l new vertices are inserted into the
41tour. The largest neighborhood is a complete exchange of all vertices on the tour.
42The shaking procedure does not guarantee that the new tour does not exceed the cost
43limit Tmax. Therefore, in a repair step, a sorted list of all vertices in the tour is created. The
44vertices are sorted in descending order with respect to costs saved when removing the vertex
45from the tour. Vertices are removed as long as the cost limit is violated.
46(Schilde et. al. 2009)")]
47  [StorableClass]
48  public sealed class OrienteeringShakingOperator : SingleSuccessorOperator, IMultiNeighborhoodShakingOperator, IStochasticOperator {
49
50    #region Shaking Parameter Properties
51    public IValueLookupParameter<IntValue> CurrentNeighborhoodIndexParameter {
52      get { return (IValueLookupParameter<IntValue>)Parameters["CurrentNeighborhoodIndex"]; }
53    }
54    public ILookupParameter<IntValue> NeighborhoodCountParameter {
55      get { return (ILookupParameter<IntValue>)Parameters["NeighborhoodCount"]; }
56    }
57    #endregion
58
59    #region Parameter Properties
60    public ILookupParameter<IntegerVector> IntegerVectorParameter {
61      get { return (ILookupParameter<IntegerVector>)Parameters["IntegerVector"]; }
62    }
63    public ILookupParameter<DoubleValue> MaximumDistanceParameter {
64      get { return (ILookupParameter<DoubleValue>)Parameters["MaximumDistance"]; }
65    }
66    public ILookupParameter<IntValue> StartingPointParameter {
67      get { return (ILookupParameter<IntValue>)Parameters["StartingPoint"]; }
68    }
69    public ILookupParameter<IntValue> TerminalPointParameter {
70      get { return (ILookupParameter<IntValue>)Parameters["TerminalPoint"]; }
71    }
72    public ILookupParameter<DistanceMatrix> DistanceMatrixParameter {
73      get { return (ILookupParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
74    }
75    public ILookupParameter<DoubleArray> ScoresParameter {
76      get { return (ILookupParameter<DoubleArray>)Parameters["Scores"]; }
77    }
78    public ILookupParameter<DoubleValue> FixedPenaltyParameter {
79      get { return (ILookupParameter<DoubleValue>)Parameters["FixedPenalty"]; }
80    }
81
82    public ILookupParameter<IRandom> RandomParameter {
83      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
84    }
85    #endregion
86
87    [StorableConstructor]
88    private OrienteeringShakingOperator(bool deserializing) : base(deserializing) { }
89    private OrienteeringShakingOperator(OrienteeringShakingOperator original, Cloner cloner)
90      : base(original, cloner) {
91    }
92    public OrienteeringShakingOperator()
93      : base() {
94      Parameters.Add(new ValueLookupParameter<IntValue>("CurrentNeighborhoodIndex", "The index of the operator that should be applied (k)."));
95      Parameters.Add(new LookupParameter<IntValue>("NeighborhoodCount", "The number of operators that are available."));
96
97      Parameters.Add(new LookupParameter<IntegerVector>("IntegerVector", "The Orienteering Solution given in path representation."));
98      Parameters.Add(new LookupParameter<DoubleValue>("MaximumDistance", "The maximum distance constraint for a Orienteering solution."));
99      Parameters.Add(new LookupParameter<IntValue>("StartingPoint", "Index of the starting point."));
100      Parameters.Add(new LookupParameter<IntValue>("TerminalPoint", "Index of the ending point."));
101      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the points."));
102      Parameters.Add(new LookupParameter<DoubleArray>("Scores", "The scores of the points."));
103      Parameters.Add(new LookupParameter<DoubleValue>("FixedPenalty", "The penalty for each visited vertex."));
104
105      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that will be used."));
106    }
107
108    public override IDeepCloneable Clone(Cloner cloner) {
109      return new OrienteeringShakingOperator(this, cloner);
110    }
111
112    public override IOperation Apply() {
113      var initialTour = IntegerVectorParameter.ActualValue;
114      var distances = DistanceMatrixParameter.ActualValue;
115      var scores = ScoresParameter.ActualValue;
116      var startingPoint = StartingPointParameter.ActualValue.Value;
117      var terminalPoint = TerminalPointParameter.ActualValue.Value;
118      var fixedPenalty = FixedPenaltyParameter.ActualValue.Value;
119      double maxDistance = MaximumDistanceParameter.ActualValue.Value;
120      int numPoints = scores.Length;
121
122      if (NeighborhoodCountParameter.ActualValue == null)
123        NeighborhoodCountParameter.ActualValue = new IntValue(initialTour.Length);
124      else NeighborhoodCountParameter.ActualValue.Value = initialTour.Length;
125
126      var random = RandomParameter.ActualValue;
127
128      if (initialTour.Length > 2) {
129        // Limit the neighborhood to the tour length
130        int currentNeighborhood = CurrentNeighborhoodIndexParameter.ActualValue.Value + 1;
131        int maximumNeighborhood = initialTour.Length - 2; // neighborhood limit within [0, changable tour length - 1)
132        maximumNeighborhood = (maximumNeighborhood > currentNeighborhood) ? currentNeighborhood : maximumNeighborhood;
133        int neighborhood = maximumNeighborhood;//random.Next(maximumNeighborhood) + 1;
134
135        // Find all points that are not yet included in the tour and are
136        // within the maximum distance allowed (ellipse)
137        // and sort them with regard to their utility
138        var visitablePoints = (
139          from point in Enumerable.Range(0, numPoints)
140          // Calculate the distance when going from the starting point to this point and then to the end point
141          let distance = distances[startingPoint, point] + distances[point, terminalPoint] + fixedPenalty
142          // If this distance is feasible and the point is neither starting nor ending point, check the point
143          where distance < maxDistance && point != startingPoint && point != terminalPoint
144          // The point was not yet visited, so add it to the candidate list
145          where !initialTour.Contains(point)
146          // Calculate the utility of the point at this position
147          let utility = scores[point]
148          orderby utility
149          select point
150          ).ToList();
151
152        // Initialize the new tour
153        var actualTour = new List<int> { startingPoint };
154
155        // Perform the insertions according to the utility sorting
156        InsertPoints(actualTour, initialTour, neighborhood, visitablePoints, random);
157
158        // Bring the tour back to be feasible
159        CleanupTour(actualTour, distances, maxDistance, fixedPenalty);
160
161        // Set new Tour
162        IntegerVectorParameter.ActualValue = new IntegerVector(actualTour.ToArray());
163      }
164
165      return base.Apply();
166    }
167    private void InsertPoints(List<int> actualTour, IntegerVector initialTour,
168      int neighborhood, List<int> visitablePoints, IRandom random) {
169
170      // Elect the starting index of the part to be replaced
171      int tourSize = initialTour.Length;
172      int randomPosition = random.Next(tourSize - neighborhood - 1) + 1;
173
174      for (int position = 1; position < tourSize; position++) {
175        if ((position < randomPosition) || (position > (randomPosition + neighborhood - 1))) {
176          // Copy from initial tour when outside shaking range
177          actualTour.Add(initialTour[position]);
178
179          // Delete this point from the candidate list
180          visitablePoints.Remove(initialTour[position]);
181        } else {
182          // Point from within shaking range
183          if (visitablePoints.Count > 0) {
184            // Add the point with the highest utility from the candidate list
185            int randomFactor = random.Next(3);
186            int insertionIndex = visitablePoints.Count - 1;
187            if (visitablePoints.Count > 4) insertionIndex -= randomFactor;
188
189            actualTour.Add(visitablePoints[insertionIndex]);
190
191            // Delete this point from the candidate list
192            visitablePoints.RemoveAt(insertionIndex);
193          } else {
194            // We don't have any points left that could be inserted so we can only re-insert
195            // the removed and not already re-inserted points in a random order
196            for (int reinsertPosition = randomPosition; reinsertPosition < randomPosition + neighborhood; reinsertPosition++) {
197              bool alreadyReinserted = actualTour.Contains(initialTour[reinsertPosition]);
198
199              if (!alreadyReinserted)
200                visitablePoints.Add(initialTour[reinsertPosition]);
201            }
202
203            int randomIndex = random.Next(visitablePoints.Count);
204            actualTour.Add(visitablePoints[randomIndex]);
205            visitablePoints.Clear();
206          }
207        }
208      }
209    }
210    private void CleanupTour(List<int> actualTour, DistanceMatrix distances, double maxDistance, double fixedPenalty) {
211      // Sort the points on the tour according to their costs savings when removed
212      var distanceSavings = (
213        from removePosition in Enumerable.Range(1, actualTour.Count - 2)
214        let saving = distances.CalculateRemovementSaving(actualTour, removePosition, fixedPenalty)
215        orderby saving descending
216        select new SavingInfo { Index = removePosition, Saving = saving }
217      ).ToList();
218
219      double tourLength = distances.CalculateTourLength(actualTour, fixedPenalty);
220
221      // As long as the created path is infeasible, remove elements
222      while (tourLength > maxDistance) {
223        // Remove the point that frees the largest distance
224        // Note, distance savings are not updated after removal
225        tourLength -= distances.CalculateRemovementSaving(actualTour, distanceSavings[0].Index, fixedPenalty);
226        actualTour.RemoveAt(distanceSavings[0].Index);
227
228        // Shift indices due to removal of a point in the tour
229        for (int i = 1; i < distanceSavings.Count; i++) {
230          if (distanceSavings[i].Index > distanceSavings[0].Index) {
231            distanceSavings[i].Index--;
232          }
233        }
234        distanceSavings.RemoveAt(0);
235      }
236    }
237    //
238    private class SavingInfo {
239      public int Index;
240      public double Saving;
241    }
242  }
243}
Note: See TracBrowser for help on using the repository browser.