Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs @ 6046

Last change on this file since 6046 was 6042, checked in by abeham, 14 years ago

#1425

  • Changed LocalImprovementOperators
    • Changed interface (made Problem a property, added a property that denotes the type of the problem that it can be applied on, added some general parameters)
    • Added some parameters and wiring
    • Changed move discovery and parameterization and added a helper class to ease finding compatible move operators
    • Discovering only IMultiMoveOperators and IExhaustiveMoveOperators and putting the multi move ones first
    • Fixed bug in Apply method that could create an endless string of nested execution contexts
    • Removed all problem specific analyzers in the two local improvement operators and only left the BestAverageWorstQualityAnalyzer since it doesn't make any sense to perform diversity or allele analysis during local improvement in the most common case and those analyzers take a lot of time (one can always add them manually should he/she be interested). The analyzers in the VNS's Analyzer parameter are left untouched.
  • Removed shaking operator and interface from VNS plugin and added that to Optimization and Optimization.Operators
  • Changed some ValueParameters to ConstrainedValueParameters and added type discovery to fill them (using the ProblemType property to get compatible local improvement operators)
  • Added missing GPL license headers
  • Changed some ValueParameters to the new FixedValueParameters
  • Added an additional encoding specific ShakingOperator to each encoding and added that to each problem
    • reason is that only the problem/encoding can really decide if a shaking operator is meaningful or not
  • Fixed an unrelated bug in the BestAverageWorstQualityAnalyzer that I encountered (and made the fix backwards compatible)
    • Also added a snippet for creating the backwards compatible comment marker and region
  • Fixed the operator graph of the VNS main loop
    • The condition to continue only when the local search was not successful is not necessary and is not part of the VNS definition as far as I know it (only condition to break the inner loop is when k reaches k_max)
  • Changed the ShakingOperator to input current index and output the maximum number of neighborhoods instead of a boolean that indicates that the last index has been reached since the maximum number is a little more generally useful and equally powerful in modeling
    • Remodeled the VNS main loop to check for k < k_max in order to continue the inner loop
  • other changes that I forgot...

Still necessary

  • test, test, test
  • check for backwards compatible breakers
  • add a maximum evaluated solutions stop criterion
  • optionally: implement fast problem specific local search improvement operators that do not build on the whole generic overhead (e.g. a 2-opt TSP specific local search operator). The idea of VNS is really to converge to a local optimum which is difficult to achieve using the current rather limited termination options
