Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Problems.VehicleRouting/3.4/PathRelinkers/VRPPathRelinker.cs @ 15018

Last change on this file since 15018 was 15018, checked in by gkronber, 7 years ago

#2520 introduced StorableConstructorFlag type for StorableConstructors

File size: 13.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.Optimization;
29using HeuristicLab.Optimization.Operators;
30using HeuristicLab.Parameters;
31using HeuristicLab.Persistence;
32using HeuristicLab.Problems.VehicleRouting.Encodings.Potvin;
33using HeuristicLab.Problems.VehicleRouting.Interfaces;
34using HeuristicLab.Problems.VehicleRouting.ProblemInstances;
35using HeuristicLab.Problems.VehicleRouting.Variants;
36
37namespace HeuristicLab.Problems.VehicleRouting {
38  /// <summary>
39  /// An operator which relinks paths between VRP solutions.
40  /// </summary>
41  [Item("VRPPathRelinker", "An operator which relinks paths between VRP solutions.")]
42  [StorableType("d8a2168a-10ac-4a17-b8ab-0b2617092dde")]
43  public sealed class VRPPathRelinker : SingleObjectivePathRelinker, IGeneralVRPOperator, IStochasticOperator {
44    #region Parameter properties
45    public IValueParameter<IntValue> IterationsParameter {
46      get { return (IValueParameter<IntValue>)Parameters["Iterations"]; }
47    }
48    public ILookupParameter<IVRPProblemInstance> ProblemInstanceParameter {
49      get { return (ILookupParameter<IVRPProblemInstance>)Parameters["ProblemInstance"]; }
50    }
51    public ILookupParameter<IRandom> RandomParameter {
52      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
53    }
54    public IValueParameter<IntValue> SampleSizeParameter {
55      get { return (IValueParameter<IntValue>)Parameters["SampleSize"]; }
56    }
57    #endregion
58
59    [StorableConstructor]
60    private VRPPathRelinker(StorableConstructorFlag deserializing) : base(deserializing) { }
61    private VRPPathRelinker(VRPPathRelinker original, Cloner cloner) : base(original, cloner) { }
62    public VRPPathRelinker()
63      : base() {
64      Parameters.Add(new ValueParameter<IntValue>("Iterations", "The number of iterations the operator should perform.", new IntValue(50)));
65      Parameters.Add(new LookupParameter<IVRPProblemInstance>("ProblemInstance", "The VRP problem instance"));
66      Parameters.Add(new LookupParameter<IRandom>("Random", "The pseudo random number generator which should be used for stochastic manipulation operators."));
67      Parameters.Add(new ValueParameter<IntValue>("SampleSize", "The number of moves that should be executed.", new IntValue(10)));
68    }
69
70    public override IDeepCloneable Clone(Cloner cloner) {
71      return new VRPPathRelinker(this, cloner);
72    }
73
74    public static ItemArray<IItem> Apply(PotvinEncoding initiator, PotvinEncoding guide, PercentValue n, int sampleSize, int iterations, IRandom rand, IVRPProblemInstance problemInstance) {
75      if (initiator == null || guide == null)
76        throw new ArgumentException("Cannot relink path because one of the provided solutions or both are null.");
77
78      double sigma = 1.5;
79      double minPenalty = 0.001;
80      double maxPenalty = 1000000000;
81
82      var originalOverloadPenalty = new DoubleValue();
83      if (problemInstance is IHomogenousCapacitatedProblemInstance)
84        originalOverloadPenalty.Value = (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value;
85      var originalTardinessPenalty = new DoubleValue();
86      if (problemInstance is ITimeWindowedProblemInstance)
87        originalTardinessPenalty.Value = (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value;
88
89      PotvinEncoding current = MatchTours(initiator, guide, problemInstance);
90      double currentSimilarity = VRPSimilarityCalculator.CalculateSimilarity(current, guide);
91
92      IList<PotvinEncoding> solutions = new List<PotvinEncoding>();
93      int i = 0;
94      while (i < iterations && !currentSimilarity.IsAlmost(1.0)) {
95        var currentEval = problemInstance.Evaluate(current);
96        currentSimilarity = VRPSimilarityCalculator.CalculateSimilarity(current, guide);
97
98        if (currentSimilarity < 1.0) {
99          for (int sample = 0; sample < sampleSize; sample++) {
100            var next = current.Clone() as PotvinEncoding;
101
102            int neighborhood = rand.Next(3);
103            switch (neighborhood) {
104              case 0:
105                next = RouteBasedXOver(next, guide, rand,
106          problemInstance);
107                break;
108              case 1:
109                next = SequenceBasedXOver(next, guide, rand,
110          problemInstance);
111                break;
112              case 2:
113                GuidedRelocateMove(next, guide, rand);
114                break;
115            }
116
117            next = MatchTours(next, guide, problemInstance);
118
119            var nextEval = problemInstance.Evaluate(next);
120            if ((nextEval.Quality < currentEval.Quality)) {
121              current = next;
122              solutions.Add(current);
123              break;
124            }
125          }
126
127          if (problemInstance is IHomogenousCapacitatedProblemInstance) {
128            if (((CVRPEvaluation)currentEval).Overload > 0) {
129              (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value =
130                Math.Min(maxPenalty,
131                (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value * sigma);
132            } else {
133              (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value =
134                Math.Max(minPenalty,
135                (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value * sigma);
136            }
137          }
138
139
140          if (problemInstance is ITimeWindowedProblemInstance) {
141            if (((CVRPTWEvaluation)currentEval).Tardiness > 0) {
142              (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value =
143                Math.Min(maxPenalty,
144              (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value * sigma);
145            } else {
146              (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value =
147                Math.Max(minPenalty,
148                (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value / sigma);
149            }
150          }
151
152          i++;
153        }
154      }
155
156      if (problemInstance is IHomogenousCapacitatedProblemInstance)
157        (problemInstance as IHomogenousCapacitatedProblemInstance).OverloadPenalty.Value = originalOverloadPenalty.Value;
158      if (problemInstance is ITimeWindowedProblemInstance)
159        (problemInstance as ITimeWindowedProblemInstance).TardinessPenalty.Value = originalTardinessPenalty.Value;
160
161      return new ItemArray<IItem>(ChooseSelection(solutions, n));
162    }
163
164    private static IList<IItem> ChooseSelection(IList<PotvinEncoding> solutions, PercentValue n) {
165      IList<IItem> selection = new List<IItem>();
166      if (solutions.Count > 0) {
167        int noSol = (int)(solutions.Count * n.Value);
168        if (noSol <= 0) noSol++;
169        double stepSize = (double)solutions.Count / (double)noSol;
170        for (int i = 0; i < noSol; i++)
171          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
172      }
173
174      return selection;
175    }
176
177    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
178      if (parents.Length != 2)
179        throw new ArgumentException("The number of parents is not equal to 2.");
180
181      if (!(parents[0] is PotvinEncoding))
182        parents[0] = PotvinEncoding.ConvertFrom(parents[0] as IVRPEncoding, ProblemInstanceParameter.ActualValue);
183      if (!(parents[1] is PotvinEncoding))
184        parents[1] = PotvinEncoding.ConvertFrom(parents[1] as IVRPEncoding, ProblemInstanceParameter.ActualValue);
185
186      return Apply(parents[0] as PotvinEncoding, parents[1] as PotvinEncoding, n,
187        SampleSizeParameter.Value.Value, IterationsParameter.Value.Value, RandomParameter.ActualValue, ProblemInstanceParameter.ActualValue);
188    }
189
190    private static int MatchingCities(Tour tour1, Tour tour2) {
191      return tour1.Stops.Intersect(tour2.Stops).Count();
192    }
193
194    private static PotvinEncoding MatchTours(PotvinEncoding initiator, PotvinEncoding guide, IVRPProblemInstance problemInstance) {
195      var result = new PotvinEncoding(problemInstance);
196
197      var used = new List<bool>();
198      for (int i = 0; i < initiator.Tours.Count; i++) {
199        used.Add(false);
200      }
201
202      for (int i = 0; i < guide.Tours.Count; i++) {
203        int bestMatch = -1;
204        int bestTour = -1;
205
206        for (int j = 0; j < initiator.Tours.Count; j++) {
207          if (!used[j]) {
208            int match = MatchingCities(guide.Tours[i], initiator.Tours[j]);
209            if (match > bestMatch) {
210              bestMatch = match;
211              bestTour = j;
212            }
213          }
214        }
215
216        if (bestTour != -1) {
217          result.Tours.Add(initiator.Tours[bestTour]);
218          used[bestTour] = true;
219        }
220      }
221
222      for (int i = 0; i < initiator.Tours.Count; i++) {
223        if (!used[i])
224          result.Tours.Add(initiator.Tours[i]);
225      }
226
227      return result;
228    }
229
230    #region moves
231    public static PotvinEncoding RouteBasedXOver(PotvinEncoding initiator, PotvinEncoding guide, IRandom random, IVRPProblemInstance problemInstance) {
232      return PotvinRouteBasedCrossover.Apply(random, initiator, guide, problemInstance, false);
233    }
234
235    public static PotvinEncoding SequenceBasedXOver(PotvinEncoding initiator, PotvinEncoding guide, IRandom random, IVRPProblemInstance problemInstance) {
236      return PotvinSequenceBasedCrossover.Apply(random, initiator, guide, problemInstance, false);
237    }
238
239    public static void GuidedRelocateMove(PotvinEncoding initiator, PotvinEncoding guide, IRandom random) {
240      List<int> cities = new List<int>();
241      foreach (Tour tour in initiator.Tours) {
242        foreach (int city in tour.Stops) {
243          Tour guideTour = guide.Tours.First(t => t.Stops.Contains(city));
244          if (guide.Tours.IndexOf(guideTour) != initiator.Tours.IndexOf(tour)) {
245            cities.Add(city);
246          }
247        }
248      }
249
250      if (cities.Count == 0) {
251        RelocateMove(initiator, random);
252      } else {
253        int city = cities[random.Next(cities.Count)];
254        Tour tour = initiator.Tours.First(t => t.Stops.Contains(city));
255        tour.Stops.Remove(city);
256
257        Tour guideTour = guide.Tours.First(t => t.Stops.Contains(city));
258        int guideTourIndex = guide.Tours.IndexOf(guideTour);
259
260        if (guideTourIndex < initiator.Tours.Count) {
261          Tour tour2 = initiator.Tours[guideTourIndex];
262
263          int guideIndex = guideTour.Stops.IndexOf(city);
264          if (guideIndex == 0) {
265            tour2.Stops.Insert(0, city);
266          } else {
267            int predecessor = guideTour.Stops[guideIndex - 1];
268            int initIndex = tour2.Stops.IndexOf(predecessor);
269            if (initIndex != -1) {
270              tour2.Stops.Insert(initIndex + 1, city);
271            } else {
272              if (guideIndex == guideTour.Stops.Count - 1) {
273                tour2.Stops.Insert(tour2.Stops.Count, city);
274              } else {
275                int sucessor = guideTour.Stops[guideIndex + 1];
276                initIndex = tour2.Stops.IndexOf(sucessor);
277                if (initIndex != -1) {
278                  tour2.Stops.Insert(initIndex, city);
279                } else {
280                  tour2.Stops.Insert(random.Next(tour2.Stops.Count + 1), city);
281                }
282              }
283            }
284          }
285        } else {
286          Tour tour2 = new Tour();
287          tour2.Stops.Add(city);
288          initiator.Tours.Add(tour2);
289        }
290
291        if (tour.Stops.Count == 0)
292          initiator.Tours.Remove(tour);
293      }
294    }
295
296    public static void RelocateMove(PotvinEncoding individual, IRandom random) {
297      int cities = individual.Cities;
298      int city = 1 + random.Next(cities);
299      Tour originalTour = individual.Tours.Find(t => t.Stops.Contains(city));
300      //consider creating new route
301      individual.Tours.Add(new Tour());
302
303      int position = 1 + random.Next(cities + individual.Tours.Count - 1);
304      if (position >= city) {
305        position++;
306      }
307
308      int originalPosition = originalTour.Stops.IndexOf(city);
309      originalTour.Stops.RemoveAt(originalPosition);
310
311      Tour insertionTour;
312      int insertionPosition;
313      if (position <= cities) {
314        insertionTour = individual.Tours.Find(t => t.Stops.Contains(position));
315        insertionPosition = insertionTour.Stops.IndexOf(position) + 1;
316      } else {
317        insertionTour = individual.Tours[position - cities - 1];
318        insertionPosition = 0;
319      }
320
321      insertionTour.Stops.Insert(insertionPosition, city);
322
323      individual.Tours.RemoveAll(t => t.Stops.Count == 0);
324    }
325    #endregion
326  }
327}
Note: See TracBrowser for help on using the repository browser.