#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.Drawing; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.PermutationEncoding; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.PluginInfrastructure; using HeuristicLab.Problems.VehicleRouting.Encodings.Alba; using HeuristicLab.Problems.VehicleRouting.Encodings.General; using HeuristicLab.Problems.VehicleRouting.Encodings.Prins; namespace HeuristicLab.Problems.VehicleRouting { [Item("Vehicle Routing Problem", "Represents a Vehicle Routing Problem.")] [Creatable("Problems")] [StorableClass] public sealed class VehicleRoutingProblem : ParameterizedNamedItem, ISingleObjectiveProblem { public override Image ItemImage { get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Type; } } #region Parameter Properties public ValueParameter MaximizationParameter { get { return (ValueParameter)Parameters["Maximization"]; } } IParameter ISingleObjectiveProblem.MaximizationParameter { get { return MaximizationParameter; } } public ValueParameter CoordinatesParameter { get { return (ValueParameter)Parameters["Coordinates"]; } } public OptionalValueParameter DistanceMatrixParameter { get { return (OptionalValueParameter)Parameters["DistanceMatrix"]; } } public ValueParameter UseDistanceMatrixParameter { get { return (ValueParameter)Parameters["UseDistanceMatrix"]; } } public ValueParameter VehiclesParameter { get { return (ValueParameter)Parameters["Vehicles"]; } } public ValueParameter CapacityParameter { get { return (ValueParameter)Parameters["Capacity"]; } } public ValueParameter DemandParameter { get { return (ValueParameter)Parameters["Demand"]; } } public ValueParameter ReadyTimeParameter { get { return (ValueParameter)Parameters["ReadyTime"]; } } public ValueParameter DueTimeParameter { get { return (ValueParameter)Parameters["DueTime"]; } } public ValueParameter ServiceTimeParameter { get { return (ValueParameter)Parameters["ServiceTime"]; } } ValueParameter SolutionCreatorParameter { get { return (ValueParameter)Parameters["SolutionCreator"]; } } IParameter IProblem.SolutionCreatorParameter { get { return SolutionCreatorParameter; } } ValueParameter EvaluatorParameter { get { return (ValueParameter)Parameters["Evaluator"]; } } IParameter IProblem.EvaluatorParameter { get { return EvaluatorParameter; } } public IValueParameter FleetUsageFactor { get { return (IValueParameter)Parameters["EvalFleetUsageFactor"]; } } public IValueParameter TimeFactor { get { return (IValueParameter)Parameters["EvalTimeFactor"]; } } public IValueParameter DistanceFactor { get { return (IValueParameter)Parameters["EvalDistanceFactor"]; } } public IValueParameter OverloadPenalty { get { return (IValueParameter)Parameters["EvalOverloadPenalty"]; } } public IValueParameter TardinessPenalty { get { return (IValueParameter)Parameters["EvalTardinessPenalty"]; } } public OptionalValueParameter BestKnownQualityParameter { get { return (OptionalValueParameter)Parameters["BestKnownQuality"]; } } IParameter ISingleObjectiveProblem.BestKnownQualityParameter { get { return BestKnownQualityParameter; } } #endregion #region Properties public DoubleMatrix Coordinates { get { return CoordinatesParameter.Value; } set { CoordinatesParameter.Value = value; } } public DoubleMatrix DistanceMatrix { get { return DistanceMatrixParameter.Value; } set { DistanceMatrixParameter.Value = value; } } public BoolValue UseDistanceMatrix { get { return UseDistanceMatrixParameter.Value; } set { UseDistanceMatrixParameter.Value = value; } } public IntValue Vehicles { get { return VehiclesParameter.Value; } set { VehiclesParameter.Value = value; } } public DoubleValue Capacity { get { return CapacityParameter.Value; } set { CapacityParameter.Value = value; } } public DoubleArray Demand { get { return DemandParameter.Value; } set { DemandParameter.Value = value; } } public DoubleArray ReadyTime { get { return ReadyTimeParameter.Value; } set { ReadyTimeParameter.Value = value; } } public DoubleArray DueTime { get { return DueTimeParameter.Value; } set { DueTimeParameter.Value = value; } } public DoubleArray ServiceTime { get { return ServiceTimeParameter.Value; } set { ServiceTimeParameter.Value = value; } } public DoubleValue BestKnownQuality { get { return BestKnownQualityParameter.Value; } set { BestKnownQualityParameter.Value = value; } } IVRPCreator SolutionCreator { get { return SolutionCreatorParameter.Value; } set { SolutionCreatorParameter.Value = value; } } ISolutionCreator IProblem.SolutionCreator { get { return SolutionCreatorParameter.Value; } } IVRPEvaluator Evaluator { get { return EvaluatorParameter.Value; } set { EvaluatorParameter.Value = value; } } ISingleObjectiveEvaluator ISingleObjectiveProblem.Evaluator { get { return EvaluatorParameter.Value; } } IEvaluator IProblem.Evaluator { get { return EvaluatorParameter.Value; } } public IEnumerable Operators { get { return operators; } } private BestVRPSolutionAnalyzer BestVRPSolutionAnalyzer { get { return operators.OfType().FirstOrDefault(); } } #endregion [Storable] private List operators; [StorableConstructor] private VehicleRoutingProblem(bool deserializing) : base(deserializing) { } public VehicleRoutingProblem() : base() { IVRPCreator creator = new RandomCreator(); IVRPEvaluator evaluator = new VRPEvaluator(); Parameters.Add(new ValueParameter("Maximization", "Set to false as the Vehicle Routing Problem is a minimization problem.", new BoolValue(false))); Parameters.Add(new ValueParameter("Coordinates", "The x- and y-Coordinates of the cities.", new DoubleMatrix())); Parameters.Add(new OptionalValueParameter("DistanceMatrix", "The matrix which contains the distances between the cities.")); Parameters.Add(new ValueParameter("UseDistanceMatrix", "True if a distance matrix should be calculated and used for evaluation, otherwise false.", new BoolValue(true))); Parameters.Add(new ValueParameter("Vehicles", "The number of vehicles.", new IntValue(0))); Parameters.Add(new ValueParameter("Capacity", "The capacity of each vehicle.", new DoubleValue(0))); Parameters.Add(new ValueParameter("Demand", "The demand of each customer.", new DoubleArray())); Parameters.Add(new ValueParameter("ReadyTime", "The ready time of each customer.", new DoubleArray())); Parameters.Add(new ValueParameter("DueTime", "The due time of each customer.", new DoubleArray())); Parameters.Add(new ValueParameter("ServiceTime", "The service time of each customer.", new DoubleArray())); Parameters.Add(new OptionalValueParameter("BestKnownQuality", "The quality of the best known solution of this VRP instance.")); Parameters.Add(new ValueParameter("EvalFleetUsageFactor", "The fleet usage factor considered in the evaluation.", new DoubleValue(100))); Parameters.Add(new ValueParameter("EvalTimeFactor", "The time factor considered in the evaluation.", new DoubleValue(0))); Parameters.Add(new ValueParameter("EvalDistanceFactor", "The distance factor considered in the evaluation.", new DoubleValue(1))); Parameters.Add(new ValueParameter("EvalOverloadPenalty", "The overload penalty considered in the evaluation.", new DoubleValue(100))); Parameters.Add(new ValueParameter("EvalTardinessPenalty", "The tardiness penalty considered in the evaluation.", new DoubleValue(100))); Parameters.Add(new ValueParameter("SolutionCreator", "The operator which should be used to create new VRP solutions.", creator)); Parameters.Add(new ValueParameter("Evaluator", "The operator which should be used to evaluate VRP solutions.", evaluator)); creator.VRPToursParameter.ActualName = "VRPTours"; evaluator.QualityParameter.ActualName = "VRPQuality"; InitializeRandomVRPInstance(); ParameterizeSolutionCreator(); ParameterizeEvaluator(); InitializeOperators(); AttachEventHandlers(); } public override IDeepCloneable Clone(Cloner cloner) { VehicleRoutingProblem clone = (VehicleRoutingProblem)base.Clone(cloner); clone.operators = operators.Select(x => (IOperator)cloner.Clone(x)).ToList(); clone.DistanceMatrixParameter.Value = DistanceMatrixParameter.Value; clone.AttachEventHandlers(); return clone; } #region Events public event EventHandler SolutionCreatorChanged; private void OnSolutionCreatorChanged() { EventHandler handler = SolutionCreatorChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler EvaluatorChanged; private void OnEvaluatorChanged() { EventHandler handler = EvaluatorChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler OperatorsChanged; private void OnOperatorsChanged() { EventHandler handler = OperatorsChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler Reset; private void OnReset() { EventHandler handler = Reset; if (handler != null) handler(this, EventArgs.Empty); } void VehiclesValue_ValueChanged(object sender, EventArgs e) { ParameterizeSolutionCreator(); } private void CoordinatesParameter_ValueChanged(object sender, EventArgs e) { Coordinates.ItemChanged += new EventHandler>(Coordinates_ItemChanged); Coordinates.Reset += new EventHandler(Coordinates_Reset); ParameterizeSolutionCreator(); ClearDistanceMatrix(); } private void Coordinates_ItemChanged(object sender, EventArgs e) { ClearDistanceMatrix(); } private void Coordinates_Reset(object sender, EventArgs e) { ParameterizeSolutionCreator(); ClearDistanceMatrix(); } private void SolutionCreatorParameter_ValueChanged(object sender, EventArgs e) { ParameterizeSolutionCreator(); ParameterizeEvaluator(); ParameterizeAnalyzer(); ParameterizeOperators(); OnSolutionCreatorChanged(); } private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) { ParameterizeEvaluator(); ParameterizeAnalyzer(); ParameterizeOperators(); } private void EvaluatorParameter_ValueChanged(object sender, EventArgs e) { Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged); ParameterizeEvaluator(); UpdateMoveEvaluators(); ParameterizeAnalyzer(); OnEvaluatorChanged(); } private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) { ParameterizeAnalyzer(); } private void TranslocationMoveParameter_ActualNameChanged(object sender, EventArgs e) { string name = ((ILookupParameter)sender).ActualName; foreach (IPermutationTranslocationMoveOperator op in Operators.OfType()) { op.TranslocationMoveParameter.ActualName = name; } } #endregion #region Helpers [StorableHook(HookType.AfterDeserialization)] private void AfterDeserializationHook() { AttachEventHandlers(); } private void AttachEventHandlers() { CoordinatesParameter.ValueChanged += new EventHandler(CoordinatesParameter_ValueChanged); Vehicles.ValueChanged += new EventHandler(VehiclesValue_ValueChanged); Coordinates.ItemChanged += new EventHandler>(Coordinates_ItemChanged); Coordinates.Reset += new EventHandler(Coordinates_Reset); SolutionCreatorParameter.ValueChanged += new EventHandler(SolutionCreatorParameter_ValueChanged); EvaluatorParameter.ValueChanged += new EventHandler(EvaluatorParameter_ValueChanged); Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged); } private void InitializeOperators() { operators = new List(); operators.Add(new BestVRPSolutionAnalyzer()); ParameterizeAnalyzer(); operators.AddRange(ApplicationManager.Manager.GetInstances().Cast()); ParameterizeOperators(); UpdateMoveEvaluators(); InitializeMoveGenerators(); } private void InitializeMoveGenerators() { foreach (IAlbaTranslocationMoveOperator op in Operators.OfType()) { if (op is IMoveGenerator) { op.TranslocationMoveParameter.ActualNameChanged += new EventHandler(TranslocationMoveParameter_ActualNameChanged); } } } private void UpdateMoveEvaluators() { ParameterizeOperators(); OnOperatorsChanged(); } private void ParameterizeSolutionCreator() { SolutionCreator.VehiclesParameter.ActualName = VehiclesParameter.Name; SolutionCreator.CoordinatesParameter.ActualName = CoordinatesParameter.Name; Evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name; Evaluator.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name; SolutionCreator.CapacityParameter.ActualName = CapacityParameter.Name; SolutionCreator.DemandParameter.ActualName = DemandParameter.Name; SolutionCreator.ReadyTimeParameter.ActualName = ReadyTimeParameter.Name; SolutionCreator.DueTimeParameter.ActualName = DueTimeParameter.Name; SolutionCreator.ServiceTimeParameter.ActualName = ServiceTimeParameter.Name; } private void ParameterizeEvaluator() { Evaluator.VRPToursParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; Evaluator.CoordinatesParameter.ActualName = CoordinatesParameter.Name; Evaluator.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name; Evaluator.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name; Evaluator.VehiclesParameter.ActualName = VehiclesParameter.Name; Evaluator.CapacityParameter.ActualName = CapacityParameter.Name; Evaluator.DemandParameter.ActualName = DemandParameter.Name; Evaluator.ReadyTimeParameter.ActualName = ReadyTimeParameter.Name; Evaluator.DueTimeParameter.ActualName = DueTimeParameter.Name; Evaluator.ServiceTimeParameter.ActualName = ServiceTimeParameter.Name; Evaluator.FleetUsageFactor.ActualName = FleetUsageFactor.Name; Evaluator.TimeFactor.ActualName = TimeFactor.Name; Evaluator.DistanceFactor.ActualName = DistanceFactor.Name; Evaluator.OverloadPenalty.ActualName = OverloadPenalty.Name; Evaluator.TardinessPenalty.ActualName = TardinessPenalty.Name; } private void ParameterizeAnalyzer() { BestVRPSolutionAnalyzer.CoordinatesParameter.ActualName = CoordinatesParameter.Name; BestVRPSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName; BestVRPSolutionAnalyzer.DistanceParameter.ActualName = Evaluator.DistanceParameter.ActualName; BestVRPSolutionAnalyzer.OverloadParameter.ActualName = Evaluator.OverloadParameter.ActualName; BestVRPSolutionAnalyzer.TardinessParameter.ActualName = Evaluator.TardinessParameter.ActualName; BestVRPSolutionAnalyzer.VRPToursParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; BestVRPSolutionAnalyzer.ResultsParameter.ActualName = "Results"; } private void ParameterizeOperators() { foreach (IVRPOperator op in Operators.OfType()) { if(op.CoordinatesParameter != null) op.CoordinatesParameter.ActualName = CoordinatesParameter.Name; if(op.DistanceMatrixParameter != null) op.DistanceMatrixParameter.ActualName = DistanceMatrixParameter.Name; if(op.UseDistanceMatrixParameter != null) op.UseDistanceMatrixParameter.ActualName = UseDistanceMatrixParameter.Name; if(op.VehiclesParameter != null) op.VehiclesParameter.ActualName = VehiclesParameter.Name; if(op.CapacityParameter != null) op.CapacityParameter.ActualName = CapacityParameter.Name; if(op.DemandParameter != null) op.DemandParameter.ActualName = DemandParameter.Name; if(op.ReadyTimeParameter != null) op.ReadyTimeParameter.ActualName = ReadyTimeParameter.Name; if(op.DueTimeParameter != null) op.DueTimeParameter.ActualName = DueTimeParameter.Name; if(op.ServiceTimeParameter != null) op.ServiceTimeParameter.ActualName = ServiceTimeParameter.Name; } foreach (IVRPMoveOperator op in Operators.OfType()) { op.VRPToursParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; } foreach (IPrinsOperator op in Operators.OfType()) { op.FleetUsageFactor.ActualName = FleetUsageFactor.Name; op.TimeFactor.ActualName = TimeFactor.Name; op.DistanceFactor.ActualName = DistanceFactor.Name; op.OverloadPenalty.ActualName = OverloadPenalty.Name; op.TardinessPenalty.ActualName = TardinessPenalty.Name; } foreach (IVRPMoveEvaluator op in Operators.OfType()) { op.FleetUsageFactor.ActualName = FleetUsageFactor.Name; op.TimeFactor.ActualName = TimeFactor.Name; op.DistanceFactor.ActualName = DistanceFactor.Name; op.OverloadPenalty.ActualName = OverloadPenalty.Name; op.TardinessPenalty.ActualName = TardinessPenalty.Name; op.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName; op.VRPToursParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; } string translocationMove = Operators.OfType().OfType().First().TranslocationMoveParameter.ActualName; foreach (IAlbaTranslocationMoveOperator op in Operators.OfType()) op.TranslocationMoveParameter.ActualName = translocationMove; foreach (IVRPCrossover op in Operators.OfType()) { op.ParentsParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; op.ChildParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; } foreach (IVRPManipulator op in Operators.OfType()) { op.VRPToursParameter.ActualName = SolutionCreator.VRPToursParameter.ActualName; } } private void ClearDistanceMatrix() { DistanceMatrixParameter.Value = null; } #endregion public void ImportFromSolomon(string solomonFileName) { SolomonParser parser = new SolomonParser(solomonFileName); parser.Parse(); this.Name = parser.ProblemName; Coordinates = new DoubleMatrix(parser.Coordinates); Vehicles.Value = parser.Vehicles; Capacity.Value = parser.Capacity; Demand = new DoubleArray(parser.Demands); ReadyTime = new DoubleArray(parser.Readytimes); DueTime = new DoubleArray(parser.Duetimes); ServiceTime = new DoubleArray(parser.Servicetimes); OnReset(); } public void ImportFromTSPLib(string tspFileName) { TSPLIBParser parser = new TSPLIBParser(tspFileName); parser.Parse(); this.Name = parser.Name; int problemSize = parser.Demands.Length; Coordinates = new DoubleMatrix(parser.Vertices); Vehicles.Value = problemSize - 1; Capacity.Value = parser.Capacity; Demand = new DoubleArray(parser.Demands); ReadyTime = new DoubleArray(problemSize); DueTime = new DoubleArray(problemSize); ServiceTime = new DoubleArray(problemSize); for (int i = 0; i < problemSize; i++) { ReadyTime[i] = 0; DueTime[i] = int.MaxValue; ServiceTime[i] = 0; } if (parser.Depot != 1) throw new Exception("Invalid depot specification"); if (parser.WeightType != TSPLIBParser.TSPLIBEdgeWeightType.EUC_2D) throw new Exception("Invalid weight type"); OnReset(); } private void InitializeRandomVRPInstance() { System.Random rand = new System.Random(); int cities = 100; Coordinates = new DoubleMatrix(cities + 1, 2); Demand = new DoubleArray(cities + 1); DueTime = new DoubleArray(cities + 1); ReadyTime = new DoubleArray(cities + 1); ServiceTime = new DoubleArray(cities + 1); Vehicles.Value = 100; Capacity.Value = 200; for (int i = 0; i <= cities; i++) { Coordinates[i, 0] = rand.Next(0, 100); Coordinates[i, 1] = rand.Next(0, 100); if (i == 0) { Demand[i] = 0; DueTime[i] = Int16.MaxValue; ReadyTime[i] = 0; ServiceTime[i] = 0; } else { Demand[i] = rand.Next(10, 50); DueTime[i] = rand.Next((int)Math.Ceiling(VRPUtilities.CalculateDistance(0, i, Coordinates)), 1200); ReadyTime[i] = DueTime[i] - rand.Next(0, 100); ServiceTime[i] = 90; } } } } }