source: branches/ProblemRefactoring/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs @ 13366

Last change on this file since 13366 was 13366, checked in by mkommend, 7 years ago

#2521: Adapted PermutationEncoding and TSP.

File size: 22.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.IO;
25using System.Linq;
26using HeuristicLab.Analysis;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Encodings.PermutationEncoding;
31using HeuristicLab.Optimization;
32using HeuristicLab.Optimization.Operators;
33using HeuristicLab.Parameters;
34using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
35using HeuristicLab.PluginInfrastructure;
36using HeuristicLab.Problems.Instances;
37
38namespace HeuristicLab.Problems.TravelingSalesman {
39  [Item("Traveling Salesman Problem (TSP)", "Represents a symmetric Traveling Salesman Problem.")]
40  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 100)]
41  [StorableClass]
42  public sealed class TravelingSalesmanProblem : SingleObjectiveHeuristicOptimizationProblem<ITSPEvaluator, IPermutationCreator>,
43    ISingleObjectiveProblem<PermutationEncoding, Permutation>, IStorableContent, IProblemInstanceConsumer<TSPData> {
44
45    private static readonly int DistanceMatrixSizeLimit = 1000;
46    public string Filename { get; set; }
47
48    #region Parameter Properties
49    public OptionalValueParameter<DoubleMatrix> CoordinatesParameter {
50      get { return (OptionalValueParameter<DoubleMatrix>)Parameters["Coordinates"]; }
51    }
52    public OptionalValueParameter<DistanceMatrix> DistanceMatrixParameter {
53      get { return (OptionalValueParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
54    }
55    public ValueParameter<BoolValue> UseDistanceMatrixParameter {
56      get { return (ValueParameter<BoolValue>)Parameters["UseDistanceMatrix"]; }
57    }
58    public OptionalValueParameter<Permutation> BestKnownSolutionParameter {
59      get { return (OptionalValueParameter<Permutation>)Parameters["BestKnownSolution"]; }
60    }
61    #endregion
62
63    #region Properties
64    public DoubleMatrix Coordinates {
65      get { return CoordinatesParameter.Value; }
66      set { CoordinatesParameter.Value = value; }
67    }
68    public DistanceMatrix DistanceMatrix {
69      get { return DistanceMatrixParameter.Value; }
70      set { DistanceMatrixParameter.Value = value; }
71    }
72    public BoolValue UseDistanceMatrix {
73      get { return UseDistanceMatrixParameter.Value; }
74      set { UseDistanceMatrixParameter.Value = value; }
75    }
76    public Permutation BestKnownSolution {
77      get { return BestKnownSolutionParameter.Value; }
78      set { BestKnownSolutionParameter.Value = value; }
79    }
80    private BestTSPSolutionAnalyzer BestTSPSolutionAnalyzer {
81      get { return Operators.OfType<BestTSPSolutionAnalyzer>().FirstOrDefault(); }
82    }
83    private TSPAlleleFrequencyAnalyzer TSPAlleleFrequencyAnalyzer {
84      get { return Operators.OfType<TSPAlleleFrequencyAnalyzer>().FirstOrDefault(); }
85    }
86    #endregion
87
88    // BackwardsCompatibility3.3
89    #region Backwards compatible code, remove with 3.4
90    [Obsolete]
91    [Storable(Name = "operators")]
92    private IEnumerable<IOperator> oldOperators {
93      get { return null; }
94      set {
95        if (value != null && value.Any())
96          Operators.AddRange(value);
97      }
98    }
99    #endregion
100
101    [StorableConstructor]
102    private TravelingSalesmanProblem(bool deserializing) : base(deserializing) { }
103    private TravelingSalesmanProblem(TravelingSalesmanProblem original, Cloner cloner)
104      : base(original, cloner) {
105      RegisterEventHandlers();
106    }
107    public override IDeepCloneable Clone(Cloner cloner) {
108      return new TravelingSalesmanProblem(this, cloner);
109    }
110    public TravelingSalesmanProblem()
111      : base(new TSPRoundedEuclideanPathEvaluator(), new RandomPermutationCreator()) {
112      Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the cities."));
113      Parameters.Add(new OptionalValueParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
114      Parameters.Add(new ValueParameter<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)));
115      Parameters.Add(new OptionalValueParameter<Permutation>("BestKnownSolution", "The best known solution of this TSP instance."));
116
117      Maximization.Value = false;
118      MaximizationParameter.Hidden = true;
119      UseDistanceMatrixParameter.Hidden = true;
120      DistanceMatrixParameter.ReactOnValueToStringChangedAndValueItemImageChanged = false;
121
122      Coordinates = new DoubleMatrix(new double[,] {
123        { 100, 100 }, { 100, 200 }, { 100, 300 }, { 100, 400 },
124        { 200, 100 }, { 200, 200 }, { 200, 300 }, { 200, 400 },
125        { 300, 100 }, { 300, 200 }, { 300, 300 }, { 300, 400 },
126        { 400, 100 }, { 400, 200 }, { 400, 300 }, { 400, 400 }
127      });
128
129      SolutionCreator.PermutationParameter.ActualName = "TSPTour";
130      Evaluator.QualityParameter.ActualName = "TSPTourLength";
131      ParameterizeSolutionCreator();
132      ParameterizeEvaluator();
133
134      InitializeOperators();
135      RegisterEventHandlers();
136    }
137
138    #region Events
139    protected override void OnSolutionCreatorChanged() {
140      base.OnSolutionCreatorChanged();
141      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
142      ParameterizeSolutionCreator();
143      ParameterizeEvaluator();
144      ParameterizeAnalyzers();
145      ParameterizeOperators();
146    }
147    protected override void OnEvaluatorChanged() {
148      base.OnEvaluatorChanged();
149      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
150      ParameterizeEvaluator();
151      ParameterizeSolutionCreator();
152      UpdateMoveEvaluators();
153      ParameterizeAnalyzers();
154      if (Evaluator is ITSPCoordinatesPathEvaluator && Coordinates != null)
155        ClearDistanceMatrix();
156    }
157    private void CoordinatesParameter_ValueChanged(object sender, EventArgs e) {
158      if (Coordinates != null) {
159        Coordinates.ItemChanged += new EventHandler<EventArgs<int, int>>(Coordinates_ItemChanged);
160        Coordinates.Reset += new EventHandler(Coordinates_Reset);
161      }
162      if (Evaluator is ITSPCoordinatesPathEvaluator) {
163        ParameterizeSolutionCreator();
164        ClearDistanceMatrix();
165      }
166    }
167    private void Coordinates_ItemChanged(object sender, EventArgs<int, int> e) {
168      if (Evaluator is ITSPCoordinatesPathEvaluator) {
169        ClearDistanceMatrix();
170      }
171    }
172    private void Coordinates_Reset(object sender, EventArgs e) {
173      if (Evaluator is ITSPCoordinatesPathEvaluator) {
174        ParameterizeSolutionCreator();
175        ClearDistanceMatrix();
176      }
177    }
178    private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
179      ParameterizeEvaluator();
180      ParameterizeAnalyzers();
181      ParameterizeOperators();
182    }
183    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
184      ParameterizeAnalyzers();
185    }
186    #endregion
187
188    #region Helpers
189    [StorableHook(HookType.AfterDeserialization)]
190    private void AfterDeserialization() {
191      // BackwardsCompatibility3.3
192      #region Backwards compatible code (remove with 3.4)
193      OptionalValueParameter<DoubleMatrix> oldDistanceMatrixParameter = Parameters["DistanceMatrix"] as OptionalValueParameter<DoubleMatrix>;
194      if (oldDistanceMatrixParameter != null) {
195        Parameters.Remove(oldDistanceMatrixParameter);
196        Parameters.Add(new OptionalValueParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
197        DistanceMatrixParameter.GetsCollected = oldDistanceMatrixParameter.GetsCollected;
198        DistanceMatrixParameter.ReactOnValueToStringChangedAndValueItemImageChanged = false;
199        if (oldDistanceMatrixParameter.Value != null) {
200          DoubleMatrix oldDM = oldDistanceMatrixParameter.Value;
201          DistanceMatrix newDM = new DistanceMatrix(oldDM.Rows, oldDM.Columns, oldDM.ColumnNames, oldDM.RowNames);
202          newDM.SortableView = oldDM.SortableView;
203          for (int i = 0; i < newDM.Rows; i++)
204            for (int j = 0; j < newDM.Columns; j++)
205              newDM[i, j] = oldDM[i, j];
206          DistanceMatrixParameter.Value = (DistanceMatrix)newDM.AsReadOnly();
207        }
208      }
209
210      ValueParameter<DoubleMatrix> oldCoordinates = (Parameters["Coordinates"] as ValueParameter<DoubleMatrix>);
211      if (oldCoordinates != null) {
212        Parameters.Remove(oldCoordinates);
213        Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the cities.", oldCoordinates.Value, oldCoordinates.GetsCollected));
214      }
215
216      if (Operators.Count == 0) InitializeOperators();
217      #endregion
218      RegisterEventHandlers();
219    }
220
221    private void RegisterEventHandlers() {
222      CoordinatesParameter.ValueChanged += new EventHandler(CoordinatesParameter_ValueChanged);
223      if (Coordinates != null) {
224        Coordinates.ItemChanged += new EventHandler<EventArgs<int, int>>(Coordinates_ItemChanged);
225        Coordinates.Reset += new EventHandler(Coordinates_Reset);
226      }
227      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
228      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
229    }
230
231    private void InitializeOperators() {
232      Operators.Add(new TSPImprovementOperator());
233      Operators.Add(new TSPMultipleGuidesPathRelinker());
234      Operators.Add(new TSPPathRelinker());
235      Operators.Add(new TSPSimultaneousPathRelinker());
236      Operators.Add(new TSPSimilarityCalculator());
237      Operators.Add(new QualitySimilarityCalculator());
238      Operators.Add(new NoSimilarityCalculator());
239
240      Operators.Add(new BestTSPSolutionAnalyzer());
241      Operators.Add(new TSPAlleleFrequencyAnalyzer());
242      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
243      ParameterizeAnalyzers();
244      var operators = new HashSet<IPermutationOperator>(new IPermutationOperator[] {
245        new OrderCrossover2(),
246        new InversionManipulator(),
247        new StochasticInversionMultiMoveGenerator()
248      }, new TypeEqualityComparer<IPermutationOperator>());
249      foreach (var op in ApplicationManager.Manager.GetInstances<IPermutationOperator>())
250        operators.Add(op);
251      Operators.AddRange(operators);
252      ParameterizeOperators();
253      UpdateMoveEvaluators();
254    }
255    private void UpdateMoveEvaluators() {
256      Operators.RemoveAll(x => x is ISingleObjectiveMoveEvaluator);
257      foreach (var op in ApplicationManager.Manager.GetInstances<ITSPMoveEvaluator>())
258        if (op.EvaluatorType == Evaluator.GetType()) {
259          Operators.Add(op);
260        }
261      ParameterizeOperators();
262      OnOperatorsChanged();
263    }
264    private void ParameterizeSolutionCreator() {
265      if (Evaluator is ITSPDistanceMatrixEvaluator && DistanceMatrix != null)
266        SolutionCreator.LengthParameter.Value = new IntValue(DistanceMatrix.Rows);
267      else if (Evaluator is ITSPCoordinatesPathEvaluator && Coordinates != null)
268        SolutionCreator.LengthParameter.Value = new IntValue(Coordinates.Rows);
269      else {
270        SolutionCreator.LengthParameter.Value = null;
271        string error = "The given problem does not support the selected evaluator.";
272        if (Evaluator is ITSPDistanceMatrixEvaluator)
273          error += Environment.NewLine + "Please review that the " + DistanceMatrixParameter.Name + " parameter is defined or choose another evaluator.";
274        else error += Environment.NewLine + "Please review that the " + CoordinatesParameter.Name + " parameter is defined or choose another evaluator.";
275        PluginInfrastructure.ErrorHandling.ShowErrorDialog(error, null);
276      }
277      SolutionCreator.LengthParameter.Hidden = SolutionCreator.LengthParameter.Value != null;
278      SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.RelativeUndirected);
279      SolutionCreator.PermutationTypeParameter.Hidden = true;
280    }
281    private void ParameterizeEvaluator() {
282      if (Evaluator is ITSPPathEvaluator) {
283        ITSPPathEvaluator evaluator = (ITSPPathEvaluator)Evaluator;
284        evaluator.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
285        evaluator.PermutationParameter.Hidden = true;
286      }
287      if (Evaluator is ITSPCoordinatesPathEvaluator) {
288        ITSPCoordinatesPathEvaluator evaluator = (ITSPCoordinatesPathEvaluator)Evaluator;
289        evaluator.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
290        evaluator.CoordinatesParameter.Hidden = true;
291        evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
292        evaluator.DistanceMatrixParameter.Hidden = true;
293        evaluator.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name;
294        evaluator.UseDistanceMatrixParameter.Hidden = true;
295      }
296      if (Evaluator is ITSPDistanceMatrixEvaluator) {
297        var evaluator = (ITSPDistanceMatrixEvaluator)Evaluator;
298        evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
299        evaluator.DistanceMatrixParameter.Hidden = true;
300      }
301    }
302    private void ParameterizeAnalyzers() {
303      if (BestTSPSolutionAnalyzer != null) {
304        BestTSPSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
305        BestTSPSolutionAnalyzer.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
306        BestTSPSolutionAnalyzer.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
307        BestTSPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
308        BestTSPSolutionAnalyzer.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
309        BestTSPSolutionAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
310        BestTSPSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
311      }
312
313      if (TSPAlleleFrequencyAnalyzer != null) {
314        TSPAlleleFrequencyAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
315        TSPAlleleFrequencyAnalyzer.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
316        TSPAlleleFrequencyAnalyzer.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
317        TSPAlleleFrequencyAnalyzer.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
318        TSPAlleleFrequencyAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
319        TSPAlleleFrequencyAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
320        TSPAlleleFrequencyAnalyzer.ResultsParameter.ActualName = "Results";
321      }
322    }
323    private void ParameterizeOperators() {
324      foreach (IPermutationCrossover op in Operators.OfType<IPermutationCrossover>()) {
325        op.ParentsParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
326        op.ParentsParameter.Hidden = true;
327        op.ChildParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
328        op.ChildParameter.Hidden = true;
329      }
330      foreach (IPermutationManipulator op in Operators.OfType<IPermutationManipulator>()) {
331        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
332        op.PermutationParameter.Hidden = true;
333      }
334      foreach (IPermutationMoveOperator op in Operators.OfType<IPermutationMoveOperator>()) {
335        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
336        op.PermutationParameter.Hidden = true;
337      }
338      foreach (ITSPPathMoveEvaluator op in Operators.OfType<ITSPPathMoveEvaluator>()) {
339        op.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
340        op.CoordinatesParameter.Hidden = true;
341        op.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
342        op.DistanceMatrixParameter.Hidden = true;
343        op.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name;
344        op.UseDistanceMatrixParameter.Hidden = true;
345        op.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
346        op.QualityParameter.Hidden = true;
347        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
348        op.PermutationParameter.Hidden = true;
349      }
350      foreach (IPermutationMultiNeighborhoodShakingOperator op in Operators.OfType<IPermutationMultiNeighborhoodShakingOperator>()) {
351        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
352        op.PermutationParameter.Hidden = true;
353      }
354      foreach (ISingleObjectiveImprovementOperator op in Operators.OfType<ISingleObjectiveImprovementOperator>()) {
355        op.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
356        op.SolutionParameter.Hidden = true;
357      }
358      foreach (ISingleObjectivePathRelinker op in Operators.OfType<ISingleObjectivePathRelinker>()) {
359        op.ParentsParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
360        op.ParentsParameter.Hidden = true;
361      }
362      foreach (ISolutionSimilarityCalculator op in Operators.OfType<ISolutionSimilarityCalculator>()) {
363        op.SolutionVariableName = SolutionCreator.PermutationParameter.ActualName;
364        op.QualityVariableName = Evaluator.QualityParameter.ActualName;
365      }
366    }
367
368    private void ClearDistanceMatrix() {
369      DistanceMatrixParameter.Value = null;
370    }
371    #endregion
372
373    public void Load(TSPData data) {
374      if (data.Coordinates == null && data.Distances == null)
375        throw new System.IO.InvalidDataException("The given instance specifies neither coordinates nor distances!");
376      if (data.Dimension > DistanceMatrixSizeLimit && (data.DistanceMeasure == DistanceMeasure.Att
377        || data.DistanceMeasure == DistanceMeasure.Manhattan
378        || data.DistanceMeasure == DistanceMeasure.Maximum))
379        throw new System.IO.InvalidDataException("The given instance uses an unsupported distance measure and is too large for using a distance matrix.");
380      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
381        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.");
382
383      Name = data.Name;
384      Description = data.Description;
385
386      bool clearCoordinates = false, clearDistanceMatrix = false;
387      if (data.Coordinates != null && data.Coordinates.GetLength(0) > 0)
388        Coordinates = new DoubleMatrix(data.Coordinates);
389      else clearCoordinates = true;
390
391      TSPEvaluator evaluator;
392      if (data.DistanceMeasure == DistanceMeasure.Att
393        || data.DistanceMeasure == DistanceMeasure.Manhattan
394        || data.DistanceMeasure == DistanceMeasure.Maximum) {
395        evaluator = new TSPDistanceMatrixEvaluator();
396        UseDistanceMatrix = new BoolValue(true);
397        DistanceMatrix = new DistanceMatrix(data.GetDistanceMatrix());
398      } else if (data.DistanceMeasure == DistanceMeasure.Direct && data.Distances != null) {
399        evaluator = new TSPDistanceMatrixEvaluator();
400        UseDistanceMatrix = new BoolValue(true);
401        DistanceMatrix = new DistanceMatrix(data.Distances);
402      } else {
403        clearDistanceMatrix = true;
404        UseDistanceMatrix = new BoolValue(data.Dimension <= DistanceMatrixSizeLimit);
405        switch (data.DistanceMeasure) {
406          case DistanceMeasure.Euclidean:
407            evaluator = new TSPEuclideanPathEvaluator();
408            break;
409          case DistanceMeasure.RoundedEuclidean:
410            evaluator = new TSPRoundedEuclideanPathEvaluator();
411            break;
412          case DistanceMeasure.UpperEuclidean:
413            evaluator = new TSPUpperEuclideanPathEvaluator();
414            break;
415          case DistanceMeasure.Geo:
416            evaluator = new TSPGeoPathEvaluator();
417            break;
418          default:
419            throw new InvalidDataException("An unknown distance measure is given in the instance!");
420        }
421      }
422      evaluator.QualityParameter.ActualName = "TSPTourLength";
423      Evaluator = evaluator;
424
425      // reset them after assigning the evaluator
426      if (clearCoordinates) Coordinates = null;
427      if (clearDistanceMatrix) DistanceMatrix = null;
428
429      BestKnownSolution = null;
430      BestKnownQuality = null;
431
432      if (data.BestKnownTour != null) {
433        try {
434          EvaluateAndLoadTour(data.BestKnownTour);
435        }
436        catch (InvalidOperationException) {
437          if (data.BestKnownQuality.HasValue)
438            BestKnownQuality = new DoubleValue(data.BestKnownQuality.Value);
439        }
440      } else if (data.BestKnownQuality.HasValue) {
441        BestKnownQuality = new DoubleValue(data.BestKnownQuality.Value);
442      }
443      OnReset();
444    }
445
446    public void EvaluateAndLoadTour(int[] tour) {
447      var route = new Permutation(PermutationTypes.RelativeUndirected, tour);
448      BestKnownSolution = route;
449
450      double quality;
451      if (Evaluator is ITSPDistanceMatrixEvaluator) {
452        quality = TSPDistanceMatrixEvaluator.Apply(DistanceMatrix, route);
453      } else if (Evaluator is ITSPCoordinatesPathEvaluator) {
454        quality = TSPCoordinatesPathEvaluator.Apply((TSPCoordinatesPathEvaluator)Evaluator, Coordinates, route);
455      } else {
456        throw new InvalidOperationException("Cannot calculate solution quality, evaluator type is unknown.");
457      }
458      BestKnownQuality = new DoubleValue(quality);
459    }
460  }
461}
Note: See TracBrowser for help on using the repository browser.