Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2208:

  • Fixed bug in LocalImprovementOperator.
  • Implemented ShakingOperator.
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 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
55    public ILookupParameter<IntValue> NeighborhoodCountParameter {
56      get { return (ILookupParameter<IntValue>)Parameters["NeighborhoodCount"]; }
57    }
58    #endregion
59
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> TerminusPointParameter {
70      get { return (ILookupParameter<IntValue>)Parameters["TerminusPoint"]; }
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
86    [StorableConstructor]
87    private OrienteeringShakingOperator(bool deserializing) : base(deserializing) { }
88    private OrienteeringShakingOperator(OrienteeringShakingOperator original, Cloner cloner)
89      : base(original, cloner) {
90      //RegisterEventHandlers();
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      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that will be used."));
97
98      Parameters.Add(new LookupParameter<IntegerVector>("IntegerVector", "The Orienteering Solution given in path representation."));
99      Parameters.Add(new LookupParameter<DoubleValue>("MaximumDistance", "The maximum distance constraint for a Orienteering solution."));
100      Parameters.Add(new LookupParameter<IntValue>("StartingPoint", "Index of the starting point."));
101      Parameters.Add(new LookupParameter<IntValue>("TerminusPoint", "Index of the ending point."));
102      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the points."));
103      Parameters.Add(new LookupParameter<DoubleArray>("Scores", "The scores of the points."));
104      Parameters.Add(new LookupParameter<DoubleValue>("FixedPenalty", "The penalty for each visited vertex."));
105
106      //RegisterEventHandlers();
107    }
108
109    public override IDeepCloneable Clone(Cloner cloner) {
110      return new OrienteeringShakingOperator(this, cloner);
111    }
112
113    [StorableHook(HookType.AfterDeserialization)]
114    private void AfterDeserialization() {
115      //RegisterEventHandlers();
116    }
117
118    public override IOperation Apply() {
119      var initialTour = IntegerVectorParameter.ActualValue;
120      var distances = DistanceMatrixParameter.ActualValue;
121      var scores = ScoresParameter.ActualValue;
122      var startingPoint = StartingPointParameter.ActualValue.Value;
123      var terminusPoint = TerminusPointParameter.ActualValue.Value;
124      var fixedPenalty = FixedPenaltyParameter.ActualValue.Value;
125      double maxDistance = MaximumDistanceParameter.ActualValue.Value;
126      int numPoints = scores.Length;
127
128      if (NeighborhoodCountParameter.ActualValue == null)
129        NeighborhoodCountParameter.ActualValue = new IntValue(initialTour.Length);
130      else NeighborhoodCountParameter.ActualValue.Value = initialTour.Length;
131
132      var random = RandomParameter.ActualValue;
133
134      // Limit the neighborhood to the tour length
135      int maxNeighborhood = CurrentNeighborhoodIndexParameter.ActualValue.Value + 1;
136      int limit = initialTour.Length - 3;
137      int neighborhood = random.Next((limit > maxNeighborhood) ? maxNeighborhood : limit) + 1;
138
139      // Find all points that are not yet included in the tour and are
140      // within the maximum distance allowed (ellipse) and sort them with
141      // regard to their utility
142      var visitablePoints = (
143          from i in Enumerable.Range(0, numPoints)
144          // Calculate the distance when going from the starting point to this point and then to the end point
145          let distance = distances[startingPoint, i] + distances[i, terminusPoint] + fixedPenalty
146          // If this distance is feasible and the point is neither starting nor ending point, check the point
147          where distance < maxDistance && i != startingPoint && i != terminusPoint
148          // The point was not yet visited, so add it to the candidate list
149          where !initialTour.Contains(i)
150          // Calculate the utility of the point at this position
151          let utility = scores[i]
152          orderby utility
153          select i
154        ).ToList();
155
156      // Elect the starting index of the part to be replaced
157      int tourSize = initialTour.Length;
158      int randomPosition = random.Next(tourSize - neighborhood - 2) + 1;
159
160      // Initialize the new tour
161      var actualTour = new List<int> { startingPoint };
162
163      // Perform the insertions according to the utility sorting
164      for (int position = 1; position < tourSize; position++) {
165        if ((position < randomPosition) || (position > (randomPosition + neighborhood - 1))) {
166          // Copy from initial tour when outside shaking range
167          actualTour.Add(initialTour[position]);
168
169          // Delete this point from the candidate list
170          visitablePoints.Remove(initialTour[position]);
171        } else {
172          if (visitablePoints.Count > 0) {
173            // Add the point with the highest utility from the candidate list
174            int randomFactor = random.Next(3);
175            int insertionIndex = visitablePoints.Count - 1;
176            if (visitablePoints.Count > 4) insertionIndex -= randomFactor;
177
178            actualTour.Add(visitablePoints[insertionIndex]);
179
180            // Delete this point from the candidate list
181            visitablePoints.RemoveAt(insertionIndex);
182          } else {
183            // We don't have any points left that could be inserted so we can only re-insert
184            // the removed and not already re-inserted points in a random order
185            for (int reinsertPosition = randomPosition;
186              reinsertPosition < (randomPosition + neighborhood);
187              reinsertPosition++) {
188              bool alreadyReinserted = actualTour.Contains(initialTour[reinsertPosition]);
189
190              if (!alreadyReinserted)
191                visitablePoints.Add(initialTour[reinsertPosition]);
192            }
193
194            int randomIndex = random.Next(visitablePoints.Count - 1);
195            actualTour.Add(visitablePoints[randomIndex]);
196            visitablePoints.Clear();
197          }
198        }
199      }
200
201      // Bring the tour back to be feasible
202      CleanupTour(actualTour, distances, maxDistance, fixedPenalty);
203
204      // Set new Tour
205      IntegerVectorParameter.ActualValue = new IntegerVector(actualTour.ToArray());
206
207      return base.Apply();
208    }
209
210    private void CleanupTour(List<int> actualTour, DistanceMatrix distances, double maxDistance, double fixedPenalty) {
211      var distanceSavingsList = new List<double>();
212      var sortedPoints = new List<int>();
213
214      // Sort the points on the tour according to their score
215      int tourPointMax = actualTour.Count - 1;
216      for (int tourPoint = 1; tourPoint < tourPointMax; tourPoint++) {
217        double distanceSaving = distances[actualTour[tourPoint - 1], actualTour[tourPoint]];
218        distanceSaving += distances[actualTour[tourPoint], actualTour[tourPoint + 1]];
219        distanceSaving -= distances[actualTour[tourPoint - 1], actualTour[tourPoint + 1]];
220
221        bool inserted = false;
222        int sortMax = sortedPoints.Count;
223        for (int sortCounter = 0; sortCounter < sortMax; sortCounter++) {
224          if (distanceSaving > distanceSavingsList[sortCounter]) {
225            distanceSavingsList.Insert(sortCounter, distanceSaving);
226            sortedPoints.Insert(sortCounter, tourPoint);
227            inserted = true;
228            break;
229          }
230        }
231        if (!inserted) {
232          distanceSavingsList.Add(distanceSaving);
233          sortedPoints.Add(tourPoint);
234        }
235      }
236
237      // As long as the created path is infeasible, remove elements
238      while (distances.CalculateTourLength(actualTour, fixedPenalty) > maxDistance) {
239        // Remove the point that frees the largest distance
240        actualTour.RemoveAt(sortedPoints[0]);
241
242        int sortMax = sortedPoints.Count;
243        for (int sortCounter = 1; sortCounter < sortMax; sortCounter++) {
244          if (sortedPoints[sortCounter] > sortedPoints[0]) {
245            sortedPoints[sortCounter]--;
246          }
247        }
248        sortedPoints.RemoveAt(0);
249        distanceSavingsList.RemoveAt(0);
250      }
251    }
252  }
253}
Note: See TracBrowser for help on using the repository browser.