#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.Problems.VehicleRouting.Interfaces;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Core;
using HeuristicLab.Parameters;
using HeuristicLab.Data;
using HeuristicLab.Optimization;
using HeuristicLab.PluginInfrastructure;
using HeuristicLab.Problems.VehicleRouting.Variants;
using HeuristicLab.Problems.VehicleRouting.Encodings;
using HeuristicLab.Common;
using HeuristicLab.Problems.VehicleRouting.ProblemInstances;
using HeuristicLab.Problems.VehicleRouting;
using HeuristicLab.Problems.VehicleRouting.Encodings.General;
using HeuristicLab.Problems.VehicleRouting.Encodings.Potvin;
namespace HeuristicLab.PDPSimulation.Operators {
public class DialARideEvaluation : DynPDPEvaluation {
public List LeadTimes { get; private set; }
public DialARideEvaluation() {
LeadTimes = new List();
}
}
[Item("DialARideEvaluator", "Represents a dynamic multi depot CVRPPDTW evaluator.")]
[StorableClass]
public class DialARideEvaluator: DynPDPEvaluator {
public ILookupParameter LeadTimeParameter {
get { return (ILookupParameter)Parameters["LeadTime"]; }
}
public IValueParameter LeadTimeFactorParameter {
get { return (IValueParameter)Parameters["LeadTimeFactor"]; }
}
protected override VRPEvaluation CreateTourEvaluation() {
return new DialARideEvaluation();
}
protected override void EvaluateTour(VRPEvaluation eval, IVRPProblemInstance instance, Tour tour, IVRPEncoding solution) {
TourInsertionInfo tourInfo = new TourInsertionInfo(solution.GetVehicleAssignment(solution.GetTourIndex(tour)));
eval.InsertionInfo.AddTourInsertionInfo(tourInfo);
double originalQuality = eval.Quality;
IHeterogenousCapacitatedProblemInstance cvrpInstance = instance as IHeterogenousCapacitatedProblemInstance;
DoubleArray demand = instance.Demand;
ITimeWindowedProblemInstance vrptw = instance as ITimeWindowedProblemInstance;
DoubleArray dueTime = vrptw.DueTime;
DoubleArray readyTime = vrptw.ReadyTime;
DoubleArray serviceTimes = vrptw.ServiceTime;
IPickupAndDeliveryProblemInstance pdp = instance as IPickupAndDeliveryProblemInstance;
IntArray pickupDeliveryLocation = pdp.PickupDeliveryLocation;
IMultiDepotProblemInstance mdp = instance as IMultiDepotProblemInstance;
IntArray vehicleAssignment = mdp.VehicleDepotAssignment;
int depots = mdp.Depots.Value;
double time = 0.0;
double waitingTime = 0.0;
double serviceTime = 0.0;
double tardiness = 0.0;
double overweight = 0.0;
double distance = 0.0;
int tourIndex = solution.GetTourIndex(tour);
int vehicle = solution.GetVehicleAssignment(tourIndex);
int depot = vehicleAssignment[vehicle];
double capacity = cvrpInstance.Capacity[vehicle];
double currentLoad = 0.0;
Dictionary stops = new Dictionary();
int pickupViolations = 0;
double tourStartTime = readyTime[depot];
time = tourStartTime;
WaitingStrategy waitingStrategy = (instance as DynPDPProblemInstance).WaitingStrategy;
List leadTimes = new List();
//simulate a tour
int count = tour.Stops.Count;
if (!(instance as DynPDPProblemInstance).RelocateBackToDepot)
count -= 1;
for (int i = 0; i <= count; i++) {
int start = 0;
if (i > 0)
start = tour.Stops[i - 1];
int end = 0;
if (i < tour.Stops.Count)
end = tour.Stops[i];
//Waiting strategy...
if (end != 0) {
double waitAction = waitingStrategy.GetBufferTime(time, instance as DynPDPProblemInstance, solution, tour, i);
time += waitAction;
}
double commitmentTime = time;
//drive there
double currentDistace = vrptw.GetDistance(start, end, solution);
time += currentDistace;
distance += currentDistace;
double arrivalTime = time;
int endIndex;
if (end == 0)
endIndex = depot;
else
endIndex = end + depots - 1;
//check if it was serviced on time
if (time > dueTime[endIndex])
tardiness += Math.Min(1000000, Math.Pow((vrptw.TardinessPenalty.Value * Math.E), (time - dueTime[endIndex])) - 1.0);
//wait
double currentWaitingTime = 0.0;
if (time < readyTime[endIndex])
currentWaitingTime = readyTime[endIndex] - time;
double waitTime = readyTime[endIndex] - time;
waitingTime += currentWaitingTime;
time += currentWaitingTime;
double spareTime = dueTime[endIndex] - time;
double arrivalSpareCapacity = capacity - currentLoad;
if (end > 0) {
//service
double currentServiceTime = serviceTimes[end - 1];
serviceTime += currentServiceTime;
time += currentServiceTime;
//Pickup / deliver
int location = pickupDeliveryLocation[end - 1];
bool validPickupDelivery =
validPickupDelivery =
((demand[end - 1] >= 0) ||
(end == location) ||
(location <= 0 && vehicle == -location) ||
(stops.ContainsKey(location)));
if (validPickupDelivery) {
currentLoad += demand[end - 1];
if (demand[end - 1] < 0) {
double pickupReady = 0;
if (location > 0) {
pickupReady = readyTime[location + depots - 1];
}
leadTimes.Add(time - currentServiceTime - pickupReady);
}
} else {
pickupViolations++;
}
if (currentLoad > capacity)
overweight += currentLoad - capacity;
}
double spareCapacity = capacity - currentLoad;
CVRPPDTWInsertionInfo stopInfo = new DynPDPInsertionInfo(start, end, spareCapacity, tourStartTime,
arrivalTime, time, spareTime, waitTime, commitmentTime, new List(stops.Keys), arrivalSpareCapacity);
tourInfo.AddStopInsertionInfo(stopInfo);
stops.Add(end, true);
}
if(!(instance as DynPDPProblemInstance).VehicleUsed[vehicle])
eval.Quality += instance.FleetUsageFactor.Value;
eval.Quality += instance.DistanceFactor.Value * distance;
eval.Distance += distance;
eval.VehicleUtilization += 1;
double leadTime = 0;
if (leadTimes.Count > 0)
leadTime = leadTimes.Sum();
eval.Quality += leadTime * LeadTimeFactorParameter.Value.Value;
(eval as CVRPEvaluation).Overload += overweight;
double tourPenalty = 0;
double penalty = overweight * cvrpInstance.OverloadPenalty.Value;
eval.Penalty += penalty;
eval.Quality += penalty;
tourPenalty += penalty;
//(eval as CVRPTWEvaluation).Tardiness += tardiness;
(eval as CVRPTWEvaluation).TravelTime += time;
//penalty = tardiness;
//eval.Penalty += penalty;
eval.Quality += tardiness;
//tourPenalty += penalty;
(eval as CVRPPDTWEvaluation).PickupViolations += pickupViolations;
penalty = pickupViolations * pdp.PickupViolationPenalty.Value;
eval.Penalty += penalty;
tourPenalty += penalty;
eval.Quality += penalty;
eval.Quality += time * vrptw.TimeFactor.Value;
tourInfo.Penalty = tourPenalty;
tourInfo.Quality = eval.Quality - originalQuality;
(eval as DialARideEvaluation).LeadTimes.AddRange(leadTimes);
}
protected override double GetTourInsertionCosts(IVRPProblemInstance instance, IVRPEncoding solution, TourInsertionInfo tourInsertionInfo, int index, int customer,
out bool feasible) {
TourEncoding individual = null;
if (solution is TourEncoding)
individual = solution as TourEncoding;
else {
individual = new PotvinEncoding(instance);
individual.Tours.AddRange(solution.GetTours());
}
int tourIdx = -1;
for (int i = 0; i < individual.Tours.Count; i++) {
if (solution.GetVehicleAssignment(i) == tourInsertionInfo.Vehicle)
tourIdx = i;
}
Tour tour = individual.Tours[tourIdx];
tour.Stops.Insert(index, customer);
VRPEvaluation newEval = instance.EvaluateTour(tour, individual);
tour.Stops.RemoveAt(index);
feasible = instance.Feasible(newEval);
return newEval.Quality - tourInsertionInfo.Quality;
}
protected override void InitResultParameters() {
base.InitResultParameters();
LeadTimeParameter.ActualValue = new DoubleValue(0);
}
protected override void SetResultParameters(VRPEvaluation tourEvaluation) {
base.SetResultParameters(tourEvaluation);
double leadTime = 0;
if((tourEvaluation as DialARideEvaluation).LeadTimes.Count > 0)
leadTime = (tourEvaluation as DialARideEvaluation).LeadTimes.Average();
LeadTimeParameter.ActualValue.Value = leadTime;
}
[StorableConstructor]
protected DialARideEvaluator(bool deserializing) : base(deserializing) { }
public DialARideEvaluator() {
Parameters.Add(new LookupParameter("LeadTime", "The total lead time."));
Parameters.Add(new ValueParameter("LeadTimeFactor", "The lead time factor considered in the evaluation.", new DoubleValue(0)));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new DialARideEvaluator(this, cloner);
}
protected DialARideEvaluator(DialARideEvaluator original, Cloner cloner)
: base(original, cloner) {
}
}
}