#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;
}
}
}