#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.IntegerVectorEncoding;
using HeuristicLab.Parameters;
using HEAL.Attic;
namespace HeuristicLab.Problems.Orienteering {
///
/// The initial solution for P-VNS is generated by means of a greedy algorithm that takes into
/// account all vertices vi that are located within the cost limit Tmax. These points are sorted
/// in descending order regarding the sum of their objective values. Afterwards, the algorithm
/// starts with a tour only including the starting and ending point and successively inserts the
/// points from this list at the first position in which they can feasibly be inserted.
/// (Schilde et. al. 2009)
///
[Item("GreedyOrienteeringTourCreator", @"Implements the solution creation procedure described in Schilde M., Doerner K.F., Hartl R.F., Kiechle G. 2009. Metaheuristics for the bi-objective orienteering problem. Swarm Intelligence, Volume 3, Issue 3, pp 179-201.")]
[StorableType("FB68525D-DD53-4BE7-A6B4-EC54E6FD0E64")]
public sealed class GreedyOrienteeringTourCreator : IntegerVectorCreator, IOrienteeringSolutionCreator {
public override bool CanChangeName { get { return false; } }
#region Parameter Properties
public ILookupParameter DistanceMatrixParameter {
get { return (ILookupParameter)Parameters["DistanceMatrix"]; }
}
public ILookupParameter ScoresParameter {
get { return (ILookupParameter)Parameters["Scores"]; }
}
public ILookupParameter MaximumDistanceParameter {
get { return (ILookupParameter)Parameters["MaximumDistance"]; }
}
public ILookupParameter StartingPointParameter {
get { return (ILookupParameter)Parameters["StartingPoint"]; }
}
public ILookupParameter TerminalPointParameter {
get { return (ILookupParameter)Parameters["TerminalPoint"]; }
}
public ILookupParameter PointVisitingCostsParameter {
get { return (ILookupParameter)Parameters["PointVisitingCosts"]; }
}
#endregion
[StorableConstructor]
private GreedyOrienteeringTourCreator(StorableConstructorFlag _) : base(_) { }
private GreedyOrienteeringTourCreator(GreedyOrienteeringTourCreator original, Cloner cloner)
: base(original, cloner) { }
public GreedyOrienteeringTourCreator()
: base() {
Parameters.Add(new LookupParameter("DistanceMatrix", "The matrix which contains the distances between the points."));
Parameters.Add(new LookupParameter("Scores", "The scores of the points."));
Parameters.Add(new LookupParameter("MaximumDistance", "The maximum distance constraint for a Orienteering solution."));
Parameters.Add(new LookupParameter("StartingPoint", "Index of the starting point."));
Parameters.Add(new LookupParameter("TerminalPoint", "Index of the ending point."));
Parameters.Add(new LookupParameter("PointVisitingCosts", "The costs for visiting a point."));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new GreedyOrienteeringTourCreator(this, cloner);
}
protected override IntegerVector Create(IRandom random, IntValue length, IntMatrix bounds) {
int startPoint = StartingPointParameter.ActualValue.Value;
int endPoint = TerminalPointParameter.ActualValue.Value;
int numPoints = ScoresParameter.ActualValue.Length;
var distances = DistanceMatrixParameter.ActualValue;
double pointVisitingCosts = PointVisitingCostsParameter.ActualValue.Value;
double maxDistance = MaximumDistanceParameter.ActualValue.Value;
var scores = ScoresParameter.ActualValue;
// Find all points within the maximum distance allowed (ellipse)
var feasiblePoints = (
from point in Enumerable.Range(0, numPoints)
let distance = distances[startPoint, point] + distances[point, endPoint] + pointVisitingCosts
let score = scores[point]
where distance <= maxDistance
where point != startPoint && point != endPoint
orderby score descending
select point
).ToList();
// Add the starting and terminus point
var tour = new List {
startPoint,
endPoint
};
double tourLength = distances[startPoint, endPoint];
// Add points in a greedy way
bool insertionPerformed = true;
while (insertionPerformed) {
insertionPerformed = false;
for (int i = 0; i < feasiblePoints.Count; i++) {
for (int insertPosition = 1; insertPosition < tour.Count; insertPosition++) {
// Create the candidate tour
double detour = distances.CalculateInsertionCosts(tour, insertPosition, feasiblePoints[i], pointVisitingCosts);
// If the insertion would be feasible, perform it
if (tourLength + detour <= maxDistance) {
tour.Insert(insertPosition, feasiblePoints[i]);
tourLength += detour;
feasiblePoints.RemoveAt(i);
insertionPerformed = true;
break;
}
}
if (insertionPerformed) break;
}
}
return new IntegerVector(tour.ToArray());
}
}
}