Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 17533 was 17533, checked in by abeham, 4 years ago

#2521: Unified architecture

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