#region License Information /* HeuristicLab * Copyright (C) 2002-2010 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; using System.Collections.Generic; using System.Linq; using System.Text; using HeuristicLab.Operators; using HeuristicLab.Data; using HeuristicLab.Core; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.VehicleRouting.Encodings; namespace HeuristicLab.Problems.VehicleRouting { public struct TourEvaluation { public double Quality { get; set; } public double VehcilesUtilized { get; set; } public double TravelTime { get; set; } public double Distance { get; set; } public double Overload { get; set; } public double Tardiness { get; set; } } [Item("VRPEvaluator", "Evaluates solutions for the VRP problem.")] [StorableClass] public sealed class VRPEvaluator : SingleSuccessorOperator, IVRPEvaluator { #region ISingleObjectiveEvaluator Members public ILookupParameter QualityParameter { get { return (ILookupParameter)Parameters["Quality"]; } } #endregion public ILookupParameter VehcilesUtilizedParameter { get { return (ILookupParameter)Parameters["VehiclesUtilized"]; } } public ILookupParameter TravelTimeParameter { get { return (ILookupParameter)Parameters["TravelTime"]; } } public ILookupParameter DistanceParameter { get { return (ILookupParameter)Parameters["Distance"]; } } public ILookupParameter OverloadParameter { get { return (ILookupParameter)Parameters["Overload"]; } } public ILookupParameter TardinessParameter { get { return (ILookupParameter)Parameters["Tardiness"]; } } public ILookupParameter VRPSolutionParameter { get { return (ILookupParameter)Parameters["VRPSolution"]; } } public ILookupParameter CoordinatesParameter { get { return (ILookupParameter)Parameters["Coordinates"]; } } public ILookupParameter DistanceMatrixParameter { get { return (ILookupParameter)Parameters["DistanceMatrix"]; } } public ILookupParameter UseDistanceMatrixParameter { get { return (ILookupParameter)Parameters["UseDistanceMatrix"]; } } public ILookupParameter VehiclesParameter { get { return (ILookupParameter)Parameters["Vehicles"]; } } public ILookupParameter CapacityParameter { get { return (ILookupParameter)Parameters["Capacity"]; } } /*public ILookupParameter MaxTravelTimeParameter { get { return (ILookupParameter)Parameters["MaxTravelTime"]; } } */ public ILookupParameter DemandParameter { get { return (ILookupParameter)Parameters["Demand"]; } } public ILookupParameter ReadyTimeParameter { get { return (ILookupParameter)Parameters["ReadyTime"]; } } public ILookupParameter DueTimeParameter { get { return (ILookupParameter)Parameters["DueTime"]; } } public ILookupParameter ServiceTimeParameter { get { return (ILookupParameter)Parameters["ServiceTime"]; } } public IValueParameter FleetUsageFactor { get { return (IValueParameter)Parameters["FleetUsageFactor"]; } } public IValueParameter TimeFactor { get { return (IValueParameter)Parameters["TimeFactor"]; } } public IValueParameter DistanceFactor { get { return (IValueParameter)Parameters["DistanceFactor"]; } } /*public IValueParameter TimePenalty { get { return (IValueParameter)Parameters["TimePenalty"]; } } */ public IValueParameter OverloadPenalty { get { return (IValueParameter)Parameters["OverloadPenalty"]; } } public IValueParameter TardinessPenalty { get { return (IValueParameter)Parameters["TardinessPenalty"]; } } public VRPEvaluator() : base() { Parameters.Add(new LookupParameter("Quality", "The evaluated quality of the VRP solution.")); Parameters.Add(new LookupParameter("VehiclesUtilized", "The number of vehicles utilized.")); Parameters.Add(new LookupParameter("TravelTime", "The total travel time.")); Parameters.Add(new LookupParameter("Distance", "The distance.")); Parameters.Add(new LookupParameter("Overload", "The overload.")); Parameters.Add(new LookupParameter("Tardiness", "The tardiness.")); Parameters.Add(new LookupParameter("VRPSolution", "The VRP solution which should be evaluated.")); Parameters.Add(new LookupParameter("Coordinates", "The coordinates of the cities.")); Parameters.Add(new LookupParameter("DistanceMatrix", "The matrix which contains the distances between the cities.")); Parameters.Add(new LookupParameter("UseDistanceMatrix", "True if a distance matrix should be calculated and used for evaluation, otherwise false.")); Parameters.Add(new LookupParameter("Vehicles", "The number of vehicles.")); Parameters.Add(new LookupParameter("Capacity", "The capacity of each vehicle.")); //Parameters.Add(new LookupParameter("MaxTravelTime", "The maximum travel time of each route.")); Parameters.Add(new LookupParameter("Demand", "The demand of each customer.")); Parameters.Add(new LookupParameter("ReadyTime", "The ready time of each customer.")); Parameters.Add(new LookupParameter("DueTime", "The due time of each customer.")); Parameters.Add(new LookupParameter("ServiceTime", "The service time of each customer.")); Parameters.Add(new ValueParameter("FleetUsageFactor", "The fleet usage factor considered in the evaluation.", new DoubleValue(0))); Parameters.Add(new ValueParameter("TimeFactor", "The time factor considered in the evaluation.", new DoubleValue(0))); Parameters.Add(new ValueParameter("DistanceFactor", "The distance factor considered in the evaluation.", new DoubleValue(1))); //Parameters.Add(new ValueParameter("TimePenalty", "The time penalty considered in the evaluation.", new DoubleValue(10))); Parameters.Add(new ValueParameter("OverloadPenalty", "The overload penalty considered in the evaluation.", new DoubleValue(50))); Parameters.Add(new ValueParameter("TardinessPenalty", "The tardiness penalty considered in the evaluation.", new DoubleValue(50))); } private double CalculateFleetUsage() { IVRPEncoding vrpSolution = VRPSolutionParameter.ActualValue; return vrpSolution.Tours.Count; } private static double CalculateDistance(int start, int end, DoubleMatrix coordinates) { double distance = 0.0; distance = Math.Sqrt( Math.Pow(coordinates[start, 0] - coordinates[end, 0], 2) + Math.Pow(coordinates[start, 1] - coordinates[end, 1], 2)); return distance; } private static DoubleMatrix CreateDistanceMatrix(DoubleMatrix coordinates) { DoubleMatrix distanceMatrix = new DoubleMatrix(coordinates.Rows, coordinates.Rows); for (int i = 0; i < distanceMatrix.Rows; i++) { for (int j = i; j < distanceMatrix.Columns; j++) { double distance = CalculateDistance(i, j, coordinates); distanceMatrix[i, j] = distance; distanceMatrix[j, i] = distance; } } return distanceMatrix; } private static double GetDistance(int start, int end, DoubleMatrix coordinates, ILookupParameter distanceMatrix, BoolValue useDistanceMatrix) { double distance = 0.0; if (useDistanceMatrix.Value) { if (distanceMatrix.ActualValue == null) { distanceMatrix.ActualValue = CreateDistanceMatrix(coordinates); } distance = distanceMatrix.ActualValue[start, end]; } else { distance = CalculateDistance(start, end, coordinates); } return distance; } private static TourEvaluation EvaluateTour(Tour tour, DoubleArray dueTimeArray, DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity, DoubleValue fleetUsageFactor, DoubleValue timeFactor, DoubleValue distanceFactor, DoubleValue overloadPenalty, DoubleValue tardinessPenalty, DoubleMatrix coordinates, ILookupParameter distanceMatrix, BoolValue useDistanceMatrix) { TourEvaluation eval = new TourEvaluation(); double quality = 0.0; double time = 0.0; double distance = 0.0; double waitingTime = 0.0; double serviceTime = 0.0; double delivered = 0.0; double overweight = 0.0; double tardiness = 0.0; //simulate a tour, start and end at depot for (int i = 1; i < tour.Count; i++) { int start = tour[i - 1].Value; int end = tour[i].Value; //drive there double currentDistace = GetDistance(start, end, coordinates, distanceMatrix, useDistanceMatrix); distance += currentDistace; time += currentDistace; //check if it was serviced on time if (time > dueTimeArray[end]) tardiness += time - dueTimeArray[end]; //wait double currentWaitingTime = 0.0; if (time < readyTimeArray[end]) currentWaitingTime = readyTimeArray[end] - time; waitingTime += currentWaitingTime; time += currentWaitingTime; //service delivered += demandArray[end]; double currentServiceTime = serviceTimeArray[end]; serviceTime += currentServiceTime; time += currentServiceTime; } if (delivered > capacity.Value) { overweight = delivered - capacity.Value; } //Fleet usage quality += fleetUsageFactor.Value; //Travel time quality += timeFactor.Value * time; //Distance quality += distanceFactor.Value * distance; //Penalties quality += overloadPenalty.Value * overweight; quality += tardinessPenalty.Value * tardiness; eval.Distance = distance; eval.TravelTime = time; eval.VehcilesUtilized = 1; eval.Overload = overweight; eval.Tardiness = tardiness; eval.Quality = quality; return eval; } public static TourEvaluation Evaluate(IVRPEncoding solution, DoubleArray dueTimeArray, DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity, DoubleValue fleetUsageFactor, DoubleValue timeFactor, DoubleValue distanceFactor, DoubleValue overloadPenalty, DoubleValue tardinessPenalty, DoubleMatrix coordinates, ILookupParameter distanceMatrix, BoolValue useDistanceMatrix) { TourEvaluation sumEval = new TourEvaluation(); sumEval.Distance = 0; sumEval.Quality = 0; sumEval.TravelTime = 0; sumEval.VehcilesUtilized = 0; sumEval.Overload = 0; sumEval.Tardiness = 0; foreach (Tour tour in solution.Tours) { TourEvaluation eval = EvaluateTour(tour, dueTimeArray, serviceTimeArray, readyTimeArray, demandArray, capacity, fleetUsageFactor, timeFactor, distanceFactor, overloadPenalty, tardinessPenalty, coordinates, distanceMatrix, useDistanceMatrix); sumEval.Quality += eval.Quality; sumEval.Distance += eval.Distance; sumEval.TravelTime += eval.TravelTime; sumEval.VehcilesUtilized += eval.VehcilesUtilized; sumEval.Overload += eval.Overload; sumEval.Tardiness += eval.Tardiness; } if (sumEval.Quality < sumEval.Distance) { } return sumEval; } public sealed override IOperation Apply() { IVRPEncoding solution = VRPSolutionParameter.ActualValue; TourEvaluation sumEval = Evaluate(solution, DueTimeParameter.ActualValue, ServiceTimeParameter.ActualValue, ReadyTimeParameter.ActualValue, DemandParameter.ActualValue, CapacityParameter.ActualValue, FleetUsageFactor.Value, TimeFactor.Value, DistanceFactor.Value, OverloadPenalty.Value, TardinessPenalty.Value, CoordinatesParameter.ActualValue, DistanceMatrixParameter, UseDistanceMatrixParameter.ActualValue); QualityParameter.ActualValue = new DoubleValue(sumEval.Quality); VehcilesUtilizedParameter.ActualValue = new DoubleValue(sumEval.VehcilesUtilized); TravelTimeParameter.ActualValue = new DoubleValue(sumEval.TravelTime); DistanceParameter.ActualValue = new DoubleValue(sumEval.Distance); OverloadParameter.ActualValue = new DoubleValue(sumEval.Overload); TardinessParameter.ActualValue = new DoubleValue(sumEval.Tardiness); return base.Apply(); } } }