Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2521: Added first version of problem results.

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