Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.Orienteering/3.3/OrienteeringProblem.cs @ 15941

Last change on this file since 15941 was 15584, checked in by swagner, 7 years ago

#2640: Updated year of copyrights in license headers on stable

File size: 20.0 KB
RevLine 
[11186]1#region License Information
2/* HeuristicLab
[15584]3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[11186]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;
[11245]23using System.IO;
[11190]24using System.Linq;
[15217]25using HeuristicLab.Analysis;
[11186]26using HeuristicLab.Common;
27using HeuristicLab.Core;
[11187]28using HeuristicLab.Data;
[11186]29using HeuristicLab.Encodings.IntegerVectorEncoding;
30using HeuristicLab.Optimization;
[15217]31using HeuristicLab.Optimization.Operators;
[11187]32using HeuristicLab.Parameters;
[11186]33using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
[11189]34using HeuristicLab.Problems.Instances;
[11261]35using HeuristicLab.Problems.Instances.Types;
[11186]36
37namespace HeuristicLab.Problems.Orienteering {
[13295]38  [Item("Orienteering Problem (OP)", "Represents a single-objective Orienteering Problem.")]
[12721]39  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 115)]
[11186]40  [StorableClass]
[11307]41  public sealed class OrienteeringProblem
[11321]42    : SingleObjectiveHeuristicOptimizationProblem<IOrienteeringEvaluator, IOrienteeringSolutionCreator>,
[11277]43    IStorableContent, IProblemInstanceConsumer<OPData>, IProblemInstanceConsumer<TSPData>, IProblemInstanceConsumer<CVRPData> {
[11186]44
45    public string Filename { get; set; }
46
[11187]47    #region Parameter Properties
[11316]48    public OptionalValueParameter<DoubleMatrix> CoordinatesParameter {
49      get { return (OptionalValueParameter<DoubleMatrix>)Parameters["Coordinates"]; }
[11187]50    }
[11325]51    public IValueParameter<DistanceMatrix> DistanceMatrixParameter {
52      get { return (IValueParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
[11187]53    }
54
[11325]55    public IFixedValueParameter<IntValue> StartingPointParameter {
56      get { return (IFixedValueParameter<IntValue>)Parameters["StartingPoint"]; }
[11187]57    }
[11325]58    public IFixedValueParameter<IntValue> TerminalPointParameter {
59      get { return (IFixedValueParameter<IntValue>)Parameters["TerminalPoint"]; }
[11187]60    }
[11325]61    public IFixedValueParameter<DoubleValue> MaximumDistanceParameter {
62      get { return (IFixedValueParameter<DoubleValue>)Parameters["MaximumDistance"]; }
[11187]63    }
[11325]64    public IValueParameter<DoubleArray> ScoresParameter {
65      get { return (IValueParameter<DoubleArray>)Parameters["Scores"]; }
[11187]66    }
[11325]67    public IFixedValueParameter<DoubleValue> PointVisitingCostsParameter {
68      get { return (IFixedValueParameter<DoubleValue>)Parameters["PointVisitingCosts"]; }
[11187]69    }
70
71    public OptionalValueParameter<IntegerVector> BestKnownSolutionParameter {
72      get { return (OptionalValueParameter<IntegerVector>)Parameters["BestKnownSolution"]; }
73    }
74    #endregion
75
76    #region Properties
77    public DoubleMatrix Coordinates {
78      get { return CoordinatesParameter.Value; }
79      set { CoordinatesParameter.Value = value; }
80    }
81    public DistanceMatrix DistanceMatrix {
82      get { return DistanceMatrixParameter.Value; }
83      set { DistanceMatrixParameter.Value = value; }
84    }
[11325]85    public int StartingPoint {
86      get { return StartingPointParameter.Value.Value; }
87      set { StartingPointParameter.Value.Value = value; }
[11189]88    }
[11325]89    public int TerminalPoint {
90      get { return TerminalPointParameter.Value.Value; }
91      set { TerminalPointParameter.Value.Value = value; }
[11189]92    }
[11325]93    public double MaximumDistance {
94      get { return MaximumDistanceParameter.Value.Value; }
95      set { MaximumDistanceParameter.Value.Value = value; }
[11187]96    }
97    public DoubleArray Scores {
98      get { return ScoresParameter.Value; }
99      set { ScoresParameter.Value = value; }
100    }
[11325]101    public double PointVisitingCosts {
102      get { return PointVisitingCostsParameter.Value.Value; }
103      set { PointVisitingCostsParameter.Value.Value = value; }
[11189]104    }
[11187]105    public IntegerVector BestKnownSolution {
106      get { return BestKnownSolutionParameter.Value; }
107      set { BestKnownSolutionParameter.Value = value; }
108    }
[12721]109    private BestOrienteeringSolutionAnalyzer BestOrienteeringSolutionAnalyser {
110      get { return Operators.OfType<BestOrienteeringSolutionAnalyzer>().SingleOrDefault(); }
[11190]111    }
[11187]112    #endregion
113
[11186]114    [StorableConstructor]
115    private OrienteeringProblem(bool deserializing)
116      : base(deserializing) {
117    }
118    private OrienteeringProblem(OrienteeringProblem original, Cloner cloner)
119      : base(original, cloner) {
120      RegisterEventHandlers();
121    }
122    public override IDeepCloneable Clone(Cloner cloner) {
123      return new OrienteeringProblem(this, cloner);
124    }
125    public OrienteeringProblem()
[11191]126      : base(new OrienteeringEvaluator(), new GreedyOrienteeringTourCreator()) {
[11316]127      Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the points."));
[11191]128      Parameters.Add(new ValueParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the points."));
[11325]129      Parameters.Add(new FixedValueParameter<IntValue>("StartingPoint", "Index of the starting point.", new IntValue(0)));
130      Parameters.Add(new FixedValueParameter<IntValue>("TerminalPoint", "Index of the ending point.", new IntValue(0)));
131      Parameters.Add(new FixedValueParameter<DoubleValue>("MaximumDistance", "The maximum distance constraint for a Orienteering solution."));
[11245]132      Parameters.Add(new ValueParameter<DoubleArray>("Scores", "The scores of the points."));
[11325]133      Parameters.Add(new FixedValueParameter<DoubleValue>("PointVisitingCosts", "The costs for visiting a point."));
[11187]134      Parameters.Add(new OptionalValueParameter<IntegerVector>("BestKnownSolution", "The best known solution of this Orienteering instance."));
[11186]135
136      Maximization.Value = true;
137      MaximizationParameter.Hidden = true;
138
139      SolutionCreator.IntegerVectorParameter.ActualName = "OrienteeringSolution";
140
[11190]141      InitializeInitialOrienteeringInstance();
[11186]142
143      ParameterizeSolutionCreator();
144      ParameterizeEvaluator();
145
146      InitializeOperators();
147      RegisterEventHandlers();
148    }
149
[11187]150    #region Events
[11186]151    protected override void OnSolutionCreatorChanged() {
152      base.OnSolutionCreatorChanged();
[11190]153      SolutionCreator.IntegerVectorParameter.ActualNameChanged += SolutionCreator_IntegerVectorParameter_ActualNameChanged;
[11186]154      ParameterizeSolutionCreator();
155      ParameterizeEvaluator();
156      ParameterizeAnalyzer();
157      ParameterizeOperators();
158    }
159    protected override void OnEvaluatorChanged() {
160      base.OnEvaluatorChanged();
161      ParameterizeEvaluator();
162      ParameterizeAnalyzer();
163    }
164    private void SolutionCreator_IntegerVectorParameter_ActualNameChanged(object sender, EventArgs e) {
165      ParameterizeEvaluator();
166      ParameterizeAnalyzer();
167      ParameterizeOperators();
168    }
[11190]169    private void CoordinatesParameter_ValueChanged(object sender, EventArgs e) {
170      if (Coordinates != null) {
171        Coordinates.ItemChanged += new EventHandler<EventArgs<int, int>>(CoordinatesValue_ItemChanged);
172        Coordinates.Reset += new EventHandler(CoordinatesValue_Reset);
173      }
174      ParameterizeSolutionCreator();
[11269]175      UpdateDistanceMatrix();
[11325]176      CheckStartingIndex();
177      CheckTerminalIndex();
[11190]178    }
179    private void CoordinatesValue_ItemChanged(object sender, EventArgs<int, int> e) {
[11269]180      UpdateDistanceMatrix();
[11325]181      CheckStartingIndex();
182      CheckTerminalIndex();
[11190]183    }
184    private void CoordinatesValue_Reset(object sender, EventArgs e) {
185      ParameterizeSolutionCreator();
[11269]186      UpdateDistanceMatrix();
[11325]187      CheckStartingIndex();
188      CheckTerminalIndex();
[11190]189    }
[11325]190    private void StartingPointParameterValue_ValueChanged(object sender, EventArgs e) {
191      CheckStartingIndex();
[11190]192    }
193
[11325]194    private void TerminalPointParameterValue_ValueChanged(object sender, EventArgs e) {
195      CheckTerminalIndex();
[11190]196    }
[11325]197    private void MaximumDistanceParameterValue_ValueChanged(object sender, EventArgs e) { }
[11190]198    private void ScoresParameter_ValueChanged(object sender, EventArgs e) {
199      ParameterizeEvaluator();
200      ParameterizeAnalyzer();
201      ParameterizeSolutionCreator();
202
203      ScoresParameter.Value.Reset += new EventHandler(ScoresValue_Reset);
204    }
205    private void ScoresValue_Reset(object sender, EventArgs e) {
206      ParameterizeSolutionCreator();
207    }
[11325]208    private void PointVisitingCostsParameterValue_ValueChanged(object sender, EventArgs e) { }
[11328]209
210    private void BestKnownSolutionParameter_ValueChanged(object sender, EventArgs e) {
211      if (BestKnownSolution == null)
212        BestKnownQuality = null;
213    }
[11186]214    #endregion
215
216    #region Helpers
217    [StorableHook(HookType.AfterDeserialization)]
218    private void AfterDeserialization() {
219      RegisterEventHandlers();
220    }
221
222    private void RegisterEventHandlers() {
[11190]223      SolutionCreator.IntegerVectorParameter.ActualNameChanged += SolutionCreator_IntegerVectorParameter_ActualNameChanged;
224
225      CoordinatesParameter.ValueChanged += CoordinatesParameter_ValueChanged;
226      if (CoordinatesParameter.Value != null) {
227        CoordinatesParameter.Value.ItemChanged += CoordinatesValue_ItemChanged;
228        CoordinatesParameter.Value.Reset += CoordinatesValue_Reset;
229      }
230
[11325]231      StartingPointParameter.Value.ValueChanged += StartingPointParameterValue_ValueChanged;
232      TerminalPointParameter.Value.ValueChanged += TerminalPointParameterValue_ValueChanged;
233      MaximumDistanceParameter.Value.ValueChanged += MaximumDistanceParameterValue_ValueChanged;
234      PointVisitingCostsParameter.Value.ValueChanged += PointVisitingCostsParameterValue_ValueChanged;
[11190]235
236      ScoresParameter.ValueChanged += ScoresParameter_ValueChanged;
237      ScoresParameter.Value.Reset += ScoresValue_Reset;
[11328]238
239      BestKnownSolutionParameter.ValueChanged += BestKnownSolutionParameter_ValueChanged;
[11186]240    }
[11190]241
[11186]242    private void ParameterizeSolutionCreator() {
[11321]243      SolutionCreator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
244      SolutionCreator.ScoresParameter.ActualName = ScoresParameter.Name;
245      SolutionCreator.MaximumDistanceParameter.ActualName = MaximumDistanceParameter.Name;
246      SolutionCreator.StartingPointParameter.ActualName = StartingPointParameter.Name;
247      SolutionCreator.TerminalPointParameter.ActualName = TerminalPointParameter.Name;
248      SolutionCreator.PointVisitingCostsParameter.ActualName = PointVisitingCostsParameter.Name;
[11186]249    }
250    private void ParameterizeEvaluator() {
[11321]251      Evaluator.IntegerVectorParameter.ActualName = SolutionCreator.IntegerVectorParameter.ActualName;
252      Evaluator.ScoresParameter.ActualName = ScoresParameter.Name;
253      Evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
254      Evaluator.MaximumDistanceParameter.ActualName = MaximumDistanceParameter.Name;
255      Evaluator.PointVisitingCostsParameter.ActualName = PointVisitingCostsParameter.Name;
[11186]256    }
257    private void ParameterizeAnalyzer() {
[11191]258      if (BestOrienteeringSolutionAnalyser != null) {
259        BestOrienteeringSolutionAnalyser.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
260
261        BestOrienteeringSolutionAnalyser.IntegerVector.ActualName = SolutionCreator.IntegerVectorParameter.ActualName;
262        BestOrienteeringSolutionAnalyser.CoordinatesParameter.ActualName = CoordinatesParameter.Name;
263        BestOrienteeringSolutionAnalyser.ScoresParameter.ActualName = ScoresParameter.Name;
264
265        BestOrienteeringSolutionAnalyser.ResultsParameter.ActualName = "Results";
266        BestOrienteeringSolutionAnalyser.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
267        BestOrienteeringSolutionAnalyser.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
268      }
[11186]269    }
270    private void InitializeOperators() {
[12721]271      Operators.Add(new BestOrienteeringSolutionAnalyzer());
[11191]272      ParameterizeAnalyzer();
273
[11303]274      Operators.Add(new OrienteeringLocalImprovementOperator());
[11195]275      Operators.Add(new OrienteeringShakingOperator());
[15217]276      Operators.Add(new QualitySimilarityCalculator());
277      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
278
[11191]279      ParameterizeOperators();
[11186]280    }
281    private void ParameterizeOperators() {
[11194]282      foreach (var op in Operators.OfType<OrienteeringLocalImprovementOperator>()) {
[11191]283        op.IntegerVectorParameter.ActualName = SolutionCreator.IntegerVectorParameter.ActualName;
[11194]284        op.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
285        op.ScoresParameter.ActualName = ScoresParameter.Name;
286        op.MaximumDistanceParameter.ActualName = MaximumDistanceParameter.Name;
287        op.StartingPointParameter.ActualName = StartingPointParameter.Name;
[11319]288        op.TerminalPointParameter.ActualName = TerminalPointParameter.Name;
[11320]289        op.PointVisitingCostsParameter.ActualName = PointVisitingCostsParameter.Name;
[11194]290      }
[11195]291      foreach (var op in Operators.OfType<OrienteeringShakingOperator>()) {
[11226]292        op.IntegerVectorParameter.ActualName = SolutionCreator.IntegerVectorParameter.ActualName;
293        op.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name;
294        op.ScoresParameter.ActualName = ScoresParameter.Name;
295        op.MaximumDistanceParameter.ActualName = MaximumDistanceParameter.Name;
296        op.StartingPointParameter.ActualName = StartingPointParameter.Name;
[11319]297        op.TerminalPointParameter.ActualName = TerminalPointParameter.Name;
[11320]298        op.PointVisitingCostsParameter.ActualName = PointVisitingCostsParameter.Name;
[11195]299      }
[15217]300      foreach (var similarityCalculator in Operators.OfType<ISolutionSimilarityCalculator>()) {
301        similarityCalculator.SolutionVariableName = SolutionCreator.IntegerVectorParameter.ActualName;
302        similarityCalculator.QualityVariableName = Evaluator.QualityParameter.ActualName;
303      }
[11186]304    }
305    #endregion
306
[11269]307    private DistanceMatrix CalculateDistanceMatrix(double[,] coordinates) {
308      var distances = DistanceHelper.GetDistanceMatrix(DistanceMeasure.Euclidean, coordinates, null, coordinates.GetLength(0));
309
310      return new DistanceMatrix(distances);
311    }
312    private void UpdateDistanceMatrix() {
[11316]313      if (Coordinates == null) {
314        DistanceMatrix = new DistanceMatrix(0, 0);
315        return;
316      }
317
[11269]318      var coordinates = Coordinates;
319      int dimension = coordinates.Rows;
[11270]320      var distances = new double[dimension, dimension];
[11269]321      for (int i = 0; i < dimension - 1; i++) {
322        for (int j = i + 1; j < dimension; j++) {
323          double x1 = coordinates[i, 0];
324          double y1 = coordinates[i, 1];
325          double x2 = coordinates[j, 0];
326          double y2 = coordinates[j, 1];
327          distances[i, j] = Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
328          distances[j, i] = distances[i, j];
[11191]329        }
330      }
[11270]331      DistanceMatrix = new DistanceMatrix(distances);
[11191]332    }
[11325]333    private void CheckStartingIndex() {
334      if (StartingPoint < 0) StartingPoint = 0;
335      if (StartingPoint >= DistanceMatrix.Rows) StartingPoint = DistanceMatrix.Rows - 1;
336    }
337    private void CheckTerminalIndex() {
338      if (TerminalPoint < 0) TerminalPoint = 0;
339      if (TerminalPoint >= DistanceMatrix.Rows) TerminalPoint = DistanceMatrix.Rows - 1;
340    }
[11191]341
[11190]342    private void InitializeInitialOrienteeringInstance() {
[11269]343      var coordinates = new double[21, 2] {
[11190]344        {  4.60,  7.10 }, {  5.70, 11.40 }, {  4.40, 12.30 }, {  2.80, 14.30 }, {  3.20, 10.30 },
345        {  3.50,  9.80 }, {  4.40,  8.40 }, {  7.80, 11.00 }, {  8.80,  9.80 }, {  7.70,  8.20 },
346        {  6.30,  7.90 }, {  5.40,  8.20 }, {  5.80,  6.80 }, {  6.70,  5.80 }, { 13.80, 13.10 },
347        { 14.10, 14.20 }, { 11.20, 13.60 }, {  9.70, 16.40 }, {  9.50, 18.80 }, {  4.70, 16.80 },
348        {  5.00,  5.60 }
[11269]349      };
350      Coordinates = new DoubleMatrix(coordinates);
351      DistanceMatrix = CalculateDistanceMatrix(coordinates);
[11190]352
[11325]353      StartingPoint = 0;
354      TerminalPoint = 20;
355      MaximumDistance = 30;
[11190]356
357      Scores = new DoubleArray(new double[21] { 0, 20, 20, 30, 15, 15, 10, 20, 20, 20, 15, 10, 10, 25, 40, 40, 30, 30, 50, 30, 0 });
[11186]358    }
[11189]359
[11325]360    #region Instance consuming
[11277]361    public void Load(OPData data) {
362      if (data.Coordinates == null && data.Distances == null)
363        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
364      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
[11245]365        throw new 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.");
366
367      // Clear old solutions
368      BestKnownSolution = null;
369
[11189]370      Name = data.Name;
371      Description = data.Description;
372
[11277]373      Coordinates = data.Coordinates != null ? new DoubleMatrix(data.Coordinates) : null;
374      if (data.Distances != null)
375        DistanceMatrix = new DistanceMatrix(data.Distances);
376      else
377        DistanceMatrix = new DistanceMatrix(data.GetDistanceMatrix());
[11245]378
[11325]379      StartingPoint = data.StartingPoint;
380      TerminalPoint = data.TerminalPoint;
[11189]381
[11325]382      PointVisitingCosts = data.PointVisitingCosts;
383      MaximumDistance = data.MaximumDistance;
[11277]384      Scores = new DoubleArray(data.Scores);
[11189]385    }
[11261]386
[11277]387    public void Load(TSPData data) {
388      if (data.Coordinates == null && data.Distances == null)
389        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
390      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
[11261]391        throw new 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.");
392
393      // Clear old solutions
394      BestKnownSolution = null;
395
396      Name = data.Name;
397      Description = data.Description;
398
[11277]399      Coordinates = data.Coordinates != null ? new DoubleMatrix(data.Coordinates) : null;
[11261]400      if (data.Distances != null)
401        DistanceMatrix = new DistanceMatrix(data.Distances);
402      else
[11277]403        DistanceMatrix = new DistanceMatrix(data.GetDistanceMatrix());
[11261]404
[11325]405      StartingPoint = 0; // First city is interpreted as start point
406      TerminalPoint = data.Dimension - 1; // Last city is interpreted als end point
[11261]407
[11325]408      PointVisitingCosts = 0;
409      MaximumDistance = DistanceMatrix.Average() * 5.0; // distance from start to end first to last city is interpreted as maximum distance
[11277]410      Scores = new DoubleArray(Enumerable.Repeat(1.0, data.Dimension).ToArray()); // all scores are 1
[11261]411    }
[11277]412
413    public void Load(CVRPData data) {
414      if (data.Coordinates == null && data.Distances == null)
415        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
416      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
417        throw new 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.");
418
419      // Clear old solutions
420      BestKnownSolution = null;
421
422      Name = data.Name;
423      Description = data.Description;
424
425      Coordinates = data.Coordinates != null ? new DoubleMatrix(data.Coordinates) : null;
426      DistanceMatrix = data.Distances != null
427        ? new DistanceMatrix(data.Distances)
428        : CalculateDistanceMatrix(data.Coordinates);
429
[11325]430      StartingPoint = 0; // Depot is interpreted as start point
431      TerminalPoint = 0; // Depot is interpreted als end point
[11277]432
[11325]433      PointVisitingCosts = 0;
434      MaximumDistance = data.Capacity * 2; // capacity is interpreted as max distance
[11277]435      Scores = new DoubleArray(data.Demands); // demands are interpreted as scores
436    }
[11325]437    #endregion
[11186]438  }
439}
Note: See TracBrowser for help on using the repository browser.