Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TSPData.cs @ 17241

Last change on this file since 17241 was 17241, checked in by abeham, 5 years ago

#2521: worked on refactoring TSP

File size: 10.4 KB
Line 
1using System;
2using System.ComponentModel;
3using System.Drawing;
4using HEAL.Attic;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using HeuristicLab.Encodings.PermutationEncoding;
9
10namespace HeuristicLab.Problems.TravelingSalesman {
11  [StorableType("1a9bf60c-b6a6-4c95-8e99-5a2dec0ee892")]
12  public interface ITSPData : IItem {
13    double GetDistance(int fromCity, int toCity);
14    ITSPSolution GetSolution(Permutation tspTour, double tourLength);
15  }
16
17  [StorableType("f08a63d9-0b83-4944-9251-42925baeb872")]
18  public interface ITSPSolution : IItem {
19    DoubleMatrix Coordinates { get; }
20    Permutation Tour { get; }
21    DoubleValue TourLength { get; }
22  }
23
24  [Item("Matrix-based TSP Data", "TSP that is representd by a distance matrix.")]
25  [StorableType("4df58a35-679d-4414-b815-9450ae100823")]
26  public class MatrixTSPData : Item, ITSPData {
27    [Storable]
28    private double[,] Matrix { get; set; }
29
30    [Storable]
31    public DoubleMatrix DisplayCoordinates { get; set; }
32
33    [StorableConstructor]
34    protected MatrixTSPData(StorableConstructorFlag _) : base(_) { }
35    protected MatrixTSPData(MatrixTSPData original, Cloner cloner) : base(original, cloner) {
36      Matrix = original.Matrix;
37      DisplayCoordinates = cloner.Clone(original.DisplayCoordinates);
38    }
39    public MatrixTSPData() {
40      Matrix = new double[0, 0];
41      DisplayCoordinates = null;
42    }
43    public MatrixTSPData(double[,] matrix, double[,] coordinates = null) {
44      Matrix = (double[,])matrix.Clone();
45      if (coordinates != null) DisplayCoordinates = new DoubleMatrix(coordinates);
46      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
47        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
48      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
49        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
50    }
51
52    public ITSPSolution GetSolution(Permutation tour, double tourLength) {
53      return new PathTSPTour(DisplayCoordinates, tour, new DoubleValue(tourLength));
54    }
55
56    public override IDeepCloneable Clone(Cloner cloner) {
57      return new MatrixTSPData(this, cloner);
58    }
59
60    public void SetMatrix(double[,] matrix, double[,] coordinates = null) {
61      Matrix = (double[,])matrix.Clone();
62      if (coordinates == null) DisplayCoordinates = null;
63      else DisplayCoordinates = new DoubleMatrix(coordinates);
64      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
65        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
66      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
67        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
68    }
69
70    public void SetMatrix(ValueTypeMatrix<double> matrix, DoubleMatrix coordinates = null) {
71      Matrix = matrix.CloneAsMatrix();
72      DisplayCoordinates = (DoubleMatrix)coordinates?.Clone();
73      if (DisplayCoordinates != null && DisplayCoordinates.Columns != 2)
74        throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
75      if (DisplayCoordinates != null && DisplayCoordinates.Rows != Matrix.GetLength(0))
76        throw new ArgumentException("Unequal number of rows in " + nameof(matrix) + " and " + nameof(coordinates) + ".");
77    }
78
79    public double GetDistance(int fromCity, int toCity) => Matrix[fromCity, toCity];
80  }
81
82  [Item("Coordinates-based TSP Data", "TSP that is represented by coordinates of locations.")]
83  [StorableType("3955d07a-d43c-4a01-9505-d2effb1ea865")]
84  public abstract class CoordinatesTSPData : Item, ITSPData {
85    [Storable]
86    public DoubleMatrix Coordinates { get; set; }
87
88    [StorableConstructor]
89    protected CoordinatesTSPData(StorableConstructorFlag _) : base(_) { }
90    protected CoordinatesTSPData(CoordinatesTSPData original, Cloner cloner) : base(original, cloner) {
91      Coordinates = cloner.Clone(original.Coordinates);
92    }
93    protected CoordinatesTSPData() : base() {
94      Coordinates = new DoubleMatrix();
95    }
96    protected CoordinatesTSPData(double[,] coordinates) : base() {
97      if (coordinates == null) throw new ArgumentNullException(nameof(coordinates));
98      if (coordinates.GetLength(1) != 2) throw new ArgumentException("Argument must have exactly two columns.", nameof(coordinates));
99      Coordinates = new DoubleMatrix(coordinates);
100    }
101
102    public double GetDistance(int fromCity, int toCity) {
103      return GetDistance(Coordinates[fromCity, 0], Coordinates[fromCity, 1],
104        Coordinates[toCity, 0], Coordinates[toCity, 1]);
105    }
106
107    public abstract double GetDistance(double fromX, double fromY, double toX, double toY);
108
109    public ITSPSolution GetSolution(Permutation tour, double tourLength) {
110      return new PathTSPTour(Coordinates, tour, new DoubleValue(tourLength));
111    }
112  }
113
114  [Item("Euclidean TSP Data", "TSP that is represented by coordinates in an Euclidean plane.")]
115  [StorableType("4bf58348-cd98-46c5-a4c0-55f486ca88b4")]
116  public sealed class EuclideanTSPData : CoordinatesTSPData {
117    public enum RoundingMode { None, Midpoint, Ceiling }
118
119    [Storable]
120    public RoundingMode Rounding { get; set; }
121
122    [StorableConstructor]
123    private EuclideanTSPData(StorableConstructorFlag _) : base(_) { }
124    private EuclideanTSPData(EuclideanTSPData original, Cloner cloner) : base(original, cloner) {
125      Rounding = original.Rounding;
126    }
127    public EuclideanTSPData() : base() { }
128    public EuclideanTSPData(double[,] coordinates) : base(coordinates) { }
129
130    public override IDeepCloneable Clone(Cloner cloner) {
131      return new EuclideanTSPData(this, cloner);
132    }
133
134    public override double GetDistance(double fromX, double fromY, double toX, double toY) {
135      var dist = Math.Sqrt((fromX - toX) * (fromX - toX) + (fromY - toY) * (fromY - toY));
136      switch (Rounding) {
137        case RoundingMode.None: return dist;
138        case RoundingMode.Midpoint: return Math.Round(dist);
139        case RoundingMode.Ceiling: return Math.Ceiling(dist);
140        default: throw new InvalidOperationException("Unknown rounding mode " + Rounding);
141      }
142    }
143  }
144
145  [Item("Geo TSP Data", "TSP that is represented by geo coordinates.")]
146  [StorableType("4bf58348-cd98-46c5-a4c0-55f486ca88b4")]
147  public sealed class GeoTSPData : CoordinatesTSPData {
148    public const double PI = 3.141592;
149    public const double RADIUS = 6378.388;
150
151    [StorableConstructor]
152    private GeoTSPData(StorableConstructorFlag _) : base(_) { }
153    private GeoTSPData(GeoTSPData original, Cloner cloner) : base(original, cloner) { }
154    public GeoTSPData() : base() { }
155    public GeoTSPData(double[,] coordinates) : base(coordinates) { }
156
157    public override IDeepCloneable Clone(Cloner cloner) {
158      return new GeoTSPData(this, cloner);
159    }
160
161    public override double GetDistance(double fromX, double fromY, double toX, double toY) {
162      double latitude1, longitude1, latitude2, longitude2;
163      double q1, q2, q3;
164      double length;
165
166      latitude1 = ConvertToRadian(fromX);
167      longitude1 = ConvertToRadian(fromY);
168      latitude2 = ConvertToRadian(toX);
169      longitude2 = ConvertToRadian(toY);
170
171      q1 = Math.Cos(longitude1 - longitude2);
172      q2 = Math.Cos(latitude1 - latitude2);
173      q3 = Math.Cos(latitude1 + latitude2);
174
175      length = (int)(RADIUS * Math.Acos(0.5 * ((1.0 + q1) * q2 - (1.0 - q1) * q3)) + 1.0);
176      return (length);
177    }
178
179    private double ConvertToRadian(double x) {
180      return PI * (Math.Truncate(x) + 5.0 * (x - Math.Truncate(x)) / 3.0) / 180.0;
181    }
182  }
183  /// <summary>
184  /// Represents a tour of a Traveling Salesman Problem given in path representation which can be visualized in the GUI.
185  /// </summary>
186  [Item("PathTSPTour", "Represents a tour of a Traveling Salesman Problem given in path representation which can be visualized in the GUI.")]
187  [StorableType("2CAE7C49-751B-4802-9025-62E2268E47AE")]
188  public sealed class PathTSPTour : Item, ITSPSolution, INotifyPropertyChanged {
189    public static new Image StaticItemImage {
190      get { return HeuristicLab.Common.Resources.VSImageLibrary.Image; }
191    }
192
193    [Storable]
194    private DoubleMatrix coordinates;
195    public DoubleMatrix Coordinates {
196      get { return coordinates; }
197      set {
198        if (coordinates == value) return;
199        coordinates = value;
200        OnPropertyChanged(nameof(Coordinates));
201      }
202    }
203
204    [Storable(Name = "tour", OldName = "permutation")]
205    private Permutation tour;
206    public Permutation Tour {
207      get { return tour; }
208      set {
209        if (tour == value) return;
210        tour = value;
211        OnPropertyChanged(nameof(Tour));
212      }
213    }
214    [Storable(Name = "tourLength", OldName = "quality")]
215    private DoubleValue tourLength;
216    public DoubleValue TourLength {
217      get { return tourLength; }
218      set {
219        if (tourLength == value) return;
220        tourLength = value;
221        OnPropertyChanged(nameof(TourLength));
222      }
223    }
224
225    [StorableConstructor]
226    private PathTSPTour(StorableConstructorFlag _) : base(_) { }
227    private PathTSPTour(PathTSPTour original, Cloner cloner)
228      : base(original, cloner) {
229      this.coordinates = cloner.Clone(original.coordinates);
230      this.tour = cloner.Clone(original.tour);
231      this.tourLength = cloner.Clone(original.tourLength);
232    }
233    public PathTSPTour() : base() { }
234    public PathTSPTour(DoubleMatrix coordinates)
235      : base() {
236      this.coordinates = coordinates;
237    }
238    public PathTSPTour(DoubleMatrix coordinates, Permutation permutation)
239      : base() {
240      this.coordinates = coordinates;
241      this.tour = permutation;
242    }
243    public PathTSPTour(DoubleMatrix coordinates, Permutation permutation, DoubleValue quality)
244      : base() {
245      this.coordinates = coordinates;
246      this.tour = permutation;
247      this.tourLength = quality;
248    }
249
250    public override IDeepCloneable Clone(Cloner cloner) {
251      return new PathTSPTour(this, cloner);
252    }
253
254    public event PropertyChangedEventHandler PropertyChanged;
255    private void OnPropertyChanged(string property) {
256      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
257    }
258  }
259}
Note: See TracBrowser for help on using the repository browser.