Free cookie consent management tool by TermsFeed Policy Generator

source: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs @ 14450

Last change on this file since 14450 was 14450, checked in by abeham, 8 years ago

#2701: working on MemPR implementation

File size: 36.7 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 System.Threading;
26using HeuristicLab.Algorithms.MemPR.Interfaces;
27using HeuristicLab.Algorithms.MemPR.Util;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Encodings.PermutationEncoding;
31using HeuristicLab.Optimization;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33using HeuristicLab.PluginInfrastructure;
34using HeuristicLab.Random;
35
36namespace HeuristicLab.Algorithms.MemPR.Permutation {
37  [Item("MemPR (permutation)", "MemPR implementation for permutations.")]
38  [StorableClass]
39  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 999)]
40  public class PermutationMemPR : MemPRAlgorithm<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext> {
41    private const double UncommonBitSubsetMutationProbabilityMagicConst = 0.05;
42
43#if DEBUG
44    private const bool VALIDATE = true;
45#else
46    private const bool VALIDATE = false;
47#endif
48
49    [StorableConstructor]
50    protected PermutationMemPR(bool deserializing) : base(deserializing) { }
51    protected PermutationMemPR(PermutationMemPR original, Cloner cloner) : base(original, cloner) { }
52    public PermutationMemPR() {
53      foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<PermutationMemPRPopulationContext>>())
54        SolutionModelTrainerParameter.ValidValues.Add(trainer);
55     
56      foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<PermutationMemPRSolutionContext>>()) {
57        LocalSearchParameter.ValidValues.Add(localSearch);
58      }
59    }
60
61    public override IDeepCloneable Clone(Cloner cloner) {
62      return new PermutationMemPR(this, cloner);
63    }
64
65    protected override bool Eq(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b) {
66      return new PermutationEqualityComparer().Equals(a.Solution, b.Solution);
67    }
68
69    protected override double Dist(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b) {
70      return Dist(a.Solution, b.Solution);
71    }
72
73    private static double Dist(Encodings.PermutationEncoding.Permutation a, Encodings.PermutationEncoding.Permutation b) {
74      return 1.0 - PermutationSimilarityCalculator.CalculateSimilarity(a, b);
75    }
76
77    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> ToScope(Encodings.PermutationEncoding.Permutation code, double fitness = double.NaN) {
78      var creator = Problem.SolutionCreator as IPermutationCreator;
79      if (creator == null) throw new InvalidOperationException("Can only solve binary encoded problems with MemPR (binary)");
80      return new SingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation>(code, creator.PermutationParameter.ActualName, fitness, Problem.Evaluator.QualityParameter.ActualName) {
81        Parent = Context.Scope
82      };
83    }
84
85    protected override ISolutionSubspace<Encodings.PermutationEncoding.Permutation> CalculateSubspace(IEnumerable<Encodings.PermutationEncoding.Permutation> solutions, bool inverse = false) {
86      var subspace = new bool[Problem.Encoding.Length, Problem.Encoding.PermutationTypeParameter.Value.Value == PermutationTypes.Absolute ? 1 : Problem.Encoding.Length];
87
88      switch (Problem.Encoding.PermutationTypeParameter.Value.Value) {
89        case PermutationTypes.Absolute: {
90            if (inverse) {
91              for (var i = 0; i < subspace.GetLength(0); i++)
92                subspace[i, 0] = true;
93            }
94            var first = solutions.First();
95            foreach (var s in solutions.Skip(1)) {
96              for (var i = 0; i < s.Length; i++) {
97                if (first[i] != s[i]) subspace[i, 0] = !inverse;
98              }
99            }
100          }
101          break;
102        case PermutationTypes.RelativeDirected: {
103            if (inverse) {
104              for (var i = 0; i < subspace.GetLength(0); i++)
105                for (var j = 0; j < subspace.GetLength(1); j++)
106                  subspace[i, j] = true;
107            }
108            var first = solutions.First();
109            var placedFirst = new int[first.Length];
110            for (var i = 0; i < first.Length; i++) {
111              placedFirst[first[i]] = i;
112            }
113            foreach (var s in solutions.Skip(1)) {
114              for (var i = 0; i < s.Length; i++) {
115                if (placedFirst[s[i]] - placedFirst[s.GetCircular(i + 1)] != -1)
116                  subspace[i, 0] = !inverse;
117              }
118            }
119          }
120          break;
121        case PermutationTypes.RelativeUndirected: {
122            if (inverse) {
123              for (var i = 0; i < subspace.GetLength(0); i++)
124                for (var j = 0; j < subspace.GetLength(1); j++)
125                  subspace[i, j] = true;
126            }
127            var first = solutions.First();
128            var placedFirst = new int[first.Length];
129            for (var i = 0; i < first.Length; i++) {
130              placedFirst[first[i]] = i;
131            }
132            foreach (var s in solutions.Skip(1)) {
133              for (var i = 0; i < s.Length; i++) {
134                if (Math.Abs(placedFirst[s[i]] - placedFirst[s.GetCircular(i + 1)]) != 1)
135                  subspace[i, 0] = !inverse;
136              }
137            }
138          }
139          break;
140        default:
141          throw new ArgumentException(string.Format("Unknown permutation type {0}", Problem.Encoding.PermutationTypeParameter.Value.Value));
142      }
143      return new PermutationSolutionSubspace(subspace);
144    }
145
146    protected override void TabuWalk(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> scope, int steps, CancellationToken token, ISolutionSubspace<Encodings.PermutationEncoding.Permutation> subspace = null) {
147      var wrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(Context.Problem, scope);
148      var quality = scope.Fitness;
149      try {
150        TabuWalk(Context.Random, scope.Solution, wrapper.Evaluate, ref quality, Context.HcSteps, subspace != null ? ((PermutationSolutionSubspace)subspace).Subspace : null);
151      } finally {
152        scope.Fitness = quality;
153      }
154    }
155
156    public static void TabuWalk(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
157      switch (perm.PermutationType) {
158        case PermutationTypes.Absolute:
159          TabuWalkSwap(random, perm, eval, ref quality, maxIterations, noTouch);
160          break;
161        case PermutationTypes.RelativeDirected:
162          TabuWalkShift(random, perm, eval, ref quality, maxIterations, noTouch);
163          break;
164        case PermutationTypes.RelativeUndirected:
165          TabuWalkOpt(random, perm, eval, ref quality, maxIterations, noTouch);
166          break;
167        default: throw new ArgumentException(string.Format("Permutation type {0} is not known", perm.PermutationType));
168      }
169      if (VALIDATE && !perm.Validate()) throw new ArgumentException("TabuWalk produced invalid child");
170    }
171
172    public static void TabuWalkSwap(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
173      if (double.IsNaN(quality)) quality = eval(perm, random);
174      Encodings.PermutationEncoding.Permutation bestOfTheWalk = null;
175      double bestOfTheWalkF = double.NaN;
176      var current = (Encodings.PermutationEncoding.Permutation)perm.Clone();
177      var currentF = quality;
178      var overallImprovement = false;
179      //Console.WriteLine("Current    {0}", string.Join(", ", current));
180      var tabu = new double[current.Length, current.Length];
181      for (var i = 0; i < current.Length; i++) {
182        for (var j = i; j < current.Length; j++) {
183          tabu[i, j] = tabu[j, i] = double.MaxValue;
184        }
185        tabu[i, current[i]] = currentF;
186      }
187
188      for (var iter = 0; iter < maxIterations; iter++) {
189        var allTabu = true;
190        var bestOfTheRestF = double.NaN;
191        Swap2Move bestOfTheRest = null;
192        var improved = false;
193        //LogAlways("TabuWalk ({0}/{2}): {1}   ({3})", iter, currentF, maxIterations, string.Join(", ", current));
194        foreach (var swap in ExhaustiveSwap2MoveGenerator.Generate(current).Shuffle(random)) {
195          if (noTouch != null && (noTouch[swap.Index1, 0] || noTouch[swap.Index2, 0]))
196            continue;
197
198          var h = current[swap.Index1];
199          current[swap.Index1] = current[swap.Index2];
200          current[swap.Index2] = h;
201          var q = eval(current, random);
202          if (q < quality) {
203            overallImprovement = true;
204            quality = q;
205            for (var i = 0; i < current.Length; i++) perm[i] = current[i];
206          }
207          // check if it would not be an improvement to swap these into their positions
208          var isTabu = q >= tabu[swap.Index1, current[swap.Index1]] && q >= tabu[swap.Index2, current[swap.Index2]];
209          if (!isTabu) allTabu = false;
210          if (q < currentF && !isTabu) {
211            if (double.IsNaN(bestOfTheWalkF) || bestOfTheWalkF > q) {
212              bestOfTheWalk = (Encodings.PermutationEncoding.Permutation)current.Clone();
213              bestOfTheWalkF = q;
214            }
215
216            improved = true;
217            // perform the move
218            currentF = q;
219            // mark that to move them to their previous position requires to make an improvement
220            tabu[swap.Index1, current[swap.Index2]] = Math.Min(q, tabu[swap.Index1, current[swap.Index2]]);
221            //LogAlways("Making Tabu [{0},{1}] = {2}", swap.Index1, current[swap.Index2], tabu[swap.Index1, current[swap.Index2]]);
222            tabu[swap.Index2, current[swap.Index1]] = Math.Min(q, tabu[swap.Index2, current[swap.Index1]]);
223            //LogAlways("Making Tabu [{0},{1}] = {2}", swap.Index2, current[swap.Index1], tabu[swap.Index2, current[swap.Index1]]);
224          } else { // undo the move
225            if (!isTabu && (double.IsNaN(bestOfTheRestF) || q < bestOfTheRestF)) {
226              bestOfTheRest = swap;
227              bestOfTheRestF = q;
228            }
229            current[swap.Index2] = current[swap.Index1];
230            current[swap.Index1] = h;
231          }
232        }
233        if (!allTabu && !improved) {
234          tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]] = Math.Min(currentF, tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]]);
235          //LogAlways("Making Tabu [{0},{1}] = {2}", bestOfTheRest.Index1, current[bestOfTheRest.Index1], tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]]);
236          tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]] = Math.Min(currentF, tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]]);
237          //LogAlways("Making Tabu [{0},{1}] = {2}", bestOfTheRest.Index2, current[bestOfTheRest.Index2], tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]]);
238
239          var h = current[bestOfTheRest.Index1];
240          current[bestOfTheRest.Index1] = current[bestOfTheRest.Index2];
241          current[bestOfTheRest.Index2] = h;
242
243          currentF = bestOfTheRestF;
244        } else if (allTabu) break;
245      }
246      if (!overallImprovement && bestOfTheWalk != null) {
247        quality = bestOfTheWalkF;
248        for (var i = 0; i < current.Length; i++) perm[i] = bestOfTheWalk[i];
249      }
250    }
251
252    public static void TabuWalkShift(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
253      return;
254    }
255
256    public static void TabuWalkOpt(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
257      if (double.IsNaN(quality)) quality = eval(perm, random);
258      Encodings.PermutationEncoding.Permutation bestOfTheWalk = null;
259      double bestOfTheWalkF = double.NaN;
260      var current = (Encodings.PermutationEncoding.Permutation)perm.Clone();
261      var currentF = quality;
262      var overallImprovement = false;
263      //Console.WriteLine("Current    {0}", string.Join(", ", current));
264      var tabu = new double[current.Length, current.Length];
265      for (var i = 0; i < current.Length; i++) {
266        for (var j = i; j < current.Length; j++) {
267          tabu[i, j] = tabu[j, i] = double.MaxValue;
268        }
269        tabu[current[i], current.GetCircular(i + 1)] = currentF;
270        tabu[current.GetCircular(i + 1), current[i]] = currentF;
271      }
272
273      for (var iter = 0; iter < maxIterations; iter++) {
274        var allTabu = true;
275        var bestOfTheRestF = double.NaN;
276        InversionMove bestOfTheRest = null;
277        var improved = false;
278
279        foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(current).Shuffle(random)) {
280          var prev = opt.Index1 - 1;
281          var next = (opt.Index2 + 1) % current.Length;
282          if (prev < 0) prev += current.Length;
283          if (noTouch != null && ((noTouch[current[prev], current[opt.Index1]]) || (noTouch[current[opt.Index2], current[next]])))
284            continue;
285
286          InversionManipulator.Apply(current, opt.Index1, opt.Index2);
287
288          var q = eval(current, random);
289          if (q < quality) {
290            overallImprovement = true;
291            quality = q;
292            for (var i = 0; i < current.Length; i++) perm[i] = current[i];
293          }
294          // check if it would not be an improvement to opt these into their positions
295          var isTabu = q >= tabu[current[prev], current[opt.Index1]] && q >= tabu[current[opt.Index2], current[next]];
296          if (!isTabu) allTabu = false;
297          if (q < currentF && !isTabu) {
298            if (double.IsNaN(bestOfTheWalkF) || bestOfTheWalkF > q) {
299              bestOfTheWalk = (Encodings.PermutationEncoding.Permutation)current.Clone();
300              bestOfTheWalkF = q;
301            }
302
303            improved = true;
304            // perform the move
305            currentF = q;
306            // mark that to move them to their previous position requires to make an improvement
307            tabu[current[prev], current[opt.Index2]] = Math.Min(q, tabu[current[prev], current[opt.Index2]]);
308            tabu[current[opt.Index2], current[prev]] = Math.Min(q, tabu[current[opt.Index2], current[prev]]);
309            tabu[current[opt.Index1], current[next]] = Math.Min(q, tabu[current[opt.Index1], current[next]]);
310            tabu[current[next], current[opt.Index1]] = Math.Min(q, tabu[current[next], current[opt.Index1]]);
311          } else { // undo the move
312            if (!isTabu && (double.IsNaN(bestOfTheRestF) || q < bestOfTheRestF)) {
313              bestOfTheRest = opt;
314              bestOfTheRestF = q;
315            }
316
317            InversionManipulator.Apply(current, opt.Index1, opt.Index2);
318          }
319        }
320        if (!allTabu && !improved) {
321          var prev = bestOfTheRest.Index1 - 1;
322          var next = (bestOfTheRest.Index2 + 1) % current.Length;
323          if (prev < 0) prev += current.Length;
324
325          tabu[current[prev], current[bestOfTheRest.Index1]] = Math.Min(currentF, tabu[current[prev], current[bestOfTheRest.Index1]]);
326          tabu[current[bestOfTheRest.Index1], current[prev]] = Math.Min(currentF, tabu[current[bestOfTheRest.Index1], current[prev]]);
327          tabu[current[bestOfTheRest.Index2], current[next]] = Math.Min(currentF, tabu[current[bestOfTheRest.Index2], current[next]]);
328          tabu[current[next], current[bestOfTheRest.Index2]] = Math.Min(currentF, tabu[current[next], current[bestOfTheRest.Index2]]);
329
330          InversionManipulator.Apply(current, bestOfTheRest.Index1, bestOfTheRest.Index2);
331
332          currentF = bestOfTheRestF;
333        } else if (allTabu) break;
334      }
335      if (!overallImprovement && bestOfTheWalk != null) {
336        quality = bestOfTheWalkF;
337        for (var i = 0; i < current.Length; i++) perm[i] = bestOfTheWalk[i];
338      }
339    }
340
341    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Cross(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> p1, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> p2, CancellationToken token) {
342      Encodings.PermutationEncoding.Permutation child = null;
343
344      if (p1.Solution.PermutationType == PermutationTypes.Absolute) {
345        child = CyclicCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
346      } else if (p1.Solution.PermutationType == PermutationTypes.RelativeDirected) {
347        child = PartiallyMatchedCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
348      } else if (p1.Solution.PermutationType == PermutationTypes.RelativeUndirected) {
349        child = EdgeRecombinationCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
350      } else throw new ArgumentException(string.Format("Unknown permutation type {0}", p1.Solution.PermutationType));
351
352      if (VALIDATE && !child.Validate()) throw new ArgumentException("Cross produced invalid child");
353      return ToScope(child);
354    }
355
356    protected override void Mutate(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> offspring, CancellationToken token, ISolutionSubspace<Encodings.PermutationEncoding.Permutation> subspace = null) {
357      Mutate(Context.Random, offspring.Solution, UncommonBitSubsetMutationProbabilityMagicConst, subspace != null ? ((PermutationSolutionSubspace)subspace).Subspace : null);
358    }
359
360    public static void Mutate(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
361      switch (perm.PermutationType) {
362        case PermutationTypes.Absolute:
363          MutateSwap(random, perm, p, subspace);
364          break;
365        case PermutationTypes.RelativeDirected:
366          MutateShift(random, perm, p, subspace);
367          break;
368        case PermutationTypes.RelativeUndirected:
369          MutateOpt(random, perm, p, subspace);
370          break;
371        default: throw new ArgumentException(string.Format("Permutation type {0} is not known", perm.PermutationType));
372      }
373      if (VALIDATE && !perm.Validate()) throw new ArgumentException("Mutate produced invalid child");
374    }
375
376    public static void MutateSwap(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
377      //Log("BEFOR: {0}", string.Join(", ", lle));
378      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
379      var options = new List<int>(Enumerable.Range(0, perm.Length).Where(x => subspace == null || !subspace[x, 0]));
380      if (options.Count < 1) return;
381
382      for (var i = options.Count - 1; i > 0; i--) {
383        if (random.NextDouble() < p) {
384          var j = random.Next(0, i);
385          var h = perm[options[i]];
386          perm[options[i]] = perm[options[j]];
387          perm[options[j]] = h;
388          if (subspace != null) {
389            subspace[options[i], 0] = true;
390            subspace[options[j], 0] = true;
391          }
392        }
393      }
394    }
395
396    public static void MutateShift(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
397      //Log("BEFOR: {0}", string.Join(", ", lle));
398      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
399      foreach (var shift in ExhaustiveInsertionMoveGenerator.Generate(perm).Shuffle(random)) {
400        var prev1 = shift.Index1 - 1;
401        var next1 = (shift.Index1 + 1) % perm.Length;
402        if (prev1 < 0) prev1 += perm.Length;
403        var prev3 = shift.Index3 - 1;
404        var next3 = (shift.Index3 + 1) % perm.Length;
405        if (prev3 < 0) prev3 += perm.Length;
406        if (subspace == null || !(subspace[perm[prev1], perm[shift.Index1]] && subspace[perm[shift.Index1], perm[next1]]
407            && subspace[perm[prev3], perm[shift.Index3]] && subspace[perm[shift.Index3], perm[next3]])) {
408          if (random.NextDouble() < p) {
409            if (subspace != null) {
410              subspace[perm[prev1], perm[shift.Index1]] = true;
411              subspace[perm[shift.Index1], perm[next1]] = true;
412              subspace[perm[prev3], perm[shift.Index3]] = true;
413              subspace[perm[shift.Index3], perm[next3]] = true;
414            }
415            TranslocationManipulator.Apply(perm, shift.Index1, shift.Index2, shift.Index3);
416            return;
417          }
418        }
419      }
420    }
421
422    public static void MutateOpt(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
423      //Log("BEFOR: {0}", string.Join(", ", lle));
424      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
425      foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(perm).Shuffle(random)) {
426        var prev = opt.Index1 - 1;
427        var next = (opt.Index2 + 1) % perm.Length;
428        if (prev < 0) prev += perm.Length;
429        if (subspace == null || !(subspace[perm[prev], perm[opt.Index1]] && subspace[perm[opt.Index2], perm[next]])) {
430          if (random.NextDouble() < p) {
431            if (subspace != null) {
432              subspace[perm[prev], perm[opt.Index1]] = true;
433              subspace[perm[opt.Index1], perm[prev]] = true;
434              subspace[perm[opt.Index2], perm[next]] = true;
435              subspace[perm[next], perm[opt.Index2]] = true;
436            }
437            InversionManipulator.Apply(perm, opt.Index1, opt.Index2);
438            return;
439          }
440        }
441      }
442    }
443
444    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Relink(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b, CancellationToken token) {
445      if (double.IsNaN(a.Fitness)) Evaluate(a, token);
446      if (double.IsNaN(b.Fitness)) Evaluate(b, token);
447      if (Context.Random.NextDouble() < 0.5)
448        return IsBetter(a, b) ? Relink(a, b, token, false) : Relink(b, a, token, true);
449      else return IsBetter(a, b) ? Relink(b, a, token, true) : Relink(a, b, token, false);
450    }
451
452    protected virtual ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Relink(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> betterScope, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> worseScope, CancellationToken token, bool fromWorseToBetter) {
453      var wrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(Problem, betterScope);
454      double quality;
455      return ToScope(Relink(Context.Random, betterScope.Solution, worseScope.Solution, wrapper.Evaluate, out quality));
456    }
457
458    public static Encodings.PermutationEncoding.Permutation Relink(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
459      if (p1.PermutationType != p2.PermutationType) throw new ArgumentException(string.Format("Unequal permutation types {0} and {1}", p1.PermutationType, p2.PermutationType));
460      switch (p1.PermutationType) {
461        case PermutationTypes.Absolute:
462          return RelinkSwap(random, p1, p2, eval, out best);
463        case PermutationTypes.RelativeDirected:
464          return RelinkShift(random, p1, p2, eval, out best);
465        case PermutationTypes.RelativeUndirected:
466          return RelinkOpt(random, p1, p2, eval, out best);
467        default: throw new ArgumentException(string.Format("Unknown permutation type {0}", p1.PermutationType));
468      }
469    }
470
471    public static Encodings.PermutationEncoding.Permutation RelinkSwap(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
472      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
473
474      best = double.NaN;
475      Encodings.PermutationEncoding.Permutation bestChild = null;
476
477      var options = Enumerable.Range(0, child.Length).Where(x => child[x] != p2[x]).ToList();
478      var invChild = new int[child.Length];
479      for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
480
481      //Log(string.Join(", ", child));
482      while (options.Count > 0) {
483        int bestOption = -1;
484        var bestChange = double.NaN;
485        for (var j = 0; j < options.Count; j++) {
486          var idx = options[j];
487          if (child[idx] == p2[idx]) {
488            options.RemoveAt(j);
489            j--;
490            continue;
491          }
492          Swap(child, invChild[p2[idx]], idx);
493          var moveF = eval(child, random);
494          if (double.IsNaN(bestChange) || moveF < bestChange) {
495            bestChange = moveF;
496            bestOption = j;
497          }
498          // undo
499          Swap(child, invChild[p2[idx]], idx);
500        }
501        if (!double.IsNaN(bestChange)) {
502          var idx1 = options[bestOption];
503          var idx2 = invChild[p2[idx1]];
504          Swap(child, idx1, idx2);
505          invChild[child[idx1]] = idx1;
506          invChild[child[idx2]] = idx2;
507          //Log(string.Join(", ", child));
508          if (double.IsNaN(best) || bestChange < best) {
509            if (Dist(child, p2) > 0) {
510              best = bestChange;
511              bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
512            }
513          }
514          options.RemoveAt(bestOption);
515        }
516      }
517      //Log(string.Join(", ", p2));
518
519      if (VALIDATE && bestChild != null && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
520      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
521
522      if (bestChild == null) best = eval(child, random);
523      return bestChild ?? child;
524    }
525
526    public static Encodings.PermutationEncoding.Permutation RelinkShift(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
527      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
528
529      best = double.NaN;
530      Encodings.PermutationEncoding.Permutation bestChild = null;
531
532      var invChild = new int[child.Length];
533      for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
534
535      var bestChange = double.NaN;
536      do {
537        int bestFrom = -1, bestTo = -1;
538        bestChange = double.NaN;
539        for (var j = 0; j < child.Length; j++) {
540          var c = invChild[p2[j]];
541          var n = invChild[p2.GetCircular(j + 1)];
542          if (n - c == 1 || c == child.Length - 1 && n == 0) continue;
543
544          if (c < n) Shift(child, from: n, to: c + 1);
545          else Shift(child, from: c, to: n);
546          var moveF = eval(child, random);
547          if (double.IsNaN(bestChange) || moveF < bestChange) {
548            bestChange = moveF;
549            bestFrom = c < n ? n : c;
550            bestTo = c < n ? c + 1 : n;
551          }
552          // undo
553          if (c < n) Shift(child, from: c + 1, to: n);
554          else Shift(child, from: n, to: c);
555        }
556        if (!double.IsNaN(bestChange)) {
557          Shift(child, bestFrom, bestTo);
558          for (var i = Math.Min(bestFrom, bestTo); i < Math.Max(bestFrom, bestTo); i++) invChild[child[i]] = i;
559          if (double.IsNaN(best) || bestChange < best) {
560            best = bestChange;
561            bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
562          }
563        }
564      } while (!double.IsNaN(bestChange));
565
566      if (VALIDATE && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
567      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
568      return bestChild;
569    }
570
571    public static Encodings.PermutationEncoding.Permutation RelinkOpt(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
572      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
573
574      best = double.NaN;
575      Encodings.PermutationEncoding.Permutation bestChild = null;
576
577      var invChild = new int[child.Length];
578      var invP2 = new int[child.Length];
579      for (var i = 0; i < child.Length; i++) {
580        invChild[child[i]] = i;
581        invP2[p2[i]] = i;
582      }
583
584      var bestChange = double.NaN;
585      var moveQueue = new Queue<Tuple<int, int>>();
586      var undoStack = new Stack<Tuple<int, int>>();
587      do {
588        Queue<Tuple<int, int>> bestQueue = null;
589        bestChange = double.NaN;
590        //Log("{0}", string.Join(" ", child));
591        for (var j = 0; j < p2.Length; j++) {
592          if (IsUndirectedEdge(invChild, p2[j], p2.GetCircular(j + 1))) continue;
593
594          var a = invChild[p2[j]];
595          var b = invChild[p2.GetCircular(j + 1)];
596          if (a > b) { var h = a; a = b; b = h; }
597          var aprev = a - 1;
598          var bprev = b - 1;
599          while (IsUndirectedEdge(invP2, child.GetCircular(aprev), child.GetCircular(aprev + 1))) {
600            aprev--;
601          }
602          while (IsUndirectedEdge(invP2, child.GetCircular(bprev), child.GetCircular(bprev + 1))) {
603            bprev--;
604          }
605          var bnext = b + 1;
606          var anext = a + 1;
607          while (IsUndirectedEdge(invP2, child.GetCircular(bnext - 1), child.GetCircular(bnext))) {
608            bnext++;
609          }
610          while (IsUndirectedEdge(invP2, child.GetCircular(anext - 1), child.GetCircular(anext))) {
611            anext++;
612          }
613          aprev++; bprev++; anext--; bnext--;
614
615          if (aprev < a && bnext > b) {
616            if (aprev < 0) {
617              moveQueue.Enqueue(Tuple.Create(a + 1, bnext));
618              moveQueue.Enqueue(Tuple.Create(a + 1, a + 1 + (bnext - b)));
619            } else {
620              moveQueue.Enqueue(Tuple.Create(aprev, b - 1));
621              moveQueue.Enqueue(Tuple.Create(b - 1 - (a - aprev), b - 1));
622            }
623          } else if (aprev < a && bnext == b && bprev == b) {
624            moveQueue.Enqueue(Tuple.Create(a + 1, b));
625          } else if (aprev < a && bprev < b) {
626            moveQueue.Enqueue(Tuple.Create(a + 1, b));
627          } else if (aprev == a && anext == a && bnext > b) {
628            moveQueue.Enqueue(Tuple.Create(a, b - 1));
629          } else if (aprev == a && anext == a && bnext == b && bprev == b) {
630            moveQueue.Enqueue(Tuple.Create(a, b - 1));
631          } else if (aprev == a && anext == a && bprev < b) {
632            moveQueue.Enqueue(Tuple.Create(a + 1, b));
633          } else if (anext > a && bnext > b) {
634            moveQueue.Enqueue(Tuple.Create(a, b - 1));
635          } else if (anext > a && bnext == b && bprev == b) {
636            moveQueue.Enqueue(Tuple.Create(a, b - 1));
637          } else /*if (anext > a && bprev < b)*/ {
638            moveQueue.Enqueue(Tuple.Create(a, bprev - 1));
639            moveQueue.Enqueue(Tuple.Create(bprev, b));
640          }
641
642          while (moveQueue.Count > 0) {
643            var m = moveQueue.Dequeue();
644            Opt(child, m.Item1, m.Item2);
645            undoStack.Push(m);
646          }
647          var moveF = eval(child, random);
648          if (double.IsNaN(bestChange) || moveF < bestChange) {
649            bestChange = moveF;
650            bestQueue = new Queue<Tuple<int, int>>(undoStack.Reverse());
651          }
652          // undo
653          while (undoStack.Count > 0) {
654            var m = undoStack.Pop();
655            Opt(child, m.Item1, m.Item2);
656          }
657        }
658        if (!double.IsNaN(bestChange)) {
659          while (bestQueue.Count > 0) {
660            var m = bestQueue.Dequeue();
661            //Log("Applying opt {0} {1}", m.Item1, m.Item2);
662            //Log("{0}", string.Join(" ", child));
663            Opt(child, m.Item1, m.Item2);
664            //Log("{0}", string.Join(" ", child));
665          }
666          for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
667          if (double.IsNaN(best) || bestChange < best) {
668            best = bestChange;
669            bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
670          }
671        }
672      } while (!double.IsNaN(bestChange));
673
674      //Log("{0}", string.Join(" ", p2));
675      if (VALIDATE && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
676      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
677      return bestChild;
678    }
679
680    private static bool IsUndirectedEdge(int[] invP, int a, int b) {
681      var d = Math.Abs(invP[a] - invP[b]);
682      return d == 1 || d == invP.Length - 1;
683    }
684
685    private static void Move(Encodings.PermutationEncoding.Permutation child, int from, int to) {
686      if (child.PermutationType == PermutationTypes.Absolute) {
687        // swap
688        Swap(child, from, to);
689      } else if (child.PermutationType == PermutationTypes.RelativeDirected) {
690        // shift
691        Shift(child, from, to);
692      } else if (child.PermutationType == PermutationTypes.RelativeUndirected) {
693        // opt
694        Opt(child, from, to);
695      } else throw new ArgumentException(string.Format("Unknown permutation type {0}", child.PermutationType));
696    }
697
698    private static void Move(PermutationTypes type, bool[] arr, int from, int to) {
699      switch (type) {
700        case PermutationTypes.Absolute: {
701            /*var h = arr[from];
702            arr[from] = arr[to];
703            arr[to] = h;*/
704            arr[from] = false;
705            arr[to] = false;
706            break;
707          }
708        case PermutationTypes.RelativeDirected: {
709            var original = (bool[])arr.Clone();
710            var number = original[from];
711            int i = 0;  // index in new permutation
712            int j = 0;  // index in old permutation
713            while (i < original.Length) {
714              if (j == from) {
715                j++;
716              }
717              if (i == to) {
718                arr[i] = number;
719                i++;
720              }
721              if ((i < original.Length) && (j < original.Length)) {
722                arr[i] = original[j];
723                i++;
724                j++;
725              }
726            }
727            break;
728          }
729        case PermutationTypes.RelativeUndirected: {
730            if (from > to) {
731              var hu = from;
732              from = to;
733              to = hu;
734            }
735            for (int i = 0; i <= (to - from) / 2; i++) {  // invert permutation between breakpoints
736              var temp = arr[from + i];
737              arr[from + i] = arr[to - i];
738              arr[to - i] = temp;
739            }
740            break;
741          }
742        default:
743          throw new ArgumentException(string.Format("Unknown permutation type {0}", type));
744      }
745    }
746
747    private static void Swap(Encodings.PermutationEncoding.Permutation child, int from, int to) {
748      Swap2Manipulator.Apply(child, from, to);
749    }
750
751    private static void Shift(Encodings.PermutationEncoding.Permutation child, int from, int to) {
752      TranslocationManipulator.Apply(child, from, from, to);
753    }
754
755    private static void Opt(Encodings.PermutationEncoding.Permutation child, int from, int to) {
756      if (from > to) {
757        var h = from;
758        from = to;
759        to = h;
760      }
761      InversionManipulator.Apply(child, from, to);
762    }
763  }
764}
Note: See TracBrowser for help on using the repository browser.