Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 17612 was 17612, checked in by mkommend, 4 years ago

#2521: Added first version of problem results.

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