Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.PTSP/3.3/PTSP.cs @ 18242

Last change on this file since 18242 was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

File size: 12.0 KB
RevLine 
[12166]1#region License Information
2/* HeuristicLab
[17181]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[12166]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
[13412]22using System;
[13470]23using System.Linq;
[15217]24using HeuristicLab.Analysis;
[13202]25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.PermutationEncoding;
[12166]29using HeuristicLab.Optimization;
[15217]30using HeuristicLab.Optimization.Operators;
[13202]31using HeuristicLab.Parameters;
[17097]32using HEAL.Attic;
[12166]33using HeuristicLab.Problems.Instances;
34
35namespace HeuristicLab.Problems.PTSP {
[13412]36  [Item("Probabilistic Traveling Salesman Problem (PTSP)", "Represents a Probabilistic Traveling Salesman Problem.")]
[17097]37  [StorableType("4CB8ACF3-C3D4-4CC6-BB1F-986BDE16B30A")]
[13412]38  public abstract class ProbabilisticTravelingSalesmanProblem : SingleObjectiveBasicProblem<PermutationEncoding>,
[12306]39  IProblemInstanceConsumer<PTSPData> {
[13470]40    protected bool SuppressEvents { get; set; }
41
[12228]42    private static readonly int DistanceMatrixSizeLimit = 1000;
43
[12183]44    #region Parameter Properties
45    public OptionalValueParameter<DoubleMatrix> CoordinatesParameter {
46      get { return (OptionalValueParameter<DoubleMatrix>)Parameters["Coordinates"]; }
47    }
[13412]48    public OptionalValueParameter<DistanceCalculator> DistanceCalculatorParameter {
49      get { return (OptionalValueParameter<DistanceCalculator>)Parameters["DistanceCalculator"]; }
50    }
[12183]51    public OptionalValueParameter<DistanceMatrix> DistanceMatrixParameter {
52      get { return (OptionalValueParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
53    }
[13412]54    public IFixedValueParameter<BoolValue> UseDistanceMatrixParameter {
55      get { return (IFixedValueParameter<BoolValue>)Parameters["UseDistanceMatrix"]; }
[12183]56    }
57    public OptionalValueParameter<Permutation> BestKnownSolutionParameter {
58      get { return (OptionalValueParameter<Permutation>)Parameters["BestKnownSolution"]; }
59    }
[13412]60    public IValueParameter<DoubleArray> ProbabilitiesParameter {
61      get { return (IValueParameter<DoubleArray>)Parameters["Probabilities"]; }
[12183]62    }
63    #endregion
64
65    #region Properties
66    public DoubleMatrix Coordinates {
67      get { return CoordinatesParameter.Value; }
68      set { CoordinatesParameter.Value = value; }
69    }
[13412]70    public DistanceCalculator DistanceCalculator {
71      get { return DistanceCalculatorParameter.Value; }
72      set { DistanceCalculatorParameter.Value = value; }
73    }
[12183]74    public DistanceMatrix DistanceMatrix {
75      get { return DistanceMatrixParameter.Value; }
76      set { DistanceMatrixParameter.Value = value; }
77    }
[13412]78    public bool UseDistanceMatrix {
79      get { return UseDistanceMatrixParameter.Value.Value; }
80      set { UseDistanceMatrixParameter.Value.Value = value; }
[12183]81    }
82    public Permutation BestKnownSolution {
83      get { return BestKnownSolutionParameter.Value; }
84      set { BestKnownSolutionParameter.Value = value; }
85    }
[13412]86    public DoubleArray Probabilities {
87      get { return ProbabilitiesParameter.Value; }
88      set { ProbabilitiesParameter.Value = value; }
[12183]89    }
[13202]90
[12183]91    #endregion
[12166]92
93    public override bool Maximization {
94      get { return false; }
95    }
96
97    [StorableConstructor]
[17097]98    protected ProbabilisticTravelingSalesmanProblem(StorableConstructorFlag _) : base(_) { }
[13470]99    protected ProbabilisticTravelingSalesmanProblem(ProbabilisticTravelingSalesmanProblem original, Cloner cloner)
100      : base(original, cloner) {
101      RegisterEventHandlers();
102    }
[13412]103    protected ProbabilisticTravelingSalesmanProblem() {
[12183]104      Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the cities."));
[13412]105      Parameters.Add(new OptionalValueParameter<DistanceCalculator>("DistanceCalculator", "Calculates the distance between two rows in the coordinates matrix."));
[12183]106      Parameters.Add(new OptionalValueParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
[13412]107      Parameters.Add(new FixedValueParameter<BoolValue>("UseDistanceMatrix", "True if the coordinates based evaluators should calculate the distance matrix from the coordinates and use it for evaluation similar to the distance matrix evaluator, otherwise false.", new BoolValue(true)));
[12183]108      Parameters.Add(new OptionalValueParameter<Permutation>("BestKnownSolution", "The best known solution of this TSP instance."));
[13412]109      Parameters.Add(new ValueParameter<DoubleArray>("Probabilities", "This list describes for each city the probability of appearing in a realized instance."));
[12228]110
[13470]111      var coordinates = new DoubleMatrix(new double[,] {
[12228]112        { 100, 100 }, { 100, 200 }, { 100, 300 }, { 100, 400 },
113        { 200, 100 }, { 200, 200 }, { 200, 300 }, { 200, 400 },
114        { 300, 100 }, { 300, 200 }, { 300, 300 }, { 300, 400 },
115        { 400, 100 }, { 400, 200 }, { 400, 300 }, { 400, 400 }
116      });
[13470]117      Coordinates = coordinates;
118      Encoding.Length = coordinates.Rows;
119      DistanceCalculator = new EuclideanDistance();
120      DistanceMatrix = new DistanceMatrix(CalculateDistances());
121      Probabilities = new DoubleArray(Enumerable.Range(0, coordinates.Rows).Select(x => 0.5).ToArray());
[12228]122
[15217]123      InitializeOperators();
124      Parameterize();
[13470]125      RegisterEventHandlers();
[13412]126    }
[13202]127
[15217]128    private void InitializeOperators() {
129      Operators.Add(new HammingSimilarityCalculator());
130      Operators.Add(new QualitySimilarityCalculator());
131      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
132    }
133
[13470]134    [StorableHook(HookType.AfterDeserialization)]
135    private void AfterDeserialization() {
136      RegisterEventHandlers();
137    }
138
[15217]139    protected override void OnEncodingChanged() {
140      base.OnEncodingChanged();
141      Encoding.Length = Coordinates.Rows;
142      Parameterize();
143    }
144
[13470]145    private void RegisterEventHandlers() {
146      CoordinatesParameter.ValueChanged += CoordinatesParameterOnValueChanged;
147      if (Coordinates != null) {
148        Coordinates.RowsChanged += CoordinatesOnChanged;
149        Coordinates.ItemChanged += CoordinatesOnChanged;
150      }
151      UseDistanceMatrixParameter.Value.ValueChanged += UseDistanceMatrixValueChanged;
152      DistanceCalculatorParameter.ValueChanged += DistanceCalculatorParameterOnValueChanged;
153    }
154
155    private void CoordinatesParameterOnValueChanged(object sender, EventArgs eventArgs) {
156      if (Coordinates != null) {
157        Coordinates.RowsChanged += CoordinatesOnChanged;
158        Coordinates.ItemChanged += CoordinatesOnChanged;
159      }
160      if (SuppressEvents) return;
161      UpdateInstance();
162    }
163
164    private void CoordinatesOnChanged(object sender, EventArgs eventArgs) {
165      if (SuppressEvents) return;
166      UpdateInstance();
167    }
168
169    private void UseDistanceMatrixValueChanged(object sender, EventArgs eventArgs) {
170      if (SuppressEvents) return;
171      UpdateInstance();
172    }
173
174    private void DistanceCalculatorParameterOnValueChanged(object sender, EventArgs eventArgs) {
175      if (SuppressEvents) return;
176      UpdateInstance();
177    }
178
[13412]179    public override double Evaluate(Individual individual, IRandom random) {
180      return Evaluate(individual.Permutation(), random);
[12166]181    }
182
[13412]183    public abstract double Evaluate(Permutation tour, IRandom random);
184
[13470]185    public double[,] CalculateDistances() {
186      var coords = Coordinates;
187      var len = coords.Rows;
188      var dist = DistanceCalculator;
189
190      var matrix = new double[len, len];
191      for (var i = 0; i < len - 1; i++)
192        for (var j = i + 1; j < len; j++)
193          matrix[i, j] = matrix[j, i] = dist.Calculate(i, j, coords);
194
195      return matrix;
196    }
197
[12306]198    public virtual void Load(PTSPData data) {
[13470]199      try {
200        SuppressEvents = true;
201        if (data.Coordinates == null && data.Distances == null)
202          throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
203        if (data.Dimension > DistanceMatrixSizeLimit && (data.Coordinates == null || data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
204          throw new System.IO.InvalidDataException("The given instance is too large for using a distance matrix and there is a problem with the coordinates.");
205        if (data.Coordinates != null && (data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
206          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 respectively.");
[12228]207
[13470]208        switch (data.DistanceMeasure) {
209          case DistanceMeasure.Direct:
210            DistanceCalculator = null;
211            if (data.Dimension > DistanceMatrixSizeLimit && Coordinates != null) {
212              DistanceCalculator = new EuclideanDistance();
213              UseDistanceMatrix = false;
214            } else UseDistanceMatrix = true;
215            break;
216          case DistanceMeasure.Att: DistanceCalculator = new AttDistance(); break;
217          case DistanceMeasure.Euclidean: DistanceCalculator = new EuclideanDistance(); break;
218          case DistanceMeasure.Geo: DistanceCalculator = new GeoDistance(); break;
219          case DistanceMeasure.Manhattan: DistanceCalculator = new ManhattanDistance(); break;
220          case DistanceMeasure.Maximum: DistanceCalculator = new MaximumDistance(); break;
221          case DistanceMeasure.RoundedEuclidean: DistanceCalculator = new RoundedEuclideanDistance(); break;
222          case DistanceMeasure.UpperEuclidean: DistanceCalculator = new UpperEuclideanDistance(); break;
223          default: throw new ArgumentException("Distance measure is unknown");
224        }
[13412]225
[13470]226        Name = data.Name;
227        Description = data.Description;
[12228]228
[13470]229        Probabilities = new DoubleArray(data.Probabilities);
230        BestKnownSolution = data.BestKnownTour != null ? new Permutation(PermutationTypes.RelativeUndirected, data.BestKnownTour) : null;
231        Coordinates = data.Coordinates != null && data.Coordinates.GetLength(0) > 0 ? new DoubleMatrix(data.Coordinates) : null;
232        DistanceMatrix = data.Dimension <= DistanceMatrixSizeLimit && UseDistanceMatrix ? new DistanceMatrix(data.GetDistanceMatrix()) : null;
[12228]233
[13470]234        Encoding.Length = data.Dimension;
235      } finally { SuppressEvents = false; }
236      OnReset();
237    }
[12228]238
[13470]239    private void UpdateInstance() {
240      var len = GetProblemDimension();
241      if (Coordinates != null && Coordinates.Rows <= DistanceMatrixSizeLimit
242        && DistanceCalculator != null && UseDistanceMatrix)
243        DistanceMatrix = new DistanceMatrix(CalculateDistances());
244      if (!UseDistanceMatrix) DistanceMatrix = null;
245      Encoding.Length = len;
246
[12228]247      OnReset();
[12166]248    }
[13470]249
250    private int GetProblemDimension() {
251      if (Coordinates == null && DistanceMatrix == null) throw new InvalidOperationException("Both coordinates and distance matrix are null, please specify at least one of them.");
252      return Coordinates != null ? Coordinates.Rows : DistanceMatrix.Rows;
253    }
[15217]254
255    private void Parameterize() {
256      foreach (var similarityCalculator in Operators.OfType<ISolutionSimilarityCalculator>()) {
257        similarityCalculator.SolutionVariableName = Encoding.SolutionCreator.PermutationParameter.ActualName;
258        similarityCalculator.QualityVariableName = Evaluator.QualityParameter.ActualName;
259      }
260    }
[12166]261  }
262}
Note: See TracBrowser for help on using the repository browser.