Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.Orienteering/HeuristicLab.Problems.Orienteering/3.3/OrienteeringProblem.cs @ 12694

Last change on this file since 12694 was 11328, checked in by pfleck, 10 years ago

#2208 Set BestKnownQuality to null when BestKnownSolution is set to null.

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