Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.Orienteering/3.3/Improvers/OrienteeringLocalImprovementOperator.cs @ 17525

Last change on this file since 17525 was 17525, checked in by abeham, 4 years ago

#2521: working on porting orienteering problem
Open points include:

  • Visualization of OrienteeringProblemData
  • Fix visualization of solution
  • Cleanup unused classes
File size: 11.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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 HEAL.Attic;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.IntegerVectorEncoding;
29using HeuristicLab.Operators;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32
33namespace HeuristicLab.Problems.Orienteering {
34  /// <summary>
35  /// Iterative improvement consists of three basic operators: shortening, vertex insert and vertex
36  /// exchange. The shortening operator tries to rearrange the vertices within a tour in order to
37  /// minimize the cost of the tour. As shortening operator a 2-opt is applied. (Schilde et. al. 2009)
38  /// </summary>
39  [Item("OrienteeringLocalImprovementOperator", @"Implements the iterative improvement procedure described in Schilde M., Doerner K.F., Hartl R.F., Kiechle G. 2009. Metaheuristics for the bi-objective orienteering problem. Swarm Intelligence, Volume 3, Issue 3, pp 179-201.")]
40  [StorableType("92FA69B3-F243-4D12-A67A-AA1D7EBCD302")]
41  public sealed class OrienteeringLocalImprovementOperator : SingleSuccessorOperator, ILocalImprovementOperator {
42
43    #region Parameter Properties
44    public ILookupParameter<IntegerVector> IntegerVectorParameter {
45      get { return (ILookupParameter<IntegerVector>)Parameters["OrienteeringSolution"]; }
46    }
47    public ILookupParameter<IOrienteeringProblemData> OrienteeringProblemDataParameter {
48      get { return (ILookupParameter<IOrienteeringProblemData>)Parameters["OrienteeringProblemData"]; }
49    }
50
51    #region ILocalImprovementOperator Parameters
52    public IValueLookupParameter<IntValue> LocalIterationsParameter {
53      get { return (IValueLookupParameter<IntValue>)Parameters["LocalIterations"]; }
54    }
55    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
56      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
57    }
58    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
59      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
60    }
61    public ILookupParameter<ResultCollection> ResultsParameter {
62      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
63    }
64    #endregion
65    public ILookupParameter<DoubleValue> QualityParameter {
66      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
67    }
68    public IValueParameter<IntValue> MaximumBlockLengthParmeter {
69      get { return (IValueParameter<IntValue>)Parameters["MaximumBlockLength"]; }
70    }
71    public IValueParameter<BoolValue> UseMaximumBlockLengthParmeter {
72      get { return (IValueParameter<BoolValue>)Parameters["UseMaximumBlockLength"]; }
73    }
74    #endregion
75
76    [StorableConstructor]
77    private OrienteeringLocalImprovementOperator(StorableConstructorFlag _) : base(_) { }
78    private OrienteeringLocalImprovementOperator(OrienteeringLocalImprovementOperator original, Cloner cloner)
79      : base(original, cloner) {
80    }
81    public OrienteeringLocalImprovementOperator()
82      : base() {
83      Parameters.Add(new LookupParameter<IntegerVector>("OrienteeringSolution", "The Orienteering Solution given in path representation."));
84      Parameters.Add(new LookupParameter<IOrienteeringProblemData>("OrienteeringProblemData", "The main data that comprises the orienteering problem."));
85
86      Parameters.Add(new ValueLookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed.", new IntValue(0)));
87      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(150)));
88      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The number of evaluated moves."));
89      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The name of the collection where the results are stored."));
90      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the solution."));
91
92      Parameters.Add(new ValueParameter<IntValue>("MaximumBlockLength", "The maximum length of the 2-opt shortening.", new IntValue(30)));
93      Parameters.Add(new ValueParameter<BoolValue>("UseMaximumBlockLength", "Use a limitation of the length for the 2-opt shortening.", new BoolValue(false)));
94    }
95
96    public override IDeepCloneable Clone(Cloner cloner) {
97      return new OrienteeringLocalImprovementOperator(this, cloner);
98    }
99
100    public override IOperation Apply() {
101      var data = OrienteeringProblemDataParameter.ActualValue;
102      int maxIterations = MaximumIterationsParameter.ActualValue.Value;
103      int maxBlockLength = MaximumBlockLengthParmeter.Value.Value;
104      bool useMaxBlockLength = UseMaximumBlockLengthParmeter.Value.Value;
105
106      bool solutionChanged = true;
107
108      var tour = IntegerVectorParameter.ActualValue.ToList();
109
110      double tourLength = 0;
111      double tourScore = tour.Sum(point => data.GetScore(point));
112
113      var localIterations = LocalIterationsParameter.ActualValue;
114      var evaluatedSolutions = EvaluatedSolutionsParameter.ActualValue;
115      int evaluations = 0;
116
117      // Check if the tour can be improved by adding or replacing points
118      while (solutionChanged && localIterations.Value < maxIterations) {
119        solutionChanged = false;
120
121        if (localIterations.Value == 0)
122          tourLength = OrienteeringProblem.CalculateTravelCosts(data, tour);
123
124        // Try to shorten the path
125        ShortenPath(tour, data, maxBlockLength, useMaxBlockLength, ref tourLength, ref evaluations);
126
127        // Determine all points that have not yet been visited by this tour
128        var visitablePoints = Enumerable.Range(0, data.RoutingData.Cities).Except(tour).ToList();
129
130        // Determine if any of the visitable points can be included at any position within the tour
131        IncludeNewPoints(tour, visitablePoints, data, ref tourLength, ref tourScore, ref evaluations, ref solutionChanged);
132
133        // Determine if any of the visitable points can take the place of an already visited point in the tour to improve the scores
134        ReplacePoints(tour, visitablePoints, data, ref tourLength, ref tourScore, ref evaluations, ref solutionChanged);
135
136        localIterations.Value++;
137      }
138
139      localIterations.Value = 0;
140      evaluatedSolutions.Value += evaluations;
141
142      // Set new tour
143      IntegerVectorParameter.ActualValue = new IntegerVector(tour.ToArray());
144      QualityParameter.ActualValue.Value = tourScore;
145
146      return base.Apply();
147    }
148
149    private void ShortenPath(List<int> tour, IOrienteeringProblemData data, int maxBlockLength, bool useMaxBlockLength, ref double tourLength, ref int evaluations) {
150      bool solutionChanged;
151      int pathSize = tour.Count;
152      maxBlockLength = (useMaxBlockLength && (pathSize > maxBlockLength + 1)) ? maxBlockLength : (pathSize - 2);
153
154      // Perform a 2-opt
155      do {
156        solutionChanged = false;
157
158        for (int blockLength = 2; blockLength < maxBlockLength; blockLength++) {
159          // If an optimization has been done, start from the beginning
160          if (solutionChanged) break;
161
162          for (int position = 1; position < (pathSize - blockLength); position++) {
163            // If an optimization has been done, start from the beginning
164            if (solutionChanged) break;
165
166            evaluations++;
167
168            double newLength = tourLength;
169            // Recalculate length of whole swapped part, in case distances are not symmetric
170            for (int index = position - 1; index < position + blockLength; index++) newLength -= data.RoutingData.GetDistance(tour[index], tour[index + 1]);
171            for (int index = position + blockLength - 1; index > position; index--) newLength += data.RoutingData.GetDistance(tour[index], tour[index - 1]);
172            newLength += data.RoutingData.GetDistance(tour[position - 1], tour[position + blockLength - 1]);
173            newLength += data.RoutingData.GetDistance(tour[position], tour[position + blockLength]);
174
175            if (newLength < tourLength - 0.00001) {
176              // Avoid cycling caused by precision
177              var reversePart = tour.GetRange(position, blockLength).AsEnumerable().Reverse();
178
179              tour.RemoveRange(position, blockLength);
180              tour.InsertRange(position, reversePart);
181
182              tourLength = newLength;
183
184              // Re-run the optimization
185              solutionChanged = true;
186            }
187          }
188        }
189      } while (solutionChanged);
190    }
191
192    private void IncludeNewPoints(List<int> tour, List<int> visitablePoints, IOrienteeringProblemData data,
193      ref double tourLength, ref double tourScore, ref int evaluations, ref bool solutionChanged) {
194
195      for (int tourPosition = 1; tourPosition < tour.Count; tourPosition++) {
196        // If an optimization has been done, start from the beginning
197        if (solutionChanged) break;
198
199        for (int i = 0; i < visitablePoints.Count; i++) {
200          // If an optimization has been done, start from the beginning
201          if (solutionChanged) break;
202
203          evaluations++;
204
205          double detour = OrienteeringProblem.CalculateInsertionCosts(data, tour, tourPosition, visitablePoints[i]);
206
207          // Determine if including the point does not violate any constraint
208          if (tourLength + detour <= data.MaximumTravelCosts) {
209            // Insert the new point at this position
210            tour.Insert(tourPosition, visitablePoints[i]);
211
212            // Update the overall tour tourLength and score
213            tourLength += detour;
214            tourScore += data.GetScore(visitablePoints[i]);
215
216            // Re-run this optimization
217            solutionChanged = true;
218          }
219        }
220      }
221    }
222
223    private void ReplacePoints(List<int> tour, List<int> visitablePoints, IOrienteeringProblemData data,
224      ref double tourLength, ref double tourScore, ref int evaluations, ref bool solutionChanged) {
225
226      for (int tourPosition = 1; tourPosition < tour.Count - 1; tourPosition++) {
227        // If an optimization has been done, start from the beginning
228        if (solutionChanged) break;
229
230        for (int i = 0; i < visitablePoints.Count; i++) {
231          // If an optimization has been done, start from the beginning
232          if (solutionChanged) break;
233
234          evaluations++;
235
236          double detour = OrienteeringProblem.CalculateReplacementCosts(data, tour, tourPosition, visitablePoints[i]);
237
238          double oldPointScore = data.GetScore(tour[tourPosition]);
239          double newPointScore = data.GetScore(visitablePoints[i]);
240
241          if ((tourLength + detour <= data.MaximumTravelCosts) && (newPointScore > oldPointScore)) {
242            // Replace the old point by the new one
243            tour[tourPosition] = visitablePoints[i];
244
245            // Update the overall tour tourLength
246            tourLength += detour;
247
248            // Update the scores achieved by visiting this point
249            tourScore += newPointScore - oldPointScore;
250
251            // Re-run this optimization
252            solutionChanged = true;
253          }
254        }
255      }
256    }
257  }
258}
Note: See TracBrowser for help on using the repository browser.