Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Problems.Orienteering/3.3/Improvers/OrienteeringLocalImprovementOperator.cs @ 11245

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

#2208

  • Added visualization in the visualization tab of the problem
  • Fixed bug in shaking operator when tour only consists of start and end point
File size: 13.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;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.IntegerVectorEncoding;
29using HeuristicLab.Operators;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33
34namespace HeuristicLab.Problems.Orienteering {
35  [Item("OrienteeringLocalImprovementOperator", @"Iterative improvement consists of three basic operators: shortening, vertex insert and vertex
36exchange. The shortening operator tries to rearrange the vertices within a tour in order to
37minimize the cost of the tour. As shortening operator a 2-opt is applied. (Schilde et. al. 2009)")]
38  [StorableClass]
39  public class OrienteeringLocalImprovementOperator : SingleSuccessorOperator, ILocalImprovementOperator {
40    #region IGenericLocalImprovementOperator Properties
41    public Type ProblemType { get { return typeof(OrienteeringProblem); } }
42
43    public OrienteeringProblem Problem {
44      get { return problem; }
45      set { ((ILocalImprovementOperator)this).Problem = value; }
46    }
47    IProblem ILocalImprovementOperator.Problem {
48      get { return problem; }
49      set {
50        if (problem != value) {
51          if (value != null && !(value is OrienteeringProblem))
52            throw new ArgumentException("Only problems of type " + ProblemType.ToString() + " can be assigned.");
53          problem = (OrienteeringProblem)value;
54        }
55      }
56    }
57    #endregion
58
59    [Storable]
60    private OrienteeringProblem problem;
61
62    #region Parameter Properties
63    public ILookupParameter<IntegerVector> IntegerVectorParameter {
64      get { return (ILookupParameter<IntegerVector>)Parameters["OrienteeringSolution"]; }
65    }
66    public ILookupParameter<DistanceMatrix> DistanceMatrixParameter {
67      get { return (ILookupParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
68    }
69    public ILookupParameter<DoubleArray> ScoresParameter {
70      get { return (ILookupParameter<DoubleArray>)Parameters["Scores"]; }
71    }
72    public ILookupParameter<DoubleValue> MaximumDistanceParameter {
73      get { return (ILookupParameter<DoubleValue>)Parameters["MaximumDistance"]; }
74    }
75    public ILookupParameter<IntValue> StartingPointParameter {
76      get { return (ILookupParameter<IntValue>)Parameters["StartingPoint"]; }
77    }
78    public ILookupParameter<IntValue> TerminusPointParameter {
79      get { return (ILookupParameter<IntValue>)Parameters["TerminusPoint"]; }
80    }
81    public ILookupParameter<DoubleValue> FixedPenaltyParameter {
82      get { return (ILookupParameter<DoubleValue>)Parameters["FixedPenalty"]; }
83    }
84    #region ILocalImprovementOperator Parameters
85    public IValueLookupParameter<IntValue> LocalIterationsParameter {
86      get { return (IValueLookupParameter<IntValue>)Parameters["LocalIterations"]; }
87    }
88    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
89      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
90    }
91    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
92      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
93    }
94    public ILookupParameter<ResultCollection> ResultsParameter {
95      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
96    }
97    #endregion
98    public ILookupParameter<DoubleValue> QualityParameter {
99      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
100    }
101    public IValueParameter<IntValue> MaximumBlockLengthParmeter {
102      get { return (IValueParameter<IntValue>)Parameters["MaximumBlockLength"]; }
103    }
104    public IValueParameter<BoolValue> UseMaximumBlockLengthParmeter {
105      get { return (IValueParameter<BoolValue>)Parameters["UseMaximumBlockLength"]; }
106    }
107    #endregion
108
109    [StorableConstructor]
110    private OrienteeringLocalImprovementOperator(bool deserializing) : base(deserializing) { }
111    private OrienteeringLocalImprovementOperator(OrienteeringLocalImprovementOperator original, Cloner cloner)
112      : base(original, cloner) {
113      this.problem = cloner.Clone(original.problem);
114    }
115    public OrienteeringLocalImprovementOperator()
116      : base() {
117      Parameters.Add(new LookupParameter<IntegerVector>("OrienteeringSolution", "The Orienteering Solution given in path representation."));
118      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the points."));
119      Parameters.Add(new LookupParameter<DoubleArray>("Scores", "The scores of the points."));
120      Parameters.Add(new LookupParameter<DoubleValue>("MaximumDistance", "The maximum distance constraint for a Orienteering solution."));
121      Parameters.Add(new LookupParameter<IntValue>("StartingPoint", "Index of the starting point."));
122      Parameters.Add(new LookupParameter<IntValue>("TerminusPoint", "Index of the ending point."));
123      Parameters.Add(new LookupParameter<DoubleValue>("FixedPenalty", "The penalty for each visited vertex."));
124
125      Parameters.Add(new ValueLookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed.", new IntValue(0)));
126      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(150)));
127      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The number of evaluated moves."));
128      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The name of the collection where the results are stored."));
129      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the solution."));
130
131      Parameters.Add(new ValueParameter<IntValue>("MaximumBlockLength", "The maximum length of the 2-opt shortening.", new IntValue(30)));
132      Parameters.Add(new ValueParameter<BoolValue>("UseMaximumBlockLength", "Use a limitation of the length for the 2-opt shortening.", new BoolValue(false)));
133    }
134
135    public override IDeepCloneable Clone(Cloner cloner) {
136      return new OrienteeringLocalImprovementOperator(this, cloner);
137    }
138
139    public override IOperation Apply() {
140      int numPoints = ScoresParameter.ActualValue.Length;
141      var distances = DistanceMatrixParameter.ActualValue;
142      var scores = ScoresParameter.ActualValue;
143      double fixedPenalty = FixedPenaltyParameter.ActualValue.Value;
144      double maxLength = MaximumDistanceParameter.ActualValue.Value;
145      int maxIterations = MaximumIterationsParameter.ActualValue.Value;
146      int maxBlockLength = MaximumBlockLengthParmeter.Value.Value;
147      bool useMaxBlockLength = UseMaximumBlockLengthParmeter.Value.Value;
148
149      bool optimizationDone = true;
150
151      var tour = IntegerVectorParameter.ActualValue.ToList();
152
153      double tourLength = distances.CalculateTourLength(tour, fixedPenalty);
154      double tourScore = tour.Sum(point => scores[point]);
155
156      var localIterations = LocalIterationsParameter.ActualValue;
157      var evaluatedSolutions = EvaluatedSolutionsParameter.ActualValue;
158      int evaluations = 0;
159
160      // Check if the tour can be improved by adding or replacing points
161      while (optimizationDone && localIterations.Value < maxIterations) {
162        optimizationDone = false;
163
164        // Try to shorten the path
165        ShortenPath(tour, distances, maxBlockLength, useMaxBlockLength, ref tourLength, ref evaluations);
166
167        // Determine all points that have not yet been visited by this tour
168        var visitablePoints = Enumerable.Range(0, numPoints).Except(tour).ToList();
169
170        // Determine if any of the visitable points can be included at any position within the tour
171        IncludeNewPoints(tour, visitablePoints,
172          distances, fixedPenalty, maxLength, scores,
173          ref tourLength, ref tourScore, ref evaluations, ref optimizationDone);
174
175        // Determine if any of the visitable points can take the place of an already visited point in the tour to improve the scores
176        ReplacePoints(tour, visitablePoints,
177          distances, maxLength, scores,
178          ref tourLength, ref tourScore, ref evaluations, ref optimizationDone);
179
180        localIterations.Value++;
181      }
182
183      localIterations.Value = 0;
184      evaluatedSolutions.Value += evaluations;
185
186      // Set new tour
187      IntegerVectorParameter.ActualValue = new IntegerVector(tour.ToArray());
188      QualityParameter.ActualValue.Value = tourScore;
189
190      return base.Apply();
191    }
192
193    private void ShortenPath(List<int> tour, DistanceMatrix distances, int maxBlockLength, bool useMaxBlockLength, ref double tourLength, ref int evaluations) {
194      bool optimizationDone = true;
195      int pathSize = tour.Count;
196      maxBlockLength = (useMaxBlockLength && (pathSize > maxBlockLength + 1)) ? maxBlockLength : (pathSize - 2);
197
198      // Perform a 2-opt
199      while (optimizationDone) {
200        optimizationDone = false;
201
202        for (int blockLength = 2; blockLength < maxBlockLength; blockLength++) {
203          // If an optimization has been done, start from the beginning
204          if (optimizationDone) break;
205
206          for (int position = 1; position < (pathSize - blockLength); position++) {
207            // If an optimization has been done, start from the beginning
208            if (optimizationDone) break;
209
210            evaluations++;
211
212            double newLength = tourLength;
213            // Recalculate length of whole swapped part, in case distances are not symmetric
214            for (int index = position - 1; index < position + blockLength; index++) newLength -= distances[tour[index], tour[index + 1]];
215            for (int index = position + blockLength - 1; index > position; index--) newLength += distances[tour[index], tour[index - 1]];
216            newLength += distances[tour[position - 1], tour[position + blockLength - 1]];
217            newLength += distances[tour[position], tour[position + blockLength]];
218
219            if (newLength < tourLength - 0.00001) { // Avoid cycling caused by precision
220              var reversePart = tour.GetRange(position, blockLength).AsEnumerable().Reverse();
221
222              tour.RemoveRange(position, blockLength);
223              tour.InsertRange(position, reversePart);
224
225              tourLength = newLength;
226
227              // Re-run the optimization
228              optimizationDone = true;
229            }
230          }
231        }
232      }
233    }
234    private void IncludeNewPoints(List<int> tour, List<int> visitablePoints,
235      DistanceMatrix distances, double fixedPenalty, double maxLength, DoubleArray scores,
236      ref double tourLength, ref double tourScore, ref int evaluations, ref bool optimizationDone) {
237
238      for (int tourPosition = 1; tourPosition < tour.Count; tourPosition++) {
239        // If an optimization has been done, start from the beginning
240        if (optimizationDone) break;
241
242        for (int i = 0; i < visitablePoints.Count; i++) {
243          // If an optimization has been done, start from the beginning
244          if (optimizationDone) break;
245
246          evaluations++;
247
248          double detour = distances.CalculateInsertionCosts(tour, tourPosition, visitablePoints[i], fixedPenalty);
249
250          // Determine if including the point does not violate any constraint
251          if (tourLength + detour <= maxLength) {
252            // Insert the new point at this position
253            tour.Insert(tourPosition, visitablePoints[i]);
254
255            // Update the overall tour tourLength and score
256            tourLength += detour;
257            tourScore += scores[visitablePoints[i]];
258
259            // Re-run this optimization
260            optimizationDone = true;
261          }
262        }
263      }
264    }
265    private void ReplacePoints(List<int> tour, List<int> visitablePoints,
266      DistanceMatrix distances, double maxLength, DoubleArray scores,
267      ref double tourLength, ref double tourScore, ref int evaluations, ref bool optimizationDone) {
268
269      for (int tourPosition = 1; tourPosition < tour.Count - 1; tourPosition++) {
270        // If an optimization has been done, start from the beginning
271        if (optimizationDone) break;
272
273        for (int i = 0; i < visitablePoints.Count; i++) {
274          // If an optimization has been done, start from the beginning
275          if (optimizationDone) break;
276
277          evaluations++;
278
279          double detour = distances.CalculateReplacementCosts(tour, tourPosition, visitablePoints[i]);
280
281          double oldPointScore = scores[tour[tourPosition]];
282          double newPointScore = scores[visitablePoints[i]];
283
284          if ((tourLength + detour <= maxLength) && (newPointScore > oldPointScore)) {
285            // Replace the old point by the new one
286            tour[tourPosition] = visitablePoints[i];
287
288            // Update the overall tour tourLength
289            tourLength += detour;
290
291            // Update the scores achieved by visiting this point
292            tourScore += newPointScore - oldPointScore;
293
294            // Re-run this optimization
295            optimizationDone = true;
296          }
297        }
298      }
299    }
300  }
301}
Note: See TracBrowser for help on using the repository browser.