Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
12/15/15 16:38:08 (9 years ago)
Author:
abeham
Message:

#2221:

  • implemented review comments
    • hid rng as private class, implemented djb2 hash function (hash function implementation may also change)
    • added missing probabilities
    • base class for instance providers
    • prebuild event events
    • build platforms
    • unit test will be removed on trunk integration
    • corrected assembly file version
    • distance calculator parameter was not hidden, can be changed by user, updates distance matrix
    • fixed performance problems (ouch!) also for estimated ptsp (inlined GetDistance method)
  • added moves (full evaluation) for analytical tsp
  • added local improvement operators for analytical ptsp
  • added recalculation of distance matrix when parameters change
  • still lots of other changes
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/PTSP/HeuristicLab.Problems.PTSP/3.3/PTSP.cs

    r13412 r13470  
    2121
    2222using System;
     23using System.Linq;
    2324using HeuristicLab.Common;
    2425using HeuristicLab.Core;
     
    3536  public abstract class ProbabilisticTravelingSalesmanProblem : SingleObjectiveBasicProblem<PermutationEncoding>,
    3637  IProblemInstanceConsumer<PTSPData> {
     38    protected bool SuppressEvents { get; set; }
     39
    3740    private static readonly int DistanceMatrixSizeLimit = 1000;
    3841
     
    9295    [StorableConstructor]
    9396    protected ProbabilisticTravelingSalesmanProblem(bool deserializing) : base(deserializing) { }
    94     protected ProbabilisticTravelingSalesmanProblem(ProbabilisticTravelingSalesmanProblem original, Cloner cloner) : base(original, cloner) { }
     97    protected ProbabilisticTravelingSalesmanProblem(ProbabilisticTravelingSalesmanProblem original, Cloner cloner)
     98      : base(original, cloner) {
     99      RegisterEventHandlers();
     100    }
    95101    protected ProbabilisticTravelingSalesmanProblem() {
    96102      Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the cities."));
     
    101107      Parameters.Add(new ValueParameter<DoubleArray>("Probabilities", "This list describes for each city the probability of appearing in a realized instance."));
    102108
    103       Coordinates = new DoubleMatrix(new double[,] {
     109      var coordinates = new DoubleMatrix(new double[,] {
    104110        { 100, 100 }, { 100, 200 }, { 100, 300 }, { 100, 400 },
    105111        { 200, 100 }, { 200, 200 }, { 200, 300 }, { 200, 400 },
     
    107113        { 400, 100 }, { 400, 200 }, { 400, 300 }, { 400, 400 }
    108114      });
    109 
    110       Probabilities = new DoubleArray(new double[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 });
     115      Coordinates = coordinates;
     116      Encoding.Length = coordinates.Rows;
     117      DistanceCalculator = new EuclideanDistance();
     118      DistanceMatrix = new DistanceMatrix(CalculateDistances());
     119      Probabilities = new DoubleArray(Enumerable.Range(0, coordinates.Rows).Select(x => 0.5).ToArray());
     120
     121      RegisterEventHandlers();
     122    }
     123
     124    [StorableHook(HookType.AfterDeserialization)]
     125    private void AfterDeserialization() {
     126      RegisterEventHandlers();
     127    }
     128
     129    private void RegisterEventHandlers() {
     130      CoordinatesParameter.ValueChanged += CoordinatesParameterOnValueChanged;
     131      if (Coordinates != null) {
     132        Coordinates.RowsChanged += CoordinatesOnChanged;
     133        Coordinates.ItemChanged += CoordinatesOnChanged;
     134      }
     135      UseDistanceMatrixParameter.Value.ValueChanged += UseDistanceMatrixValueChanged;
     136      DistanceCalculatorParameter.ValueChanged += DistanceCalculatorParameterOnValueChanged;
     137    }
     138
     139    private void CoordinatesParameterOnValueChanged(object sender, EventArgs eventArgs) {
     140      if (Coordinates != null) {
     141        Coordinates.RowsChanged += CoordinatesOnChanged;
     142        Coordinates.ItemChanged += CoordinatesOnChanged;
     143      }
     144      if (SuppressEvents) return;
     145      UpdateInstance();
     146    }
     147
     148    private void CoordinatesOnChanged(object sender, EventArgs eventArgs) {
     149      if (SuppressEvents) return;
     150      UpdateInstance();
     151    }
     152
     153    private void UseDistanceMatrixValueChanged(object sender, EventArgs eventArgs) {
     154      if (SuppressEvents) return;
     155      UpdateInstance();
     156    }
     157
     158    private void DistanceCalculatorParameterOnValueChanged(object sender, EventArgs eventArgs) {
     159      if (SuppressEvents) return;
     160      UpdateInstance();
    111161    }
    112162
     
    117167    public abstract double Evaluate(Permutation tour, IRandom random);
    118168
     169    public double[,] CalculateDistances() {
     170      var coords = Coordinates;
     171      var len = coords.Rows;
     172      var dist = DistanceCalculator;
     173
     174      var matrix = new double[len, len];
     175      for (var i = 0; i < len - 1; i++)
     176        for (var j = i + 1; j < len; j++)
     177          matrix[i, j] = matrix[j, i] = dist.Calculate(i, j, coords);
     178
     179      return matrix;
     180    }
     181
    119182    public virtual void Load(PTSPData data) {
    120       if (data.Coordinates == null && data.Distances == null)
    121         throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
    122       if (data.Dimension > DistanceMatrixSizeLimit && (data.Coordinates == null || data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
    123         throw new System.IO.InvalidDataException("The given instance is too large for using a distance matrix and there is a problem with the coordinates.");
    124       if (data.Coordinates != null && (data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
    125         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.");
    126 
    127       switch (data.DistanceMeasure) {
    128         case DistanceMeasure.Direct:
    129           DistanceCalculator = null;
    130           if (data.Dimension > DistanceMatrixSizeLimit && Coordinates != null) {
    131             DistanceCalculator = new EuclideanDistance();
    132             UseDistanceMatrix = false;
    133           } else UseDistanceMatrix = true;
    134           break;
    135         case DistanceMeasure.Att: DistanceCalculator = new AttDistance(); break;
    136         case DistanceMeasure.Euclidean: DistanceCalculator = new EuclideanDistance(); break;
    137         case DistanceMeasure.Geo: DistanceCalculator = new GeoDistance(); break;
    138         case DistanceMeasure.Manhattan: DistanceCalculator = new ManhattanDistance(); break;
    139         case DistanceMeasure.Maximum: DistanceCalculator = new MaximumDistance(); break;
    140         case DistanceMeasure.RoundedEuclidean: DistanceCalculator = new RoundedEuclideanDistance(); break;
    141         case DistanceMeasure.UpperEuclidean: DistanceCalculator = new UpperEuclideanDistance(); break;
    142         default: throw new ArgumentException("Distance measure is unknown");
    143       }
    144 
    145       Name = data.Name;
    146       Description = data.Description;
    147 
    148       Probabilities = new DoubleArray(data.Probabilities);
    149       BestKnownSolution = data.BestKnownTour != null ? new Permutation(PermutationTypes.RelativeUndirected, data.BestKnownTour) : null;
    150       Coordinates = data.Coordinates != null && data.Coordinates.GetLength(0) > 0 ? new DoubleMatrix(data.Coordinates) : null;
    151       DistanceMatrix = new DistanceMatrix(data.GetDistanceMatrix());
    152 
    153       Encoding.Length = data.Dimension;
    154 
     183      try {
     184        SuppressEvents = true;
     185        if (data.Coordinates == null && data.Distances == null)
     186          throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
     187        if (data.Dimension > DistanceMatrixSizeLimit && (data.Coordinates == null || data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
     188          throw new System.IO.InvalidDataException("The given instance is too large for using a distance matrix and there is a problem with the coordinates.");
     189        if (data.Coordinates != null && (data.Coordinates.GetLength(0) != data.Dimension || data.Coordinates.GetLength(1) != 2))
     190          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.");
     191
     192        switch (data.DistanceMeasure) {
     193          case DistanceMeasure.Direct:
     194            DistanceCalculator = null;
     195            if (data.Dimension > DistanceMatrixSizeLimit && Coordinates != null) {
     196              DistanceCalculator = new EuclideanDistance();
     197              UseDistanceMatrix = false;
     198            } else UseDistanceMatrix = true;
     199            break;
     200          case DistanceMeasure.Att: DistanceCalculator = new AttDistance(); break;
     201          case DistanceMeasure.Euclidean: DistanceCalculator = new EuclideanDistance(); break;
     202          case DistanceMeasure.Geo: DistanceCalculator = new GeoDistance(); break;
     203          case DistanceMeasure.Manhattan: DistanceCalculator = new ManhattanDistance(); break;
     204          case DistanceMeasure.Maximum: DistanceCalculator = new MaximumDistance(); break;
     205          case DistanceMeasure.RoundedEuclidean: DistanceCalculator = new RoundedEuclideanDistance(); break;
     206          case DistanceMeasure.UpperEuclidean: DistanceCalculator = new UpperEuclideanDistance(); break;
     207          default: throw new ArgumentException("Distance measure is unknown");
     208        }
     209
     210        Name = data.Name;
     211        Description = data.Description;
     212
     213        Probabilities = new DoubleArray(data.Probabilities);
     214        BestKnownSolution = data.BestKnownTour != null ? new Permutation(PermutationTypes.RelativeUndirected, data.BestKnownTour) : null;
     215        Coordinates = data.Coordinates != null && data.Coordinates.GetLength(0) > 0 ? new DoubleMatrix(data.Coordinates) : null;
     216        DistanceMatrix = data.Dimension <= DistanceMatrixSizeLimit && UseDistanceMatrix ? new DistanceMatrix(data.GetDistanceMatrix()) : null;
     217
     218        Encoding.Length = data.Dimension;
     219      } finally { SuppressEvents = false; }
    155220      OnReset();
     221    }
     222
     223    private void UpdateInstance() {
     224      var len = GetProblemDimension();
     225      if (Coordinates != null && Coordinates.Rows <= DistanceMatrixSizeLimit
     226        && DistanceCalculator != null && UseDistanceMatrix)
     227        DistanceMatrix = new DistanceMatrix(CalculateDistances());
     228      if (!UseDistanceMatrix) DistanceMatrix = null;
     229      Encoding.Length = len;
     230
     231      OnReset();
     232    }
     233
     234    private int GetProblemDimension() {
     235      if (Coordinates == null && DistanceMatrix == null) throw new InvalidOperationException("Both coordinates and distance matrix are null, please specify at least one of them.");
     236      return Coordinates != null ? Coordinates.Rows : DistanceMatrix.Rows;
    156237    }
    157238  }
Note: See TracChangeset for help on using the changeset viewer.