Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2971: Added first draft of results implementation and problem adaptation.

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