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