#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, customerCoordinates;
[Storable]
LrpUtils.DistanceType distanceType;
[Storable]
double[] depotCapacities, customerDemands, depotCosts;
[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).*"));
}
public override void Prepare() {
Results.Clear();
var metaMsg = MetaSolverOrchestrationPort.PrepareMessage();
metaMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Prepare | OrchestrationMessage.QualityAdaption);
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();
try {
var metaMsg = MetaSolverOrchestrationPort.PrepareMessage();
metaMsg["OrchestrationMessage"] = new EnumValue(OrchestrationMessage.Start);
MetaSolverOrchestrationPort.SendMessage(metaMsg);
} catch (Exception e) { }
}
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.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.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
}
}