#region License Information /* HeuristicLab * Copyright (C) 2002-2017 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.RegularExpressions; using System.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Core.Networks; using HeuristicLab.Data; using HeuristicLab.Encodings.BinaryVectorEncoding; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Encodings.PermutationEncoding; using HeuristicLab.Encodings.RealVectorEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.FacilityLocation; using HeuristicLab.Problems.VehicleRouting; using HeuristicLab.Problems.VehicleRouting.Encodings.General; using HeuristicLab.Problems.VehicleRouting.ProblemInstances; namespace HeuristicLab.Networks.IntegratedOptimization.LocationRouting { [Item("LrpOrchestratorNode1", "Orchestrator for LRP optimization network version 1.")] [StorableClass] public sealed class LrpOrchestratorNode1 : OrchestratorNode { #region Constants private const string InstanceParameterName = "Instance"; private const string FlpParameterName = "FLP"; private const string VrpParameterName = "VRP"; private const string MetaSolverName = "MetaSolver"; private const string FlpSolverName = "FlpSolver"; private const string VrpSolverName = "VrpSolver"; #endregion private CancellationTokenSource cts; private ResultCollection vrpResults, flpResults; [Storable] int nrOfDepots, nrOfCustomers; [Storable] double[,] depotCoordinates = new double[0, 0], customerCoordinates = new double[0, 0]; [Storable] LrpUtils.DistanceType distanceType; [Storable] double[] depotCapacities = new double[0], customerDemands = new double[0], depotCosts = new double[0]; [Storable] double vehicleCapacity, vehicleCost; #region Parameters public IFixedValueParameter InstanceParameter { get { return (IFixedValueParameter)Parameters[InstanceParameterName]; } } public IValueParameter FlpParameter { get { return (IValueParameter)Parameters[FlpParameterName]; } } public IValueParameter VrpParameter { get { return (IValueParameter)Parameters[VrpParameterName]; } } #endregion #region Ports public IMessagePort MetaSolverOrchestrationPort { get { return (IMessagePort)Ports[MetaSolverName + OrchestrationPortNameSuffix]; } } public IMessagePort MetaSolverEvaluationPort { get { return (IMessagePort)Ports[MetaSolverName + EvaluationPortNameSuffix]; } } public IMessagePort FlpSolverOrchestrationPort { get { return (IMessagePort)Ports[FlpSolverName + OrchestrationPortNameSuffix]; } } public IMessagePort FlpSolverEvaluationPort { get { return (IMessagePort)Ports[FlpSolverName + EvaluationPortNameSuffix]; } } public IMessagePort VrpSolverOrchestrationPort { get { return (IMessagePort)Ports[VrpSolverName + OrchestrationPortNameSuffix]; } } public IMessagePort VrpSolverEvaluationPort { get { return (IMessagePort)Ports[VrpSolverName + EvaluationPortNameSuffix]; } } #endregion [StorableConstructor] private LrpOrchestratorNode1(bool deserializing) : base(deserializing) { } private LrpOrchestratorNode1(LrpOrchestratorNode1 original, Cloner cloner) : base(original, cloner) { nrOfDepots = original.nrOfDepots; nrOfCustomers = original.nrOfCustomers; depotCoordinates = (double[,])original.depotCoordinates.Clone(); customerCoordinates = (double[,])original.customerCoordinates.Clone(); distanceType = original.distanceType; depotCapacities = (double[])original.depotCapacities.Clone(); customerDemands = (double[])original.customerDemands.Clone(); depotCosts = (double[])original.depotCosts.Clone(); vehicleCapacity = original.vehicleCapacity; vehicleCost = original.vehicleCost; RegisterEvents(); } public LrpOrchestratorNode1() : this("LrpOrchestratorNode1") { } public LrpOrchestratorNode1(string name) : base(name) { #region Configure Parameters Parameters.Add(new FixedValueParameter(InstanceParameterName)); Parameters.Add(new ValueParameter(FlpParameterName, new FacilityLocationProblem())); Parameters.Add(new ValueParameter(VrpParameterName, new VehicleRoutingProblem() { ProblemInstance = new CVRPProblemInstance() })); #endregion #region Configure Ports AddOrchestrationPort(MetaSolverName); AddEvaluationPort(MetaSolverName, "RealVector", "Quality"); AddOrchestrationPort(VrpSolverName); AddEvaluationPort(VrpSolverName, "TSPTour", "TSPTourLength"); AddOrchestrationPort(FlpSolverName); AddEvaluationPort(FlpSolverName, "KnapsackSolution", "Quality"); RegisterEvents(); #endregion } public override IDeepCloneable Clone(Cloner cloner) { return new LrpOrchestratorNode1(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { RegisterEvents(); } private void RegisterEvents() { InstanceParameter.Value.ToStringChanged += InstanceParameter_Value_ToStringChanged; MetaSolverOrchestrationPort.ConnectedPortChanged += MetaSolverOrchestrationPort_ConnectedPortChanged; VrpSolverOrchestrationPort.ConnectedPortChanged += VrpSolverOrchestrationPort_ConnectedPortChanged; FlpSolverOrchestrationPort.ConnectedPortChanged += FlpSolverOrchestrationPort_ConnectedPortChanged; } private void InstanceParameter_Value_ToStringChanged(object sender, EventArgs e) { string filePath = InstanceParameter.Value.Value; LrpUtils.Import(filePath, out nrOfDepots, out nrOfCustomers, out depotCoordinates, out customerCoordinates, out distanceType, out depotCapacities, out customerDemands, out depotCosts, out vehicleCapacity, out vehicleCost); var flp = FlpParameter.Value; flp.CustomerDemandsParameter.Value = new DoubleArray(customerDemands); flp.DeliveryCostsParameter.Value = new DoubleMatrix(LrpUtils.GetFlpDeliveryCosts(depotCoordinates, customerCoordinates, distanceType)); flp.DepotCapacitiesParameter.Value = new DoubleArray(depotCapacities); flp.Encoding.Length = nrOfCustomers; flp.OpeningCostsParameter.Value = new DoubleArray(depotCosts); var vrpInstance = (CVRPProblemInstance)VrpParameter.Value.ProblemInstance; vrpInstance.Capacity.Value = vehicleCapacity; vrpInstance.FleetUsageFactor.Value = vehicleCost; vrpInstance.OverloadPenalty.Value = vehicleCost * 1000.0; var crossover = VrpParameter.Value.OperatorsParameter.Value.OfType().Single(x => x.Name == "MultiVRPSolutionCrossover"); foreach (var c in crossover.Operators) crossover.Operators.SetItemCheckedState(c, c.Name.StartsWith("Potvin")); var mutator = VrpParameter.Value.OperatorsParameter.Value.OfType().Single(x => x.Name == "MultiVRPSolutionManipulator"); foreach (var m in mutator.Operators) mutator.Operators.SetItemCheckedState(m, Regex.IsMatch(m.Name, @"Potvin(One|Two).*")); Prepare(); } public override void Prepare(bool clearRuns = false) { Results.Clear(); var metaMsg = MetaSolverOrchestrationPort.PrepareMessage(); var msgFlags = OrchestrationMessage.Prepare | OrchestrationMessage.SetEvalHook; if (clearRuns) msgFlags |= OrchestrationMessage.ClearRuns; metaMsg["OrchestrationMessage"] = new EnumValue(msgFlags); var problem = new VariegationProblem(); problem.Encoding.Length = FlpParameter.Value.Encoding.Length * 2; problem.Encoding.Bounds = new DoubleMatrix(new[,] { { 0.0, 2.0 } }); metaMsg["Problem"] = problem; MetaSolverOrchestrationPort.SendMessage(metaMsg); } public override void Start() { cts = new CancellationTokenSource(); var metaMsg = MetaSolverOrchestrationPort.PrepareMessage(); metaMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Start); MetaSolverOrchestrationPort.SendMessage(metaMsg); } public override void Pause() { cts.Cancel(); var metaMsg = MetaSolverOrchestrationPort.PrepareMessage(); metaMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Pause); MetaSolverOrchestrationPort.SendMessage(metaMsg); var vrpMsg = VrpSolverOrchestrationPort.PrepareMessage(); vrpMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Stop); VrpSolverOrchestrationPort.SendMessage(vrpMsg); var kspMsg = FlpSolverOrchestrationPort.PrepareMessage(); kspMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Stop); FlpSolverOrchestrationPort.SendMessage(kspMsg); } public override void Stop() { cts.Cancel(); var metaMsg = MetaSolverOrchestrationPort.PrepareMessage(); metaMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Stop); MetaSolverOrchestrationPort.SendMessage(metaMsg); var vrpMsg = VrpSolverOrchestrationPort.PrepareMessage(); vrpMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Stop); VrpSolverOrchestrationPort.SendMessage(vrpMsg); var kspMsg = FlpSolverOrchestrationPort.PrepareMessage(); kspMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Stop); FlpSolverOrchestrationPort.SendMessage(kspMsg); } protected override void ProcessMessage(IMessage message, IMessagePort port, CancellationToken token) { var messageActions = new Dictionary>(); messageActions.Add(MetaSolverOrchestrationPort, MetaSolverOrchestrationPortMessage); messageActions.Add(MetaSolverEvaluationPort, MetaSolverEvaluationPortMessage); messageActions.Add(VrpSolverOrchestrationPort, VrpSolverOrchestrationPortMessage); messageActions.Add(VrpSolverEvaluationPort, VrpSolverEvaluationPortMessage); messageActions.Add(FlpSolverOrchestrationPort, FlpSolverOrchestrationPortMessage); messageActions.Add(FlpSolverEvaluationPort, FlpSolverEvaluationPortMessage); messageActions[port](message); base.ProcessMessage(message, port, token); } #region MetaSolver Message Handling private void MetaSolverOrchestrationPortMessage(IMessage message) { } private void MetaSolverEvaluationPortMessage(IMessage message) { var factors = (RealVector)message["RealVector"]; var flp = (FacilityLocationProblem)FlpParameter.Value.Clone(); var cc = (double[,])customerCoordinates.Clone(); for (int i = 0; i < nrOfCustomers; i++) { cc[i, 0] = cc[i, 0] * factors[i * 2]; cc[i, 1] = cc[i, 1] * factors[i * 2 + 1]; } flp.DeliveryCostsParameter.Value = new DoubleMatrix(LrpUtils.GetFlpDeliveryCosts(depotCoordinates, cc, distanceType)); var flpMsg = FlpSolverOrchestrationPort.PrepareMessage(); flpMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Prepare | OrchestrationMessage.ClearRuns | OrchestrationMessage.Start); flpMsg["Problem"] = flp; FlpSolverOrchestrationPort.SendMessage(flpMsg); cts.Token.ThrowIfCancellationRequested(); var bestFlpSolution = (IntegerVector)flpResults["Best Solution"].Value; var flpSolution = FlpParameter.Value.GetSolution(bestFlpSolution); var depots = bestFlpSolution.Select((x, i) => Tuple.Create(x, i)).GroupBy(x => x.Item1, x => x.Item2); var vrpSolutions = new ResultCollection(depots.Count()); foreach (var depot in depots.OrderBy(x => x.Key)) { var depotIdx = depot.Key; var customers = depot.ToArray(); var vrp = (VehicleRoutingProblem)VrpParameter.Value.Clone(); var vrpInstance = (CVRPProblemInstance)vrp.ProblemInstance; var coordinates = LrpUtils.GetVrpCoordinates(depotCoordinates, customerCoordinates, depotIdx, customers); var distances = LrpUtils.GetVrpDistances(coordinates, distanceType); vrpInstance.Coordinates = new DoubleMatrix(coordinates); vrpInstance.DistanceMatrix = new DoubleMatrix(distances); vrpInstance.Demand = new DoubleArray(new[] { 0.0 }.Concat(customers.Select(x => customerDemands[x])).ToArray()); vrpInstance.Vehicles.Value = customers.Length; var vrpMsg = VrpSolverOrchestrationPort.PrepareMessage(); vrpMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Prepare | OrchestrationMessage.ClearRuns | OrchestrationMessage.Start); vrpMsg["Problem"] = vrp; VrpSolverOrchestrationPort.SendMessage(vrpMsg); cts.Token.ThrowIfCancellationRequested(); var bestVrpSolution = (VRPSolution)vrpResults["Best valid VRP Solution"].Value.Clone(); vrpSolutions.Add(new Result("Depot " + depot.Key, bestVrpSolution)); } #region Analyze double objectiveValue = LrpUtils.Evaluate(flpSolution, vrpSolutions.Select(x => (VRPSolution)x.Value).ToArray()); ((DoubleValue)message["Quality"]).Value = objectiveValue; IResult bestQuality; if (!Results.TryGetValue("Best LRP Quality", out bestQuality)) { Results.Add(new Result("Best LRP Quality", new DoubleValue(objectiveValue))); Results.Add(new Result("Best FLP Solution", flpSolution)); Results.Add(new Result("Best VRP Solutions", vrpSolutions)); } else if (objectiveValue < ((DoubleValue)bestQuality.Value).Value) { ((DoubleValue)bestQuality.Value).Value = objectiveValue; Results["Best FLP Solution"].Value = flpSolution; Results["Best VRP Solutions"].Value = vrpSolutions; } #endregion } #endregion #region VrpSolver Message Handling private void VrpSolverOrchestrationPortMessage(IMessage message) { var results = (ResultCollection)message["Results"]; if (results.ContainsKey("Best valid VRP Solution")) { vrpResults = results; } } private void VrpSolverEvaluationPortMessage(IMessage message) { } #endregion #region KspSolver Message Handling private void FlpSolverOrchestrationPortMessage(IMessage message) { var results = (ResultCollection)message["Results"]; if (results.ContainsKey("Best Solution")) { flpResults = results; } } private void FlpSolverEvaluationPortMessage(IMessage message) { } #endregion #region Event Handlers private void MetaSolverOrchestrationPort_ConnectedPortChanged(object sender, EventArgs e) { if (MetaSolverOrchestrationPort.ConnectedPort == null) return; var node = MetaSolverOrchestrationPort.ConnectedPort.Parent as OrchestratedAlgorithmNode; if (node == null) return; var hook = new HookOperator { Name = "Meta Eval Hook" }; hook.Parameters.Add(new LookupParameter("RealVector") { Hidden = true }); hook.Parameters.Add(new LookupParameter("Quality") { Hidden = true }); node.EvalHook = hook; node.OrchestrationPort.CloneParametersFromPort(MetaSolverOrchestrationPort); node.EvaluationPort.CloneParametersFromPort(MetaSolverEvaluationPort); node.EvaluationPort.ConnectedPort = MetaSolverEvaluationPort; } private void VrpSolverOrchestrationPort_ConnectedPortChanged(object sender, EventArgs e) { if (VrpSolverOrchestrationPort.ConnectedPort == null) return; var node = VrpSolverOrchestrationPort.ConnectedPort.Parent as OrchestratedAlgorithmNode; if (node == null) return; var hook = new HookOperator { Name = "VRP Eval Hook" }; hook.Parameters.Add(new LookupParameter("VRPTours") { Hidden = true }); hook.Parameters.Add(new LookupParameter("Quality") { Hidden = true }); node.EvalHook = hook; node.OrchestrationPort.CloneParametersFromPort(VrpSolverOrchestrationPort); node.EvaluationPort.CloneParametersFromPort(VrpSolverEvaluationPort); node.EvaluationPort.ConnectedPort = VrpSolverEvaluationPort; } private void FlpSolverOrchestrationPort_ConnectedPortChanged(object sender, EventArgs e) { if (FlpSolverOrchestrationPort.ConnectedPort == null) return; var node = FlpSolverOrchestrationPort.ConnectedPort.Parent as OrchestratedAlgorithmNode; if (node == null) return; var hook = new HookOperator { Name = "FLP Eval Hook" }; hook.Parameters.Add(new LookupParameter("IntegerVector") { Hidden = true }); hook.Parameters.Add(new LookupParameter("Quality") { Hidden = true }); node.EvalHook = hook; node.OrchestrationPort.CloneParametersFromPort(FlpSolverOrchestrationPort); node.EvaluationPort.CloneParametersFromPort(FlpSolverEvaluationPort); node.EvaluationPort.ConnectedPort = FlpSolverEvaluationPort; } #endregion } }