#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.Interfaces; using HeuristicLab.Problems.VehicleRouting.Parsers; using HeuristicLab.Problems.VehicleRouting.ProblemInstances; using HeuristicLab.Problems.VehicleRouting.Variants; namespace HeuristicLab.Problems.VehicleRouting { [Item("Vehicle Routing Problem", "Represents a Vehicle Routing Problem.")] [Creatable("Problems")] [StorableClass] public sealed class VehicleRoutingProblem : ParameterizedNamedItem, ISingleObjectiveHeuristicOptimizationProblem, IStorableContent { public string Filename { get; set; } public override Image ItemImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.Type; } } #region Parameter Properties public ValueParameter MaximizationParameter { get { return (ValueParameter)Parameters["Maximization"]; } } IParameter ISingleObjectiveHeuristicOptimizationProblem.MaximizationParameter { get { return MaximizationParameter; } } public ValueParameter ProblemInstanceParameter { get { return (ValueParameter)Parameters["ProblemInstance"]; } } public OptionalValueParameter BestKnownQualityParameter { get { return (OptionalValueParameter)Parameters["BestKnownQuality"]; } } IParameter ISingleObjectiveHeuristicOptimizationProblem.BestKnownQualityParameter { get { return BestKnownQualityParameter; } } public OptionalValueParameter BestKnownSolutionParameter { get { return (OptionalValueParameter)Parameters["BestKnownSolution"]; } } public IValueParameter SolutionCreatorParameter { get { return (IValueParameter)Parameters["SolutionCreator"]; } } IParameter IHeuristicOptimizationProblem.SolutionCreatorParameter { get { return SolutionCreatorParameter; } } public IValueParameter EvaluatorParameter { get { return (IValueParameter)Parameters["Evaluator"]; } } IParameter IHeuristicOptimizationProblem.EvaluatorParameter { get { return EvaluatorParameter; } } #endregion #region Properties public IVRPProblemInstance ProblemInstance { get { return ProblemInstanceParameter.Value; } set { ProblemInstanceParameter.Value = value; } } public VRPSolution BestKnownSolution { get { return BestKnownSolutionParameter.Value; } set { BestKnownSolutionParameter.Value = value; } } public ISingleObjectiveEvaluator Evaluator { get { return ProblemInstance.EvaluatorParameter.Value; } } IEvaluator IHeuristicOptimizationProblem.Evaluator { get { return this.Evaluator; } } public ISolutionCreator SolutionCreator { get { return ProblemInstance.SolutionCreatorParameter.Value; } } [Storable] private List operators; public IEnumerable Operators { get { return operators; } } #endregion [StorableConstructor] private VehicleRoutingProblem(bool deserializing) : base(deserializing) { } public VehicleRoutingProblem() : base() { Parameters.Add(new ValueParameter("Maximization", "Set to false as the Vehicle Routing Problem is a minimization problem.", new BoolValue(false))); Parameters.Add(new ValueParameter("ProblemInstance", "The VRP problem instance")); Parameters.Add(new OptionalValueParameter("BestKnownQuality", "The quality of the best known solution of this VRP instance.")); Parameters.Add(new OptionalValueParameter("BestKnownSolution", "The best known solution of this VRP instance.")); operators = new List(); InitializeRandomVRPInstance(); InitializeOperators(); AttachEventHandlers(); AttachProblemInstanceEventHandlers(); } public override IDeepCloneable Clone(Cloner cloner) { return new VehicleRoutingProblem(this, cloner); } private VehicleRoutingProblem(VehicleRoutingProblem original, Cloner cloner) : base(original, cloner) { this.operators = original.operators.Select(x => (IOperator)cloner.Clone(x)).ToList(); this.AttachEventHandlers(); } #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); } #endregion #region Helpers [StorableHook(HookType.AfterDeserialization)] private void AfterDeserializationHook() { AttachEventHandlers(); AttachProblemInstanceEventHandlers(); } private void AttachEventHandlers() { ProblemInstanceParameter.ValueChanged += new EventHandler(ProblemInstanceParameter_ValueChanged); } private void AttachProblemInstanceEventHandlers() { if (Parameters.ContainsKey("Evaluator")) Parameters.Remove("Evaluator"); if (Parameters.ContainsKey("SolutionCreator")) Parameters.Remove("SolutionCreator"); if (Parameters.ContainsKey("BestKnownSolution")) Parameters.Remove("BestKnownSolution"); if (Parameters.ContainsKey("BestKnownQuality")) Parameters.Remove("BestKnownQuality"); if (ProblemInstance != null) { ProblemInstance.SolutionCreatorParameter.ValueChanged += new EventHandler(SolutionCreatorParameter_ValueChanged); ProblemInstance.EvaluatorParameter.ValueChanged += new EventHandler(EvaluatorParameter_ValueChanged); Parameters.Add(ProblemInstance.EvaluatorParameter); Parameters.Add(ProblemInstance.SolutionCreatorParameter); Parameters.Add(ProblemInstance.BestKnownQualityParameter); Parameters.Add(ProblemInstance.BestKnownSolutionParameter); } } void ProblemInstanceParameter_ValueChanged(object sender, EventArgs e) { AttachProblemInstanceEventHandlers(); InitializeOperators(); OnSolutionCreatorChanged(); OnEvaluatorChanged(); OnOperatorsChanged(); } public void SetProblemInstance(IVRPProblemInstance instance) { ProblemInstanceParameter.ValueChanged -= new EventHandler(ProblemInstanceParameter_ValueChanged); ProblemInstance = instance; AttachProblemInstanceEventHandlers(); OnSolutionCreatorChanged(); OnEvaluatorChanged(); ProblemInstanceParameter.ValueChanged += new EventHandler(ProblemInstanceParameter_ValueChanged); } private void SolutionCreatorParameter_ValueChanged(object sender, EventArgs e) { ParameterizeSolutionCreator(); OnSolutionCreatorChanged(); } private void EvaluatorParameter_ValueChanged(object sender, EventArgs e) { OnEvaluatorChanged(); } private void InitializeOperators() { operators = new List(); if (ProblemInstance != null) { operators.AddRange( ProblemInstance.Operators.Concat( ApplicationManager.Manager.GetInstances().Cast()).OrderBy(op => op.Name)); } ParameterizeOperators(); } private void ParameterizeSolutionCreator() { if (SolutionCreator is IMultiVRPOperator) { (SolutionCreator as IMultiVRPOperator).SetOperators(Operators); } } private void ParameterizeOperators() { foreach (IOperator op in Operators) { if (op is IMultiVRPOperator) { (op as IMultiVRPOperator).SetOperators(Operators); } } } #endregion public void ImportFromCordeau(string cordeauFileName) { CordeauParser parser = new CordeauParser(cordeauFileName); parser.Parse(); MDCVRPTWProblemInstance problem = new MDCVRPTWProblemInstance(); problem.Coordinates = new DoubleMatrix(parser.Coordinates); problem.Vehicles.Value = parser.Vehicles; problem.Capacity = new DoubleArray(parser.Capacity); problem.Demand = new DoubleArray(parser.Demands); problem.Depots.Value = parser.Depots; problem.VehicleDepotAssignment = new IntArray(parser.Vehicles); problem.ReadyTime = new DoubleArray(parser.Readytimes); problem.ServiceTime = new DoubleArray(parser.Servicetimes); problem.DueTime = new DoubleArray(parser.Duetimes); int depot = 0; int i = 0; while(i < parser.Vehicles) { problem.VehicleDepotAssignment[i] = depot; i++; if (i % (parser.Vehicles / parser.Depots) == 0) depot++; } this.ProblemInstance = problem; OnReset(); } public void ImportFromLiLim(string liLimFileName) { LiLimParser parser = new LiLimParser(liLimFileName); parser.Parse(); CVRPPDTWProblemInstance problem = new CVRPPDTWProblemInstance(); problem.Coordinates = new DoubleMatrix(parser.Coordinates); problem.Vehicles.Value = parser.Vehicles; problem.Capacity.Value = parser.Capacity; problem.Demand = new DoubleArray(parser.Demands); problem.ReadyTime = new DoubleArray(parser.Readytimes); problem.DueTime = new DoubleArray(parser.Duetimes); problem.ServiceTime = new DoubleArray(parser.Servicetimes); problem.PickupDeliveryLocation = new IntArray(parser.PickupDeliveryLocations); this.ProblemInstance = problem; OnReset(); } public void ImportFromSolomon(string solomonFileName) { SolomonParser parser = new SolomonParser(solomonFileName); parser.Parse(); this.Name = parser.ProblemName; CVRPTWProblemInstance problem = new CVRPTWProblemInstance(); problem.Coordinates = new DoubleMatrix(parser.Coordinates); problem.Vehicles.Value = parser.Vehicles; problem.Capacity.Value = parser.Capacity; problem.Demand = new DoubleArray(parser.Demands); problem.ReadyTime = new DoubleArray(parser.Readytimes); problem.DueTime = new DoubleArray(parser.Duetimes); problem.ServiceTime = new DoubleArray(parser.Servicetimes); this.ProblemInstance = problem; OnReset(); } public void ImportFromTSPLib(string tspFileName) { TSPLIBParser parser = new TSPLIBParser(tspFileName); parser.Parse(); this.Name = parser.Name; int problemSize = parser.Demands.Length; if (parser.Depot != 1) { ErrorHandling.ShowErrorDialog(new Exception("Invalid depot specification")); return; } if (parser.WeightType != TSPLIBParser.TSPLIBEdgeWeightType.EUC_2D) { ErrorHandling.ShowErrorDialog(new Exception("Invalid weight type")); return; } CVRPTWProblemInstance problem = new CVRPTWProblemInstance(); problem.Coordinates = new DoubleMatrix(parser.Vertices); if (parser.Vehicles != -1) problem.Vehicles.Value = parser.Vehicles; else problem.Vehicles.Value = problemSize - 1; problem.Capacity.Value = parser.Capacity; problem.Demand = new DoubleArray(parser.Demands); problem.ReadyTime = new DoubleArray(problemSize); problem.DueTime = new DoubleArray(problemSize); problem.ServiceTime = new DoubleArray(problemSize); for (int i = 0; i < problemSize; i++) { problem.ReadyTime[i] = 0; problem.DueTime[i] = int.MaxValue; problem.ServiceTime[i] = 0; } if (parser.Distance != -1) { problem.DueTime[0] = parser.Distance; } this.ProblemInstance = problem; OnReset(); } public void ImportFromORLib(string orFileName) { ORLIBParser parser = new ORLIBParser(orFileName); parser.Parse(); this.Name = parser.Name; int problemSize = parser.Demands.Length; CVRPProblemInstance problem = new CVRPProblemInstance(); problem.Coordinates = new DoubleMatrix(parser.Vertices); problem.Vehicles.Value = problemSize - 1; problem.Capacity.Value = parser.Capacity; problem.Demand = new DoubleArray(parser.Demands); this.ProblemInstance = problem; OnReset(); } private void InitializeRandomVRPInstance() { System.Random rand = new System.Random(); CVRPTWProblemInstance problem = new CVRPTWProblemInstance(); int cities = 100; problem.Coordinates = new DoubleMatrix(cities + 1, 2); problem.Demand = new DoubleArray(cities + 1); problem.DueTime = new DoubleArray(cities + 1); problem.ReadyTime = new DoubleArray(cities + 1); problem.ServiceTime = new DoubleArray(cities + 1); problem.Vehicles.Value = 100; problem.Capacity.Value = 200; for (int i = 0; i <= cities; i++) { problem.Coordinates[i, 0] = rand.Next(0, 100); problem.Coordinates[i, 1] = rand.Next(0, 100); if (i == 0) { problem.Demand[i] = 0; problem.DueTime[i] = Int16.MaxValue; problem.ReadyTime[i] = 0; problem.ServiceTime[i] = 0; } else { problem.Demand[i] = rand.Next(10, 50); problem.DueTime[i] = rand.Next((int)Math.Ceiling(problem.GetDistance(0, i, null)), 1200); problem.ReadyTime[i] = problem.DueTime[i] - rand.Next(0, 100); problem.ServiceTime[i] = 90; } } this.ProblemInstance = problem; } public void ImportSolution(string solutionFileName) { SolutionParser parser = new SolutionParser(solutionFileName); parser.Parse(); HeuristicLab.Problems.VehicleRouting.Encodings.Potvin.PotvinEncoding encoding = new Encodings.Potvin.PotvinEncoding(ProblemInstance); int cities = 0; foreach (List route in parser.Routes) { Tour tour = new Tour(); tour.Stops.AddRange(route); cities += tour.Stops.Count; encoding.Tours.Add(tour); } if (cities != ProblemInstance.Coordinates.Rows - 1) ErrorHandling.ShowErrorDialog(new Exception("The optimal solution does not seem to correspond with the problem data")); else { VRPSolution solution = new VRPSolution(ProblemInstance, encoding, new DoubleValue(0)); ProblemInstance.BestKnownSolutionParameter.Value = solution; } } } }