#pragma warning disable 436 #region License Information /* HeuristicLab * Copyright (C) 2002-2014 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.Drawing; using System.Linq; using System.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Core.Networks; using HeuristicLab.Data; using HeuristicLab.Encodings.BinaryVectorEncoding; using HeuristicLab.Encodings.PermutationEncoding; using HeuristicLab.Networks.Programmable; using HeuristicLab.Problems.Knapsack; using HeuristicLab.Problems.TravelingSalesman; namespace HeuristicLab.Networks { [Item("KSPTSPControl", "A node of an optimization network which connects a KSP and a TSP.")] public class CompiledKSPTSPControl : ProgrammableNode.CompiledProgrammableNode { public static new Image StaticItemImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.RadialChart; } } new protected KSPTSPControl Context { get { return (KSPTSPControl)base.Context; } } protected CompiledKSPTSPControl(CompiledKSPTSPControl original, Cloner cloner) : base(original, cloner) { } public CompiledKSPTSPControl(ProgrammableNode context) : base(context) { if (Ports.Count == 0) Initialize(); } public override IDeepCloneable Clone(Cloner cloner) { return new CompiledKSPTSPControl(this, cloner); } public override void Initialize() { base.Initialize(); var configPort = new ConfigurationPort("Configure"); Ports.Add(configPort); configPort.Parameters.Add(new PortParameter("KnapsackCapacity") { Type = PortParameterType.Input }); configPort.Parameters.Add(new PortParameter("Values") { Type = PortParameterType.Input }); configPort.Parameters.Add(new PortParameter("Weights") { Type = PortParameterType.Input }); configPort.Parameters.Add(new PortParameter("Coordinates") { Type = PortParameterType.Input }); configPort.Parameters.Add(new PortParameter("TransportCostsFactor") { Type = PortParameterType.Input }); var evalKspPort = new MessagePort("Evaluate KSP"); Ports.Add(evalKspPort); evalKspPort.Parameters.Add(new PortParameter("KnapsackSolution") { Type = PortParameterType.Input }); evalKspPort.Parameters.Add(new PortParameter("Quality") { Type = PortParameterType.Output }); var evalTspPort = new MessagePort("Evaluate TSP"); Ports.Add(evalTspPort); evalTspPort.Parameters.Add(new PortParameter("TSPTour") { Type = PortParameterType.Input }); evalTspPort.Parameters.Add(new PortParameter("TSPTourLength") { Type = PortParameterType.Output }); var addKspSolultionPort = new MessagePort("Add KSP Solution"); Ports.Add(addKspSolultionPort); addKspSolultionPort.Parameters.Add(new PortParameter("BestSolution") { Type = PortParameterType.Input }); var addTspSolutionPort = new MessagePort("Add TSP Solution"); Ports.Add(addTspSolutionPort); addTspSolutionPort.Parameters.Add(new PortParameter("BestSolution") { Type = PortParameterType.Input }); } private void AddKspSolultionPortOnMessageReceived(object sender, EventArgs e) { var cities = (KnapsackSolution)(e.Value.Values["BestSolution"]).Value; AddSelectedCities(cities.BinaryVector); } private void AddTspSolutionPortOnMessageReceived(object sender, EventArgs e) { var trip = (PathTSPTour)(e.Value.Values["BestSolution"]).Value; AddPredefinedTrip(trip.Permutation); } private void ConfigPortOnMessageReceived(object sender, EventArgs e) { Context.TransportCostFactor = (DoubleValue)(e.Value["TransportCostsFactor"]); Context.Coordinates = (DoubleMatrix)(e.Value["Coordinates"]); Context.Distances = CalculateEuclidean(Context.Coordinates); Context.CityValues = (IntArray)(e.Value["Values"]); Context.CityWeights = (IntArray)(e.Value["Weights"]); Context.CityLimit = (IntValue)(e.Value["KnapsackCapacity"]); } private void EvalKspPortOnMessageReceived(object sender, EventArgs e) { var cities = (BinaryVector)(e.Value.Values["KnapsackSolution"]).Value; e.Value.Values["Quality"].Value = new DoubleValue(EvaluatePredefinedTrip(cities)); } private void EvalTspPortOnMessageReceived(object sender, EventArgs e) { var trip = (Permutation)(e.Value.Values["TSPTour"]).Value; e.Value.Values["TSPTourLength"].Value = new DoubleValue(EvaluateSelectedCities(trip)); } public override void RegisterEvents() { base.RegisterEvents(); ((IMessagePort)Ports["Configure"]).MessageReceived += ConfigPortOnMessageReceived; ((IMessagePort)Ports["Evaluate KSP"]).MessageReceived += EvalKspPortOnMessageReceived; ((IMessagePort)Ports["Evaluate TSP"]).MessageReceived += EvalTspPortOnMessageReceived; ((IMessagePort)Ports["Add KSP Solution"]).MessageReceived += AddKspSolultionPortOnMessageReceived; ((IMessagePort)Ports["Add TSP Solution"]).MessageReceived += AddTspSolutionPortOnMessageReceived; } public override void DeregisterEvents() { ((IMessagePort)Ports["Configure"]).MessageReceived -= ConfigPortOnMessageReceived; ((IMessagePort)Ports["Evaluate KSP"]).MessageReceived -= EvalKspPortOnMessageReceived; ((IMessagePort)Ports["Evaluate TSP"]).MessageReceived -= EvalTspPortOnMessageReceived; ((IMessagePort)Ports["Add KSP Solution"]).MessageReceived -= AddKspSolultionPortOnMessageReceived; ((IMessagePort)Ports["Add TSP Solution"]).MessageReceived -= AddTspSolutionPortOnMessageReceived; base.DeregisterEvents(); } public double EvaluatePredefinedTrip(BinaryVector cities) { if (Context.SelectedCities.Count == 0) { Context.SelectedCities.Add(cities); Context.KspWait.Set(); Context.TspWait.WaitOne(); } return EvaluateBoth(cities, Context.PredefinedTrip.Last()); } public double EvaluateSelectedCities(Permutation trip) { if (Context.PredefinedTrip.Count == 0) { Context.PredefinedTrip.Add(trip); Context.TspWait.Set(); Context.KspWait.WaitOne(); } return EvaluateBoth(Context.SelectedCities.Last(), trip); } public double EvaluateBoth(BinaryVector cities, Permutation trip) { var cityValues = cities.Select((v, i) => v ? Context.CityValues[i] : 0).Sum(); var cityWeights = cities.Select((v, i) => v ? Context.CityWeights[i] : 0).Sum(); var subtour = trip.Where(x => cities[x]).ToArray(); var tourLength = 0.0; for (var i = 1; i < subtour.Length; i++) tourLength += Context.Distances[subtour[i - 1], subtour[i]]; tourLength += Context.Distances[subtour.Last(), subtour[0]]; if (cityWeights > Context.CityLimit.Value) // infeasible solution return Context.CityLimit.Value - cityWeights - tourLength * Context.TransportCostFactor.Value; return cityValues - tourLength * Context.TransportCostFactor.Value; } public void AddPredefinedTrip(Permutation trip) { Context.TspWait.Set(); Context.KspWait.WaitOne(); lock (Context.Locker) { Context.PredefinedTrip.Add(trip); } } public void AddSelectedCities(BinaryVector cities) { Context.KspWait.Set(); Context.TspWait.WaitOne(); lock (Context.Locker) { Context.SelectedCities.Add(cities); } } public static DoubleMatrix CalculateEuclidean(DoubleMatrix cities) { var len = cities.Rows; var distances = new DoubleMatrix(len, len); for (var i = 0; i < len - 1; i++) { var sX = cities[i, 0]; var sY = cities[i, 1]; for (var j = i + 1; j < len; j++) { var tX = cities[j, 0]; var tY = cities[j, 1]; distances[i, j] = Math.Sqrt((sX - tX) * (sX - tX) + (sY - tY) * (sY - tY)); distances[j, i] = distances[i, j]; } } return distances; } } }