Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinInsertionBasedCrossover.cs @ 6455

Last change on this file since 6455 was 6455, checked in by svonolfe, 13 years ago

Worked on insertion based crossover (#1561)

File size: 10.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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 HeuristicLab.Common;
23using HeuristicLab.Core;
24using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
25using System.Collections.Generic;
26using HeuristicLab.Data;
27using System;
28using HeuristicLab.Parameters;
29
30namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
31  [Item("PotvinInsertionBasedCrossover", "The IBX crossover for VRP representations. It is implemented as described in Berger, J and Solois, M and Begin, R (1998). A hybrid genetic algorithm for the vehicle routing problem with time windows. LNCS 1418. Springer, London 114-127.")]
32  [StorableClass]
33  public sealed class PotvinInsertionBasedCrossover : PotvinCrossover {
34    public IValueParameter<IntValue> Length {
35      get { return (IValueParameter<IntValue>)Parameters["Length"]; }
36    }
37
38    [StorableConstructor]
39    private PotvinInsertionBasedCrossover(bool deserializing) : base(deserializing) { }
40    private PotvinInsertionBasedCrossover(PotvinInsertionBasedCrossover original, Cloner cloner)
41      : base(original, cloner) {
42    }
43    public override IDeepCloneable Clone(Cloner cloner) {
44      return new PotvinInsertionBasedCrossover(this, cloner);
45    }
46    public PotvinInsertionBasedCrossover()
47      : base() {
48        Parameters.Add(new ValueParameter<IntValue>("Length", "The maximum length of the replaced route.", new IntValue(1)));
49    }
50
51    protected static int SelectRandomTourBiasedByLength(IRandom random, PotvinEncoding individual) {
52      int tourIndex = -1;
53
54      double sum = 0.0;
55      double[] probabilities = new double[individual.Tours.Count];
56      for (int i = 0; i < individual.Tours.Count; i++) {
57        probabilities[i] = 1.0 / ((double)individual.Tours[i].Cities.Count / (double)individual.Cities);
58        sum += probabilities[i];
59      }
60
61      for (int i = 0; i < probabilities.Length; i++)
62        probabilities[i] = probabilities[i] / sum;
63
64      double rand = random.NextDouble();
65      double cumulatedProbabilities = 0.0;
66      int index = 0;
67      while (tourIndex == -1 && index < probabilities.Length) {
68        if (cumulatedProbabilities <= rand && rand <= cumulatedProbabilities + probabilities[index])
69          tourIndex = index;
70
71        cumulatedProbabilities += probabilities[index];
72        index++;
73      }
74
75      return tourIndex;
76    }
77
78    private double CalculateCentroidDistance(Tour t1, Tour t2, DoubleMatrix coordinates) {
79      double xSum = 0;
80      double ySum = 0;
81      double c1X, c1Y, c2X, c2Y;
82
83      for (int i = 0; i < t1.Cities.Count; i++) {
84        xSum += coordinates[t1.Cities[i], 0];
85        ySum += coordinates[t1.Cities[i], 0];
86      }
87      c1X = xSum / t1.Cities.Count;
88      c1Y = ySum / t1.Cities.Count;
89
90      for (int i = 0; i < t2.Cities.Count; i++) {
91        xSum += coordinates[t2.Cities[i], 0];
92        ySum += coordinates[t2.Cities[i], 0];
93      }
94      c2X = xSum / t1.Cities.Count;
95      c2Y = ySum / t1.Cities.Count;
96
97      return Math.Sqrt(
98            Math.Pow(c1X - c2X, 2) +
99            Math.Pow(c1Y - c2Y, 2));
100    }
101
102    private double CalculateMeanCentroidDistance(Tour t1, IList<Tour> tours, DoubleMatrix coordinates) {
103      double sum = 0;
104
105      for (int i = 0; i < tours.Count; i++) {
106        sum += CalculateCentroidDistance(t1, tours[i], coordinates);
107      }
108
109      return sum / tours.Count;
110    }
111
112    private int SelectCityBiasedByNeighborDistance(IRandom random, Tour tour, DistanceMatrix distMatrix) {
113      int cityIndex = -1;
114
115      double sum = 0.0;
116      double[] probabilities = new double[tour.Cities.Count];
117      for (int i = 0; i < tour.Cities.Count; i++) {
118        int next = i + 1;
119        if (next >= tour.Cities.Count)
120          next = 0;
121        else
122          next = tour.Cities[next];
123        double distance = VRPUtilities.GetDistance(
124          tour.Cities[i], next, distMatrix);
125
126        int prev = i - 1;
127        if (prev < 0)
128          prev = 0;
129        else
130          prev = tour.Cities[prev];
131        distance += VRPUtilities.GetDistance(
132          tour.Cities[i], prev, distMatrix);
133
134        probabilities[i] = distance;
135        sum += probabilities[i];
136      }
137
138      for (int i = 0; i < probabilities.Length; i++)
139        probabilities[i] = probabilities[i] / sum;
140
141      double rand = random.NextDouble();
142      double cumulatedProbabilities = 0.0;
143      int index = 0;
144      while (cityIndex == -1 && index < probabilities.Length) {
145        if (cumulatedProbabilities <= rand && rand <= cumulatedProbabilities + probabilities[index])
146          cityIndex = index;
147
148        cumulatedProbabilities += probabilities[index];
149        index++;
150      }
151
152      return cityIndex;
153    }
154
155    private bool FindRouteInsertionPlace(
156      Tour tour,
157      DoubleArray dueTimeArray,
158      DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity,
159      DistanceMatrix distMatrix,
160      int city, out int place) {
161      place = -1;
162      bool bestFeasible = false;
163      double minDetour = 0;
164
165      for (int i = 0; i <= tour.Cities.Count; i++) {
166        double length = tour.GetLength(distMatrix);
167
168        tour.Cities.Insert(i, city);
169
170        bool feasible = tour.Feasible(dueTimeArray, serviceTimeArray, readyTimeArray, demandArray,
171          capacity, distMatrix);
172
173        if (!bestFeasible || feasible) {
174          double newLength = tour.GetLength(distMatrix);
175          double detour = newLength - length;
176
177          if (place <= 0 || (!(bestFeasible && !feasible)) && detour < minDetour || (feasible && !bestFeasible)) {
178            place = i;
179            minDetour = detour;
180
181            if (feasible)
182              bestFeasible = true;
183          }
184        }
185
186        tour.Cities.RemoveAt(i);
187      }
188
189      return place >= 0;
190    }
191
192    protected override PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2) {
193      PotvinEncoding child = new PotvinEncoding();
194      bool success = true;
195
196      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
197      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
198      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
199      DoubleArray dueTime = DueTimeParameter.ActualValue;
200      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
201      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
202      DoubleArray demand = DemandParameter.ActualValue;
203      DoubleValue capacity = CapacityParameter.ActualValue;
204
205      List<Tour> R1 = new List<Tour>();
206      PotvinEncoding p1Clone = parent1.Clone() as PotvinEncoding;
207
208      int length = Math.Min(Length.Value.Value, parent1.Tours.Count) + 1;
209      int k = random.Next(1, length);
210      for (int i = 0; i < k; i++) {
211        int index = SelectRandomTourBiasedByLength(random, p1Clone);
212        R1.Add(p1Clone.Tours[index]);
213        p1Clone.Tours.RemoveAt(index);
214      }
215
216      foreach (Tour r1 in R1) {
217        List<int> R2 = new List<int>();
218
219        double r = CalculateMeanCentroidDistance(r1, parent2.Tours, coordinates);
220        foreach (Tour tour in parent2.Tours) {
221          if (CalculateCentroidDistance(r1, tour, coordinates) <= r) {
222            R2.AddRange(tour.Cities);
223          }
224        }
225
226        Tour childTour = new Tour();
227        childTour.Cities.AddRange(r1.Cities);
228
229        //DESTROY - remove cities from r1
230        int removed = random.Next(1, r1.Cities.Count + 1);
231        for (int i = 0; i < removed; i++) {
232          childTour.Cities.RemoveAt(SelectCityBiasedByNeighborDistance(random, childTour, distMatrix));
233        }
234
235        //REPAIR - add cities from R2
236        bool insertSuccess = true;
237        int maxCount = random.Next(1, Math.Min(5, R2.Count));
238        int count = 0;
239
240        while (count < maxCount && R2.Count != 0) {
241          PotvinEncoding newChild = child.Clone() as PotvinEncoding;
242          newChild.Tours.Add(childTour);
243
244          int index = random.Next(R2.Count);
245          int city = R2[index];
246          R2.RemoveAt(index);
247
248          int place = -1;
249          if(FindRouteInsertionPlace(childTour, dueTime, serviceTime, readyTime,
250            demand, capacity, distMatrix, city, out place)) {
251            childTour.Cities.Insert(place, city);
252
253            if (!Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity)) {
254              childTour.Cities.RemoveAt(place);
255              insertSuccess = false;
256            } else {
257              count++;
258            }
259          }
260        }
261
262        child.Tours.Add(childTour);
263        if (!Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity)) {
264          /*success = false;
265          break;*/
266        }
267      }
268
269      if (success) {
270        for (int i = 0; i < p1Clone.Tours.Count; i++) {
271          Tour childTour = p1Clone.Tours[i].Clone() as Tour;
272          child.Tours.Add(childTour);
273          if (!Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity)) {
274            /*success = false;
275            break;*/
276          }
277        }
278      }
279
280      if (success) {
281        //route unrouted customers
282        for (int i = 1; i <= parent1.Cities; i++) {
283          if (FindRoute(child, i) == null)
284            child.Unrouted.Add(i);
285        }
286
287        if (!RouteUnrouted(child, distMatrix, dueTime, readyTime, serviceTime, demand, capacity)) {
288          success = false;
289        }
290      }
291
292      if (success)
293        return child;
294      else {
295        if (random.NextDouble() < 0.5)
296          return parent1.Clone() as PotvinEncoding;
297        else
298          return parent2.Clone() as PotvinEncoding;   
299      }
300    }
301  }
302}
Note: See TracBrowser for help on using the repository browser.