Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSP.cs @ 17251

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

#2521: finished refactoring TSP

File size: 10.8 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;
23using System.Collections.Generic;
24using System.Linq;
25using HEAL.Attic;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Encodings.PermutationEncoding;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.PluginInfrastructure;
33using HeuristicLab.Problems.Instances;
34
35namespace HeuristicLab.Problems.TravelingSalesman {
36  [Item("Traveling Salesman Problem (TSP)", "Represents a symmetric Traveling Salesman Problem.")]
37  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 100)]
38  [StorableType("8415476a-69de-45ad-95be-298ed7c97e84")]
39  public class TSP : PermutationProblem, IProblemInstanceConsumer<TSPData>, IProblemInstanceExporter<TSPData> {
40    /// <summary>
41    /// This limit governs when a distance matrix is used. For all problems smaller than that, the distance matrix is
42    /// computed. This greatly speeds up computation time.
43    /// </summary>
44    public static int DistanceMatrixSizeLimit { get; set; } = 1000;
45
46    public override bool Maximization => false;
47
48    [Storable] public IValueParameter<ITSPData> TSPDataParameter { get; private set; }
49    [Storable] public IValueParameter<ITSPSolution> BestKnownSolutionParameter { get; private set; }
50
51    public ITSPData TSPData {
52      get { return TSPDataParameter.Value; }
53      set { TSPDataParameter.Value = value; }
54    }
55    public ITSPSolution BestKnownSolution {
56      get { return BestKnownSolutionParameter.Value; }
57      set { BestKnownSolutionParameter.Value = value; }
58    }
59
60    [StorableConstructor]
61    protected TSP(StorableConstructorFlag _) : base(_) { }
62
63    protected TSP(TSP original, Cloner cloner)
64      : base(original, cloner) {
65      TSPDataParameter = cloner.Clone(original.TSPDataParameter);
66      BestKnownSolutionParameter = cloner.Clone(original.BestKnownSolutionParameter);
67    }
68
69    public TSP() : base(new PermutationEncoding("Tour", 16, PermutationTypes.RelativeUndirected)) {
70      Parameters.Add(TSPDataParameter = new ValueParameter<ITSPData>("TSPData", "The main parameters of the TSP."));
71      Parameters.Add(BestKnownSolutionParameter = new OptionalValueParameter<ITSPSolution>("BestKnownSolution", "The best known solution."));
72
73      TSPData = new EuclideanTSPData();
74
75      InitializeOperators();
76    }
77
78    public override IDeepCloneable Clone(Cloner cloner) {
79      return new TSP(this, cloner);
80    }
81
82    public override double Evaluate(Permutation tour, IRandom random) {
83      return Evaluate(tour);
84    }
85
86    public double Evaluate(Permutation tour) {
87      var tourLength = 0.0;
88      for (var i = 0; i < tour.Length - 1; i++) {
89        tourLength += TSPData.GetDistance(tour[i], tour[i + 1]);
90      }
91      tourLength += TSPData.GetDistance(tour[tour.Length - 1], tour[0]);
92      return tourLength;
93    }
94
95    public override void Analyze(Permutation[] solutions, double[] qualities, ResultCollection results, IRandom random) {
96      base.Analyze(solutions, qualities, results, random);
97      int i = -1;
98      if (!Maximization)
99        i = qualities.Select((x, index) => new { index, Fitness = x }).OrderBy(x => x.Fitness).First().index;
100      else i = qualities.Select((x, index) => new { index, Fitness = x }).OrderByDescending(x => x.Fitness).First().index;
101      var solution = TSPData.GetSolution(solutions[i], qualities[i]);
102
103      if (double.IsNaN(BestKnownQuality) ||
104          Maximization && qualities[i] > BestKnownQuality ||
105          !Maximization && qualities[i] < BestKnownQuality) {
106        BestKnownQualityParameter.Value = new DoubleValue(qualities[i]);
107        BestKnownSolutionParameter.Value = solution;
108      }
109      results.AddOrUpdateResult("Best TSP Solution", solution);
110    }
111
112    public override IEnumerable<Permutation> GetNeighbors(Permutation solution, IRandom random) {
113      foreach (var move in ExhaustiveInversionMoveGenerator.Generate(solution)) {
114        var clone = (Permutation)solution.Clone();
115        InversionManipulator.Apply(clone, move.Index1, move.Index2);
116        yield return clone;
117      }
118    }
119
120    public void Load(TSPData data) {
121      if (data.Coordinates == null && data.Distances == null)
122        throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
123      if (data.Dimension > DistanceMatrixSizeLimit && (data.DistanceMeasure == DistanceMeasure.Att
124        || data.DistanceMeasure == DistanceMeasure.Manhattan
125        || data.DistanceMeasure == DistanceMeasure.Maximum))
126        throw new System.IO.InvalidDataException("The given instance uses an unsupported distance measure and is too large for using a distance matrix.");
127      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
128        throw new System.IO.InvalidDataException("The coordinates of the given instance are not in the right format, there need to be one row for each customer and two columns for the x and y coordinates.");
129
130      Encoding.Length = data.Dimension;
131      Name = data.Name;
132      Description = data.Description;
133
134      if (data.DistanceMeasure == DistanceMeasure.Att
135        || data.DistanceMeasure == DistanceMeasure.Manhattan
136        || data.DistanceMeasure == DistanceMeasure.Maximum
137        || data.Dimension <= DistanceMatrixSizeLimit) {
138        TSPData = new MatrixTSPData(data.Name, data.GetDistanceMatrix(), data.Coordinates) { Description = data.Description };
139      } else if (data.DistanceMeasure == DistanceMeasure.Direct && data.Distances != null) {
140        TSPData = new MatrixTSPData(data.Name, data.Distances, data.Coordinates) { Description = data.Description };
141      } else {
142        switch (data.DistanceMeasure) {
143          case DistanceMeasure.Euclidean:
144            TSPData = new EuclideanTSPData(data.Name, data.Coordinates, EuclideanTSPData.DistanceRounding.None) { Description = data.Description };
145            break;
146          case DistanceMeasure.RoundedEuclidean:
147            TSPData = new EuclideanTSPData(data.Name, data.Coordinates, EuclideanTSPData.DistanceRounding.Midpoint) { Description = data.Description };
148            break;
149          case DistanceMeasure.UpperEuclidean:
150            TSPData = new EuclideanTSPData(data.Name, data.Coordinates, EuclideanTSPData.DistanceRounding.Ceiling) { Description = data.Description };
151            break;
152          case DistanceMeasure.Geo:
153            TSPData = new GeoTSPData(data.Name, data.Coordinates) { Description = data.Description };
154            break;
155          default:
156            throw new System.IO.InvalidDataException("An unknown distance measure is given in the instance!");
157        }
158      }
159      BestKnownSolution = null;
160      BestKnownQuality = double.NaN;
161
162      if (data.BestKnownTour != null) {
163        try {
164          var tour = new Permutation(PermutationTypes.RelativeUndirected, data.BestKnownTour);
165          var tourLength = Evaluate(tour);
166          BestKnownSolution = new TSPSolution(data.Coordinates != null ? new DoubleMatrix(data.Coordinates) : null, tour, new DoubleValue(tourLength));
167          BestKnownQuality = tourLength;
168        } catch (InvalidOperationException) {
169          if (data.BestKnownQuality.HasValue)
170            BestKnownQuality = data.BestKnownQuality.Value;
171        }
172      } else if (data.BestKnownQuality.HasValue) {
173        BestKnownQuality = data.BestKnownQuality.Value;
174      }
175      OnReset();
176    }
177
178    public TSPData Export() {
179      var instance = TSPData.Export();
180      if (!double.IsNaN(BestKnownQuality))
181        instance.BestKnownQuality = BestKnownQuality;
182      if (BestKnownSolution?.Tour != null)
183        instance.BestKnownTour = BestKnownSolution.Tour.ToArray();
184      return instance;
185    }
186
187    protected override void OnEncodingChanged() {
188      base.OnEncodingChanged();
189      ParameterizeOperators();
190    }
191
192    protected override void OnEvaluatorChanged() {
193      base.OnEvaluatorChanged();
194      ParameterizeOperators();
195    }
196
197    private void InitializeOperators() {
198      Operators.Add(new TSPImprovementOperator());
199      Operators.Add(new TSPMultipleGuidesPathRelinker());
200      Operators.Add(new TSPPathRelinker());
201      Operators.Add(new TSPSimultaneousPathRelinker());
202
203      Operators.Add(new TSPAlleleFrequencyAnalyzer());
204      foreach (var op in ApplicationManager.Manager.GetInstances<ITSPMoveEvaluator>()) {
205        Encoding.ConfigureOperator(op);
206        Operators.Add(op);
207      }
208      ParameterizeOperators();
209    }
210
211    private void ParameterizeOperators() {
212      foreach (var op in Operators.OfType<TSPAlleleFrequencyAnalyzer>()) {
213        op.MaximizationParameter.ActualName = MaximizationParameter.Name;
214        op.TSPDataParameter.ActualName = TSPDataParameter.Name;
215        op.SolutionParameter.ActualName = Encoding.Name;
216        op.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
217        op.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
218        op.ResultsParameter.ActualName = "Results";
219      }
220      foreach (var op in Operators.OfType<ITSPMoveEvaluator>()) {
221        op.TSPDataParameter.ActualName = TSPDataParameter.Name;
222        op.TSPDataParameter.Hidden = true;
223        op.TourLengthParameter.ActualName = Evaluator.QualityParameter.ActualName;
224        op.TourLengthParameter.Hidden = true;
225        op.TSPTourParameter.ActualName = Encoding.Name;
226        op.TSPTourParameter.Hidden = true;
227      }
228      foreach (var op in Operators.OfType<ISingleObjectiveImprovementOperator>()) {
229        op.SolutionParameter.ActualName = Encoding.Name;
230        op.SolutionParameter.Hidden = true;
231      }
232      foreach (ISingleObjectivePathRelinker op in Operators.OfType<ISingleObjectivePathRelinker>()) {
233        op.ParentsParameter.ActualName = Encoding.Name;
234        op.ParentsParameter.Hidden = true;
235      }
236      foreach (ISolutionSimilarityCalculator op in Operators.OfType<ISolutionSimilarityCalculator>()) {
237        op.SolutionVariableName = Encoding.Name;
238        op.QualityVariableName = Evaluator.QualityParameter.ActualName;
239      }
240    }
241  }
242}
Note: See TracBrowser for help on using the repository browser.