1 | #region License Information
|
---|
2 | /* HeuristicLab
|
---|
3 | * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
4 | *
|
---|
5 | * This file is part of HeuristicLab.
|
---|
6 | *
|
---|
7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
8 | * it under the terms of the GNU General Public License as published by
|
---|
9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
10 | * (at your option) any later version.
|
---|
11 | *
|
---|
12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | * GNU General Public License for more details.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License
|
---|
18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 | #endregion
|
---|
21 |
|
---|
22 | using System;
|
---|
23 | using System.Drawing;
|
---|
24 | using System.Linq;
|
---|
25 | using System.Threading;
|
---|
26 | using HeuristicLab.Common;
|
---|
27 | using HeuristicLab.Core;
|
---|
28 | using HeuristicLab.Core.Networks;
|
---|
29 | using HeuristicLab.Data;
|
---|
30 | using HeuristicLab.Encodings.BinaryVectorEncoding;
|
---|
31 | using HeuristicLab.Encodings.PermutationEncoding;
|
---|
32 | using HeuristicLab.Networks.Programmable;
|
---|
33 | using HeuristicLab.Problems.Knapsack;
|
---|
34 | using HeuristicLab.Problems.TravelingSalesman;
|
---|
35 |
|
---|
36 | namespace HeuristicLab.Networks {
|
---|
37 | [Item("KSPTSPControl", "A node of an optimization network which connects a KSP and a TSP.")]
|
---|
38 | public class CompiledKSPTSPControl : ProgrammableNode.CompiledProgrammableNode {
|
---|
39 |
|
---|
40 | public static new Image StaticItemImage {
|
---|
41 | get { return HeuristicLab.Common.Resources.VSImageLibrary.RadialChart; }
|
---|
42 | }
|
---|
43 |
|
---|
44 | new protected KSPTSPControl Context {
|
---|
45 | get { return (KSPTSPControl)base.Context; }
|
---|
46 | }
|
---|
47 |
|
---|
48 | protected CompiledKSPTSPControl(CompiledKSPTSPControl original, Cloner cloner) : base(original, cloner) { }
|
---|
49 | public CompiledKSPTSPControl(ProgrammableNode context)
|
---|
50 | : base(context) {
|
---|
51 | if (Ports.Count == 0)
|
---|
52 | Initialize();
|
---|
53 | }
|
---|
54 |
|
---|
55 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
56 | return new CompiledKSPTSPControl(this, cloner);
|
---|
57 | }
|
---|
58 |
|
---|
59 | public override void Initialize() {
|
---|
60 | base.Initialize();
|
---|
61 | var configPort = new ConfigurationPort("Configure");
|
---|
62 | Ports.Add(configPort);
|
---|
63 |
|
---|
64 | configPort.Parameters.Add(new PortParameter<IntValue>("KnapsackCapacity") {
|
---|
65 | Type = PortParameterType.Input
|
---|
66 | });
|
---|
67 | configPort.Parameters.Add(new PortParameter<IntArray>("Values") {
|
---|
68 | Type = PortParameterType.Input
|
---|
69 | });
|
---|
70 | configPort.Parameters.Add(new PortParameter<IntArray>("Weights") {
|
---|
71 | Type = PortParameterType.Input
|
---|
72 | });
|
---|
73 | configPort.Parameters.Add(new PortParameter<DoubleMatrix>("Coordinates") {
|
---|
74 | Type = PortParameterType.Input
|
---|
75 | });
|
---|
76 | configPort.Parameters.Add(new PortParameter<DoubleValue>("TransportCostsFactor") {
|
---|
77 | Type = PortParameterType.Input
|
---|
78 | });
|
---|
79 |
|
---|
80 | var evalKspPort = new MessagePort("Evaluate KSP");
|
---|
81 | Ports.Add(evalKspPort);
|
---|
82 | evalKspPort.Parameters.Add(new PortParameter<BinaryVector>("KnapsackSolution") {
|
---|
83 | Type = PortParameterType.Input
|
---|
84 | });
|
---|
85 | evalKspPort.Parameters.Add(new PortParameter<DoubleValue>("Quality") {
|
---|
86 | Type = PortParameterType.Output
|
---|
87 | });
|
---|
88 |
|
---|
89 | var evalTspPort = new MessagePort("Evaluate TSP");
|
---|
90 | Ports.Add(evalTspPort);
|
---|
91 | evalTspPort.Parameters.Add(new PortParameter<Permutation>("TSPTour") {
|
---|
92 | Type = PortParameterType.Input
|
---|
93 | });
|
---|
94 | evalTspPort.Parameters.Add(new PortParameter<DoubleValue>("TSPTourLength") {
|
---|
95 | Type = PortParameterType.Output
|
---|
96 | });
|
---|
97 |
|
---|
98 | var addKspSolultionPort = new MessagePort("Add KSP Solution");
|
---|
99 | Ports.Add(addKspSolultionPort);
|
---|
100 | addKspSolultionPort.Parameters.Add(new PortParameter<KnapsackSolution>("BestSolution") {
|
---|
101 | Type = PortParameterType.Input
|
---|
102 | });
|
---|
103 |
|
---|
104 | var addTspSolutionPort = new MessagePort("Add TSP Solution");
|
---|
105 | Ports.Add(addTspSolutionPort);
|
---|
106 | addTspSolutionPort.Parameters.Add(new PortParameter<PathTSPTour>("BestSolution") {
|
---|
107 | Type = PortParameterType.Input
|
---|
108 | });
|
---|
109 | }
|
---|
110 |
|
---|
111 | private void AddKspSolultionPortOnMessageReceived(object sender, EventArgs<IMessage, CancellationToken> e) {
|
---|
112 | var cities = (KnapsackSolution)(e.Value.Values["BestSolution"]).Value;
|
---|
113 | AddSelectedCities(cities.BinaryVector);
|
---|
114 | }
|
---|
115 |
|
---|
116 | private void AddTspSolutionPortOnMessageReceived(object sender, EventArgs<IMessage, CancellationToken> e) {
|
---|
117 | var trip = (PathTSPTour)(e.Value.Values["BestSolution"]).Value;
|
---|
118 | AddPredefinedTrip(trip.Permutation);
|
---|
119 | }
|
---|
120 |
|
---|
121 | private void ConfigPortOnMessageReceived(object sender, EventArgs<IMessage, CancellationToken> e) {
|
---|
122 | Context.TransportCostFactor = (DoubleValue)(e.Value["TransportCostsFactor"]);
|
---|
123 | Context.Coordinates = (DoubleMatrix)(e.Value["Coordinates"]);
|
---|
124 | Context.Distances = CalculateEuclidean(Context.Coordinates);
|
---|
125 | Context.CityValues = (IntArray)(e.Value["Values"]);
|
---|
126 | Context.CityWeights = (IntArray)(e.Value["Weights"]);
|
---|
127 | Context.CityLimit = (IntValue)(e.Value["KnapsackCapacity"]);
|
---|
128 | }
|
---|
129 |
|
---|
130 | private void EvalKspPortOnMessageReceived(object sender, EventArgs<IMessage, CancellationToken> e) {
|
---|
131 | var cities = (BinaryVector)(e.Value.Values["KnapsackSolution"]).Value;
|
---|
132 | e.Value.Values["Quality"].Value = new DoubleValue(EvaluatePredefinedTrip(cities));
|
---|
133 | }
|
---|
134 |
|
---|
135 | private void EvalTspPortOnMessageReceived(object sender, EventArgs<IMessage, CancellationToken> e) {
|
---|
136 | var trip = (Permutation)(e.Value.Values["TSPTour"]).Value;
|
---|
137 | e.Value.Values["TSPTourLength"].Value = new DoubleValue(EvaluateSelectedCities(trip));
|
---|
138 | }
|
---|
139 |
|
---|
140 | public override void RegisterEvents() {
|
---|
141 | base.RegisterEvents();
|
---|
142 | ((IMessagePort)Ports["Configure"]).MessageReceived += ConfigPortOnMessageReceived;
|
---|
143 | ((IMessagePort)Ports["Evaluate KSP"]).MessageReceived += EvalKspPortOnMessageReceived;
|
---|
144 | ((IMessagePort)Ports["Evaluate TSP"]).MessageReceived += EvalTspPortOnMessageReceived;
|
---|
145 | ((IMessagePort)Ports["Add KSP Solution"]).MessageReceived += AddKspSolultionPortOnMessageReceived;
|
---|
146 | ((IMessagePort)Ports["Add TSP Solution"]).MessageReceived += AddTspSolutionPortOnMessageReceived;
|
---|
147 |
|
---|
148 | }
|
---|
149 | public override void DeregisterEvents() {
|
---|
150 | ((IMessagePort)Ports["Configure"]).MessageReceived -= ConfigPortOnMessageReceived;
|
---|
151 | ((IMessagePort)Ports["Evaluate KSP"]).MessageReceived -= EvalKspPortOnMessageReceived;
|
---|
152 | ((IMessagePort)Ports["Evaluate TSP"]).MessageReceived -= EvalTspPortOnMessageReceived;
|
---|
153 | ((IMessagePort)Ports["Add KSP Solution"]).MessageReceived -= AddKspSolultionPortOnMessageReceived;
|
---|
154 | ((IMessagePort)Ports["Add TSP Solution"]).MessageReceived -= AddTspSolutionPortOnMessageReceived;
|
---|
155 | base.DeregisterEvents();
|
---|
156 | }
|
---|
157 |
|
---|
158 | public double EvaluatePredefinedTrip(BinaryVector cities) {
|
---|
159 | if (Context.SelectedCities.Count == 0) {
|
---|
160 | Context.SelectedCities.Add(cities);
|
---|
161 | Context.KspWait.Set();
|
---|
162 | Context.TspWait.WaitOne();
|
---|
163 | }
|
---|
164 | return EvaluateBoth(cities, Context.PredefinedTrip.Last());
|
---|
165 | }
|
---|
166 |
|
---|
167 | public double EvaluateSelectedCities(Permutation trip) {
|
---|
168 | if (Context.PredefinedTrip.Count == 0) {
|
---|
169 | Context.PredefinedTrip.Add(trip);
|
---|
170 | Context.TspWait.Set();
|
---|
171 | Context.KspWait.WaitOne();
|
---|
172 | }
|
---|
173 | return EvaluateBoth(Context.SelectedCities.Last(), trip);
|
---|
174 | }
|
---|
175 |
|
---|
176 | public double EvaluateBoth(BinaryVector cities, Permutation trip) {
|
---|
177 | var cityValues = cities.Select((v, i) => v ? Context.CityValues[i] : 0).Sum();
|
---|
178 | var cityWeights = cities.Select((v, i) => v ? Context.CityWeights[i] : 0).Sum();
|
---|
179 | var subtour = trip.Where(x => cities[x]).ToArray();
|
---|
180 | var tourLength = 0.0;
|
---|
181 | for (var i = 1; i < subtour.Length; i++)
|
---|
182 | tourLength += Context.Distances[subtour[i - 1], subtour[i]];
|
---|
183 | tourLength += Context.Distances[subtour.Last(), subtour[0]];
|
---|
184 | if (cityWeights > Context.CityLimit.Value) // infeasible solution
|
---|
185 | return Context.CityLimit.Value - cityWeights - tourLength * Context.TransportCostFactor.Value;
|
---|
186 | return cityValues - tourLength * Context.TransportCostFactor.Value;
|
---|
187 | }
|
---|
188 |
|
---|
189 | public void AddPredefinedTrip(Permutation trip) {
|
---|
190 | Context.TspWait.Set();
|
---|
191 | Context.KspWait.WaitOne();
|
---|
192 | lock (Context.Locker) {
|
---|
193 | Context.PredefinedTrip.Add(trip);
|
---|
194 | }
|
---|
195 | }
|
---|
196 |
|
---|
197 | public void AddSelectedCities(BinaryVector cities) {
|
---|
198 | Context.KspWait.Set();
|
---|
199 | Context.TspWait.WaitOne();
|
---|
200 | lock (Context.Locker) {
|
---|
201 | Context.SelectedCities.Add(cities);
|
---|
202 | }
|
---|
203 | }
|
---|
204 |
|
---|
205 | public static DoubleMatrix CalculateEuclidean(DoubleMatrix cities) {
|
---|
206 | var len = cities.Rows;
|
---|
207 | var distances = new DoubleMatrix(len, len);
|
---|
208 | for (var i = 0; i < len - 1; i++) {
|
---|
209 | var sX = cities[i, 0];
|
---|
210 | var sY = cities[i, 1];
|
---|
211 | for (var j = i + 1; j < len; j++) {
|
---|
212 | var tX = cities[j, 0];
|
---|
213 | var tY = cities[j, 1];
|
---|
214 | distances[i, j] = Math.Sqrt((sX - tX) * (sX - tX) + (sY - tY) * (sY - tY));
|
---|
215 | distances[j, i] = distances[i, j];
|
---|
216 | }
|
---|
217 | }
|
---|
218 | return distances;
|
---|
219 | }
|
---|
220 |
|
---|
221 | }
|
---|
222 | }
|
---|