File size: 16.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.IO;
26using System.Linq;
27using System.Reflection;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.PermutationEncoding;
32using HeuristicLab.Optimization;
33using HeuristicLab.Parameters;
34using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
35using HeuristicLab.PluginInfrastructure;
36
37namespace HeuristicLab.Problems.QuadraticAssignment {
38  [Item("Quadratic Assignment Problem", "The Quadratic Assignment Problem (QAP) can be described as the problem of assigning N facilities to N fixed locations such that there is exactly one facility in each location and that the sum of the distances multiplied by the connection strength between the facilities becomes minimal.")]
39  [Creatable("Problems")]
40  [StorableClass]
41  public sealed class QuadraticAssignmentProblem : SingleObjectiveHeuristicOptimizationProblem<IQAPEvaluator, IPermutationCreator>, IStorableContent {
42    private static string InstancePrefix = "HeuristicLab.Problems.QuadraticAssignment.Data.";
43
44    public string Filename { get; set; }
45
46    public override Image ItemImage {
47      get { return HeuristicLab.Common.Resources.VSImageLibrary.Type; }
48    }
49
50    #region Parameter Properties
51    public IValueParameter<Permutation> BestKnownSolutionParameter {
52      get { return (IValueParameter<Permutation>)Parameters["BestKnownSolution"]; }
53    }
54    public IValueParameter<DoubleMatrix> WeightsParameter {
55      get { return (IValueParameter<DoubleMatrix>)Parameters["Weights"]; }
56    }
57    public IValueParameter<DoubleMatrix> DistancesParameter {
58      get { return (IValueParameter<DoubleMatrix>)Parameters["Distances"]; }
59    }
60    #endregion
61
62    #region Properties
63    public Permutation BestKnownSolution {
64      get { return BestKnownSolutionParameter.Value; }
65      set { BestKnownSolutionParameter.Value = value; }
66    }
67    public DoubleMatrix Weights {
68      get { return WeightsParameter.Value; }
69      set { WeightsParameter.Value = value; }
70    }
71    public DoubleMatrix Distances {
72      get { return DistancesParameter.Value; }
73      set { DistancesParameter.Value = value; }
74    }
75
76    public IEnumerable<string> EmbeddedInstances {
77      get {
78        return Assembly.GetExecutingAssembly()
79          .GetManifestResourceNames()
80          .Where(x => x.EndsWith(".dat"))
81          .OrderBy(x => x)
82          .Select(x => x.Replace(".dat", String.Empty))
83          .Select(x => x.Replace(InstancePrefix, String.Empty));
84      }
85    }
86
87    private BestQAPSolutionAnalyzer BestQAPSolutionAnalyzer {
88      get { return Operators.OfType<BestQAPSolutionAnalyzer>().FirstOrDefault(); }
89    }
90    #endregion
91
92    [StorableConstructor]
93    private QuadraticAssignmentProblem(bool deserializing) : base(deserializing) { }
94    private QuadraticAssignmentProblem(QuadraticAssignmentProblem original, Cloner cloner)
95      : base(original, cloner) {
96      AttachEventHandlers();
97    }
98    public QuadraticAssignmentProblem()
99      : base(new QAPEvaluator(), new RandomPermutationCreator()) {
100      Parameters.Add(new OptionalValueParameter<Permutation>("BestKnownSolution", "The best known solution which is updated whenever a new better solution is found or may be the optimal solution if it is known beforehand.", null));
101      Parameters.Add(new ValueParameter<DoubleMatrix>("Weights", "The strength of the connection between the facilities.", new DoubleMatrix(5, 5)));
102      Parameters.Add(new ValueParameter<DoubleMatrix>("Distances", "The distance matrix which can either be specified directly without the coordinates, or can be calculated automatically from the coordinates.", new DoubleMatrix(5, 5)));
103
104      Maximization = new BoolValue(false);
105
106      Weights = new DoubleMatrix(new double[,] {
107        { 0, 1, 0, 0, 1 },
108        { 1, 0, 1, 0, 0 },
109        { 0, 1, 0, 1, 0 },
110        { 0, 0, 1, 0, 1 },
111        { 1, 0, 0, 1, 0 }
112      });
113
114      Distances = new DoubleMatrix(new double[,] {
115        {   0, 360, 582, 582, 360 },
116        { 360,   0, 360, 582, 582 },
117        { 582, 360,   0, 360, 582 },
118        { 582, 582, 360,   0, 360 },
119        { 360, 582, 582, 360,   0 }
120      });
121
122      SolutionCreator.PermutationParameter.ActualName = "Assignment";
123      ParameterizeSolutionCreator();
124      ParameterizeEvaluator();
125
126      InitializeOperators();
127      AttachEventHandlers();
128    }
129
130    public override IDeepCloneable Clone(Cloner cloner) {
131      return new QuadraticAssignmentProblem(this, cloner);
132    }
133
134    #region Events
135    protected override void OnSolutionCreatorChanged() {
136      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
137      ParameterizeSolutionCreator();
138      ParameterizeEvaluator();
139      ParameterizeAnalyzers();
140      ParameterizeOperators();
141      base.OnSolutionCreatorChanged();
142    }
143    protected override void OnEvaluatorChanged() {
144      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
145      ParameterizeEvaluator();
146      ParameterizeAnalyzers();
147      ParameterizeOperators();
148      base.OnEvaluatorChanged();
149    }
150
151    private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
152      ParameterizeEvaluator();
153      ParameterizeAnalyzers();
154      ParameterizeOperators();
155    }
156    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
157      ParameterizeAnalyzers();
158      ParameterizeOperators();
159    }
160    private void WeightsParameter_ValueChanged(object sender, EventArgs e) {
161      Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
162      Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
163      ParameterizeSolutionCreator();
164      ParameterizeEvaluator();
165      ParameterizeOperators();
166      AdjustDistanceMatrix();
167    }
168    private void Weights_RowsChanged(object sender, EventArgs e) {
169      if (Weights.Rows != Weights.Columns)
170        ((IStringConvertibleMatrix)Weights).Columns = Weights.Rows;
171      else {
172        ParameterizeSolutionCreator();
173        ParameterizeEvaluator();
174        ParameterizeOperators();
175        AdjustDistanceMatrix();
176      }
177    }
178    private void Weights_ColumnsChanged(object sender, EventArgs e) {
179      if (Weights.Rows != Weights.Columns)
180        ((IStringConvertibleMatrix)Weights).Rows = Weights.Columns;
181      else {
182        ParameterizeSolutionCreator();
183        ParameterizeEvaluator();
184        ParameterizeOperators();
185        AdjustDistanceMatrix();
186      }
187    }
188    private void DistancesParameter_ValueChanged(object sender, EventArgs e) {
189      Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
190      Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
191      ParameterizeSolutionCreator();
192      ParameterizeEvaluator();
193      ParameterizeOperators();
194      AdjustWeightsMatrix();
195    }
196    private void Distances_RowsChanged(object sender, EventArgs e) {
197      if (Distances.Rows != Distances.Columns)
198        ((IStringConvertibleMatrix)Distances).Columns = Distances.Rows;
199      else {
200        ParameterizeSolutionCreator();
201        ParameterizeEvaluator();
202        ParameterizeOperators();
203        AdjustWeightsMatrix();
204      }
205    }
206    private void Distances_ColumnsChanged(object sender, EventArgs e) {
207      if (Distances.Rows != Distances.Columns)
208        ((IStringConvertibleMatrix)Distances).Rows = Distances.Columns;
209      else {
210        ParameterizeSolutionCreator();
211        ParameterizeEvaluator();
212        ParameterizeOperators();
213        AdjustWeightsMatrix();
214      }
215    }
216    #endregion
217
218    #region Helpers
219    [StorableHook(HookType.AfterDeserialization)]
220    private void AfterDeserializationHook() {
221      AttachEventHandlers();
222    }
223
224    private void AttachEventHandlers() {
225      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
226      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
227      WeightsParameter.ValueChanged += new EventHandler(WeightsParameter_ValueChanged);
228      Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
229      Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
230      DistancesParameter.ValueChanged += new EventHandler(DistancesParameter_ValueChanged);
231      Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
232      Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
233    }
234
235    private void InitializeOperators() {
236      Operators.AddRange(ApplicationManager.Manager.GetInstances<IPermutationOperator>());
237      Operators.Add(new BestQAPSolutionAnalyzer());
238      ParameterizeAnalyzers();
239      ParameterizeOperators();
240    }
241    private void ParameterizeSolutionCreator() {
242      if (SolutionCreator != null) {
243        SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.Absolute);
244        SolutionCreator.LengthParameter.Value = new IntValue(Weights.Rows);
245      }
246    }
247    private void ParameterizeEvaluator() {
248      if (Evaluator != null) {
249        Evaluator.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
250        Evaluator.DistancesParameter.ActualName = DistancesParameter.Name;
251        Evaluator.WeightsParameter.ActualName = WeightsParameter.Name;
252      }
253    }
254    private void ParameterizeAnalyzers() {
255      if (BestQAPSolutionAnalyzer != null) {
256        BestQAPSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
257        BestQAPSolutionAnalyzer.DistancesParameter.ActualName = DistancesParameter.Name;
258        BestQAPSolutionAnalyzer.WeightsParameter.ActualName = WeightsParameter.Name;
259        BestQAPSolutionAnalyzer.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
260        BestQAPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
261        BestQAPSolutionAnalyzer.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
262        BestQAPSolutionAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
263        BestQAPSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
264      }
265    }
266    private void ParameterizeOperators() {
267      foreach (IPermutationCrossover op in Operators.OfType<IPermutationCrossover>()) {
268        op.ParentsParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
269        op.ChildParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
270      }
271      foreach (IPermutationManipulator op in Operators.OfType<IPermutationManipulator>()) {
272        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
273      }
274      foreach (IPermutationMoveOperator op in Operators.OfType<IPermutationMoveOperator>()) {
275        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
276      }
277      if (Operators.OfType<IMoveGenerator>().Any()) {
278        string inversionMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationInversionMoveOperator>().First().InversionMoveParameter.ActualName;
279        foreach (IPermutationInversionMoveOperator op in Operators.OfType<IPermutationInversionMoveOperator>())
280          op.InversionMoveParameter.ActualName = inversionMove;
281        string translocationMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationTranslocationMoveOperator>().First().TranslocationMoveParameter.ActualName;
282        foreach (IPermutationTranslocationMoveOperator op in Operators.OfType<IPermutationTranslocationMoveOperator>())
283          op.TranslocationMoveParameter.ActualName = translocationMove;
284        string swapMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationSwap2MoveOperator>().First().Swap2MoveParameter.ActualName;
285        foreach (IPermutationSwap2MoveOperator op in Operators.OfType<IPermutationSwap2MoveOperator>()) {
286          op.Swap2MoveParameter.ActualName = swapMove;
287        }
288      }
289      foreach (var op in Operators.OfType<IPermutationMultiNeighborhoodShakingOperator>())
290        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
291    }
292
293    private void AdjustDistanceMatrix() {
294      if (Distances.Rows != Weights.Rows || Distances.Columns != Weights.Columns) {
295        ((IStringConvertibleMatrix)Distances).Rows = Weights.Rows;
296      }
297    }
298
299    private void AdjustWeightsMatrix() {
300      if (Weights.Rows != Distances.Rows || Weights.Columns != Distances.Columns) {
301        ((IStringConvertibleMatrix)Weights).Rows = Distances.Rows;
302      }
303    }
304    #endregion
305
306    public void ImportFileInstance(string filename) {
307      QAPLIBParser parser = new QAPLIBParser();
308      parser.Parse(filename);
309      if (parser.Error != null) throw parser.Error;
310      Distances = new DoubleMatrix(parser.Distances);
311      Weights = new DoubleMatrix(parser.Weights);
312      Name = "Quadratic Assignment Problem (imported from " + Path.GetFileNameWithoutExtension(filename) + ")";
313      Description = "Imported problem data using QAPLIBParser " + Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true).Cast<AssemblyFileVersionAttribute>().FirstOrDefault().Version + ".";
314      BestKnownQuality = null;
315      BestKnownSolution = null;
316      OnReset();
317    }
318
319    public void LoadEmbeddedInstance(string instance) {
320      using (Stream stream = Assembly.GetExecutingAssembly()
321        .GetManifestResourceStream(InstancePrefix + instance + ".dat")) {
322        QAPLIBParser parser = new QAPLIBParser();
323        parser.Parse(stream);
324        if (parser.Error != null) throw parser.Error;
325        Distances = new DoubleMatrix(parser.Distances);
326        Weights = new DoubleMatrix(parser.Weights);
327        Name = "Quadratic Assignment Problem (loaded instance " + instance + ")";
328        Description = "Loaded embedded problem data of instance " + instance + ".";
329        OnReset();
330      }
331      bool solutionExists = Assembly.GetExecutingAssembly()
332          .GetManifestResourceNames()
333          .Where(x => x.EndsWith(instance + ".sln"))
334          .Any();
335      if (solutionExists) {
336        using (Stream solStream = Assembly.GetExecutingAssembly()
337          .GetManifestResourceStream(InstancePrefix + instance + ".sln")) {
338          QAPLIBSolutionParser solParser = new QAPLIBSolutionParser();
339          solParser.Parse(solStream, true); // most sln's seem to be of the type index = "facility" => value = "location"
340          if (solParser.Error != null) throw solParser.Error;
341          if (!solParser.Quality.IsAlmost(QAPEvaluator.Apply(new Permutation(PermutationTypes.Absolute, solParser.Assignment), Weights, Distances))) {
342            solStream.Seek(0, SeekOrigin.Begin);
343            solParser.Reset();
344            solParser.Parse(solStream, false); // some sln's seem to be of the type index = "location" => value = "facility"
345            if (solParser.Error != null) throw solParser.Error;
346            if (solParser.Quality.IsAlmost(QAPEvaluator.Apply(new Permutation(PermutationTypes.Absolute, solParser.Assignment), Weights, Distances))) {
347              BestKnownQuality = new DoubleValue(solParser.Quality);
348              BestKnownSolution = new Permutation(PermutationTypes.Absolute, solParser.Assignment);
349            } else {
350              BestKnownQuality = new DoubleValue(solParser.Quality);
351              BestKnownSolution = null;
352            }
353          } else {
354            BestKnownQuality = new DoubleValue(solParser.Quality);
355            BestKnownSolution = new Permutation(PermutationTypes.Absolute, solParser.Assignment);
356          }
357        }
358      } else {
359        BestKnownQuality = null;
360        BestKnownSolution = null;
361      }
362    }
363  }
364}
Note: See TracBrowser for help on using the repository browser.