Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.Orienteering/3.3/OrienteeringProblem.cs @ 17594

Last change on this file since 17594 was 17594, checked in by mkommend, 4 years ago

#2521: Added first version of new results. The first algorithm that has been adapted for testing purposes is the hill climber.

File size: 12.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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 System.Threading;
27using HEAL.Attic;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Encodings.IntegerVectorEncoding;
32using HeuristicLab.Optimization;
33using HeuristicLab.Optimization.Operators;
34using HeuristicLab.Parameters;
35using HeuristicLab.Problems.Instances;
36using HeuristicLab.Problems.Instances.Types;
37using HeuristicLab.Problems.TravelingSalesman;
38
39namespace HeuristicLab.Problems.Orienteering {
40  [Item("Orienteering Problem (OP)", "Represents a single-objective Orienteering Problem.")]
41  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 115)]
42  [StorableType("0B8DB4A4-F183-4368-86C6-C51289B183D2")]
43  public sealed class OrienteeringProblem : IntegerVectorProblem,
44      IProblemInstanceConsumer<OPData>, IProblemInstanceConsumer<TSPData>, IProblemInstanceConsumer<CVRPData> {
45
46    [Storable] public ValueParameter<IOrienteeringProblemData> OrienteeringProblemDataParameter { get; private set; }
47    [Storable] public OptionalValueParameter<OrienteeringSolution> BestKnownSolutionParameter { get; private set; }
48    [Storable] private IResultParameter<OrienteeringSolution> BestOrienteeringSolutionParameter { get; set; }
49    //public IResultDefinition<OrienteeringSolution> BestOrienteeringSolution => BestOrienteeringSolutionParameter;
50
51    public IOrienteeringProblemData OrienteeringProblemData {
52      get { return OrienteeringProblemDataParameter.Value; }
53      set { OrienteeringProblemDataParameter.Value = value; }
54    }
55    public OrienteeringSolution BestKnownSolution {
56      get { return BestKnownSolutionParameter.Value; }
57      set { BestKnownSolutionParameter.Value = value; }
58    }
59
60    [StorableConstructor]
61    private OrienteeringProblem(StorableConstructorFlag _) : base(_) {
62    }
63    private OrienteeringProblem(OrienteeringProblem original, Cloner cloner)
64      : base(original, cloner) {
65      OrienteeringProblemDataParameter = cloner.Clone(original.OrienteeringProblemDataParameter);
66      BestKnownSolutionParameter = cloner.Clone(original.BestKnownSolutionParameter);
67      BestOrienteeringSolutionParameter = cloner.Clone(original.BestOrienteeringSolutionParameter);
68    }
69    public override IDeepCloneable Clone(Cloner cloner) {
70      return new OrienteeringProblem(this, cloner);
71    }
72    public OrienteeringProblem()
73      : base(new IntegerVectorEncoding("Route")) {
74      Parameters.Add(OrienteeringProblemDataParameter = new ValueParameter<IOrienteeringProblemData>("OP Data", "The main parameters for the orienteering problem.", new OrienteeringProblemData()));
75      Parameters.Add(BestKnownSolutionParameter = new OptionalValueParameter<OrienteeringSolution>("BestKnownSolution", "The best known solution of this Orienteering instance."));
76      Parameters.Add(BestOrienteeringSolutionParameter = new ResultParameter<OrienteeringSolution>("Best Orienteering Solution", "The best so far solution found."));
77      Maximization = true;
78      Dimension = OrienteeringProblemData.Cities;
79
80      InitializeOperators();
81    }
82
83    public override ISingleObjectiveEvaluationResult Evaluate(IntegerVector solution, IRandom random, CancellationToken cancellationToken) {
84      var data = OrienteeringProblemData;
85      var score = CalculateScore(data, solution);
86      var travelCosts = CalculateTravelCosts(data, solution);
87      var quality = CalculateQuality(data, score, travelCosts);
88
89      return new SingleObjectiveEvaluationResult(quality);
90    }
91
92    public static double CalculateQuality(IOrienteeringProblemData data, double score, double travelCosts) {
93      if (travelCosts > data.MaximumTravelCosts) return data.MaximumTravelCosts - travelCosts; // negative excessive distance
94      return score;
95    }
96    public static double CalculateScore(IOrienteeringProblemData data, IEnumerable<int> solution) {
97      return solution.Sum(t => data.GetScore(t));
98    }
99    public static double CalculateTravelCosts(IOrienteeringProblemData data, IntegerVector solution) {
100      var distance = data.GetPathDistance(solution, closed: false);
101      distance += (solution.Length - 2) * data.PointVisitingCosts;
102      return distance;
103    }
104    public static double CalculateTravelCosts(IOrienteeringProblemData data, IList<int> solution) {
105      var distance = data.GetPathDistance(solution, closed: false);
106      distance += (solution.Count - 2) * data.PointVisitingCosts;
107      return distance;
108    }
109
110    public override void Analyze(IntegerVector[] vectors, double[] qualities, ResultCollection results, IRandom random) {
111      base.Analyze(vectors, qualities, results, random);
112      var data = OrienteeringProblemData;
113
114      var best = GetBestSolution(vectors, qualities).Item1;
115      var score = CalculateScore(OrienteeringProblemData, best);
116      var travelCosts = CalculateTravelCosts(OrienteeringProblemData, best);
117      var quality = CalculateQuality(OrienteeringProblemData, score, travelCosts);
118
119      if (double.IsNaN(BestKnownQuality) || IsBetter(quality, BestKnownQuality)) {
120        BestKnownQuality = quality;
121        BestKnownSolutionParameter.ActualValue = data.GetSolution((IntegerVector)best.Clone(), quality, score, travelCosts);
122      }
123      var bestSoFar = BestOrienteeringSolutionParameter.ActualValue;
124     
125      if (bestSoFar == null || IsBetter(quality, bestSoFar.Quality.Value)) {
126        bestSoFar = data.GetSolution((IntegerVector)best.Clone(), quality, score, travelCosts);
127        BestOrienteeringSolutionParameter.ActualValue = bestSoFar;
128      }
129    }
130    public static double CalculateInsertionCosts(IOrienteeringProblemData data, IList<int> path, int insertPosition, int point) {
131      double detour = data.GetDistance(path[insertPosition - 1], point) + data.GetDistance(point, path[insertPosition]);
132      detour += data.PointVisitingCosts;
133      detour -= data.GetDistance(path[insertPosition - 1], path[insertPosition]);
134      return detour;
135    }
136    public static double CalculateReplacementCosts(IOrienteeringProblemData data, IList<int> path, int replacePosition, int point) {
137      double detour = data.GetDistance(path[replacePosition - 1], point) + data.GetDistance(point, path[replacePosition + 1]);
138      detour -= data.GetDistance(path[replacePosition - 1], path[replacePosition]) + data.GetDistance(path[replacePosition], path[replacePosition + 1]);
139      return detour;
140    }
141    public static double CalculateRemovementSaving(IOrienteeringProblemData data, IList<int> path, int removePosition) {
142      double saving = data.GetDistance(path[removePosition - 1], path[removePosition]);
143      saving += data.GetDistance(path[removePosition], path[removePosition + 1]);
144      saving -= data.GetDistance(path[removePosition - 1], path[removePosition + 1]);
145      saving += data.PointVisitingCosts;
146      return saving;
147    }
148
149    private void RegisterEventHandlers() {
150      OrienteeringProblemDataParameter.ValueChanged += OrienteeringProblemDataParameterOnValueChanged;
151    }
152
153    private void OrienteeringProblemDataParameterOnValueChanged(object sender, EventArgs e) {
154      Dimension = OrienteeringProblemData.Cities;
155    }
156
157    protected override void OnEvaluatorChanged() {
158      base.OnEvaluatorChanged();
159      ParameterizeOperators();
160    }
161    protected override void DimensionOnChanged() {
162      base.DimensionOnChanged();
163      if (Dimension != OrienteeringProblemData.Cities)
164        Dimension = OrienteeringProblemData.Cities;
165    }
166
167    private void InitializeOperators() {
168      Encoding.SolutionCreator = new GreedyOrienteeringTourCreator() {
169        OrienteeringProblemDataParameter = { ActualName = OrienteeringProblemDataParameter.Name }
170      };
171      Operators.Add(new OrienteeringLocalImprovementOperator() {
172        OrienteeringProblemDataParameter = { ActualName = OrienteeringProblemDataParameter.Name }
173      });
174      Operators.Add(new OrienteeringShakingOperator() {
175        OrienteeringProblemDataParameter = { ActualName = OrienteeringProblemDataParameter.Name }
176      });
177      Operators.Add(new QualitySimilarityCalculator());
178      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
179
180      ParameterizeOperators();
181    }
182
183    private void ParameterizeOperators() {
184      foreach (var op in Operators.OfType<OrienteeringLocalImprovementOperator>()) {
185        op.IntegerVectorParameter.ActualName = Encoding.Name;
186        op.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
187      }
188      foreach (var op in Operators.OfType<OrienteeringShakingOperator>()) {
189        op.IntegerVectorParameter.ActualName = Encoding.Name;
190      }
191      foreach (var similarityCalculator in Operators.OfType<ISolutionSimilarityCalculator>()) {
192        similarityCalculator.SolutionVariableName = Encoding.Name;
193        similarityCalculator.QualityVariableName = Evaluator.QualityParameter.ActualName;
194      }
195    }
196
197    #region Instance consuming
198    public void Load(OPData data) {
199      if (data.Coordinates == null && data.Distances == null)
200        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
201      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
202        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.");
203
204      // Clear old solutions
205      BestKnownSolution = null;
206
207      Name = data.Name;
208      Description = data.Description;
209
210      var tsp = TSP.GetDataFromInstance(data);
211      OrienteeringProblemData = new OrienteeringProblemData(tsp, data.StartingPoint, data.TerminalPoint, data.Scores, data.MaximumDistance, data.PointVisitingCosts);
212    }
213
214    public void Load(TSPData data) {
215      if (data.Coordinates == null && data.Distances == null)
216        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
217      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
218        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.");
219
220      // Clear old solutions
221      BestKnownSolution = null;
222
223      Name = data.Name;
224      Description = data.Description;
225
226
227      var tsp = TSP.GetDataFromInstance(data);
228      var avgDist = 0.0;
229      for (var i = 0; i < data.Dimension - 1; i++)
230        for (var j = i + 1; i < data.Dimension; j++)
231          avgDist += tsp.GetDistance(i, j);
232      avgDist /= (data.Dimension - 1) * data.Dimension / 2.0;
233
234      OrienteeringProblemData = new OrienteeringProblemData(tsp, 0, data.Dimension - 1,
235        Enumerable.Repeat(1.0, data.Dimension).ToArray(), 5 * avgDist, 0);
236    }
237
238    public void Load(CVRPData data) {
239      if (data.Coordinates == null && data.Distances == null)
240        throw new InvalidDataException("The given instance specifies no coordinates or distance matrix!");
241      if (data.Coordinates != null && data.Coordinates.GetLength(1) != 2)
242        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.");
243
244      // Clear old solutions
245      BestKnownSolution = null;
246
247      Name = data.Name;
248      Description = data.Description;
249
250      var tsp = TSP.GetDataFromInstance(data);
251      OrienteeringProblemData = new OrienteeringProblemData(tsp, 0, 0, data.Demands, data.Capacity * 2, 0);
252    }
253    #endregion
254  }
255}
Note: See TracBrowser for help on using the repository browser.