Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebJobManager/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs @ 15428

Last change on this file since 15428 was 13656, checked in by ascheibe, 9 years ago

#2582 created branch for Hive Web Job Manager

File size: 24.9 KB
RevLine 
[5558]1#region License Information
2/* HeuristicLab
[12012]3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[5558]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;
[7626]23using System.Collections.Generic;
[5558]24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Encodings.PermutationEncoding;
29using HeuristicLab.Optimization;
30using HeuristicLab.Parameters;
31using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
[5562]32using HeuristicLab.PluginInfrastructure;
[7558]33using HeuristicLab.Problems.Instances;
[5558]34
35namespace HeuristicLab.Problems.QuadraticAssignment {
[13173]36  [Item("Quadratic Assignment Problem (QAP)", "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.")]
[12504]37  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 140)]
[5558]38  [StorableClass]
[7558]39  public sealed class QuadraticAssignmentProblem : SingleObjectiveHeuristicOptimizationProblem<IQAPEvaluator, IPermutationCreator>, IStorableContent,
40    IProblemInstanceConsumer<QAPData>,
41    IProblemInstanceConsumer<TSPData> {
[5953]42    public string Filename { get; set; }
43
[5558]44
[13656]45
[5558]46    #region Parameter Properties
[13656]47    public IValueParameter<ItemSet<Permutation>> BestKnownSolutionsParameter
48    {
[6525]49      get { return (IValueParameter<ItemSet<Permutation>>)Parameters["BestKnownSolutions"]; }
[6342]50    }
[13656]51    public IValueParameter<Permutation> BestKnownSolutionParameter
52    {
[5641]53      get { return (IValueParameter<Permutation>)Parameters["BestKnownSolution"]; }
[5558]54    }
[13656]55    public IValueParameter<DoubleMatrix> WeightsParameter
56    {
[5641]57      get { return (IValueParameter<DoubleMatrix>)Parameters["Weights"]; }
[5558]58    }
[13656]59    public IValueParameter<DoubleMatrix> DistancesParameter
60    {
[5838]61      get { return (IValueParameter<DoubleMatrix>)Parameters["Distances"]; }
[5558]62    }
[13656]63    public IValueParameter<DoubleValue> LowerBoundParameter
64    {
[7877]65      get { return (IValueParameter<DoubleValue>)Parameters["LowerBound"]; }
66    }
[13656]67    public IValueParameter<DoubleValue> AverageQualityParameter
68    {
[7877]69      get { return (IValueParameter<DoubleValue>)Parameters["AverageQuality"]; }
70    }
[5558]71    #endregion
72
73    #region Properties
[13656]74    public ItemSet<Permutation> BestKnownSolutions
75    {
[6342]76      get { return BestKnownSolutionsParameter.Value; }
77      set { BestKnownSolutionsParameter.Value = value; }
78    }
[13656]79    public Permutation BestKnownSolution
80    {
[5558]81      get { return BestKnownSolutionParameter.Value; }
82      set { BestKnownSolutionParameter.Value = value; }
83    }
[13656]84    public DoubleMatrix Weights
85    {
[5558]86      get { return WeightsParameter.Value; }
87      set { WeightsParameter.Value = value; }
88    }
[13656]89    public DoubleMatrix Distances
90    {
[5838]91      get { return DistancesParameter.Value; }
92      set { DistancesParameter.Value = value; }
[5558]93    }
[13656]94    public DoubleValue LowerBound
95    {
[7877]96      get { return LowerBoundParameter.Value; }
97      set { LowerBoundParameter.Value = value; }
98    }
[13656]99    public DoubleValue AverageQuality
100    {
[7877]101      get { return AverageQualityParameter.Value; }
102      set { AverageQualityParameter.Value = value; }
103    }
[5563]104
[13656]105    private BestQAPSolutionAnalyzer BestQAPSolutionAnalyzer
106    {
[5583]107      get { return Operators.OfType<BestQAPSolutionAnalyzer>().FirstOrDefault(); }
108    }
[6342]109
[13656]110    private QAPAlleleFrequencyAnalyzer QAPAlleleFrequencyAnalyzer
111    {
[6342]112      get { return Operators.OfType<QAPAlleleFrequencyAnalyzer>().FirstOrDefault(); }
113    }
114
[13656]115    private QAPPopulationDiversityAnalyzer QAPPopulationDiversityAnalyzer
116    {
[6342]117      get { return Operators.OfType<QAPPopulationDiversityAnalyzer>().FirstOrDefault(); }
118    }
[5558]119    #endregion
120
121    [StorableConstructor]
122    private QuadraticAssignmentProblem(bool deserializing) : base(deserializing) { }
[5562]123    private QuadraticAssignmentProblem(QuadraticAssignmentProblem original, Cloner cloner)
[5558]124      : base(original, cloner) {
[7351]125      RegisterEventHandlers();
[5558]126    }
127    public QuadraticAssignmentProblem()
[5931]128      : base(new QAPEvaluator(), new RandomPermutationCreator()) {
[6525]129      Parameters.Add(new OptionalValueParameter<ItemSet<Permutation>>("BestKnownSolutions", "The list of best known solutions which is updated whenever a new better solution is found or may be the optimal solution if it is known beforehand.", null));
[5648]130      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));
[5558]131      Parameters.Add(new ValueParameter<DoubleMatrix>("Weights", "The strength of the connection between the facilities.", new DoubleMatrix(5, 5)));
[5838]132      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)));
[7877]133      Parameters.Add(new OptionalValueParameter<DoubleValue>("LowerBound", "The Gilmore-Lawler lower bound to the solution quality."));
134      Parameters.Add(new OptionalValueParameter<DoubleValue>("AverageQuality", "The expected quality of a random solution."));
[5558]135
[6939]136      Maximization.Value = false;
137      MaximizationParameter.Hidden = true;
[5563]138
[7877]139      WeightsParameter.GetsCollected = false;
[5558]140      Weights = new DoubleMatrix(new double[,] {
141        { 0, 1, 0, 0, 1 },
142        { 1, 0, 1, 0, 0 },
143        { 0, 1, 0, 1, 0 },
144        { 0, 0, 1, 0, 1 },
145        { 1, 0, 0, 1, 0 }
146      });
147
[7877]148      DistancesParameter.GetsCollected = false;
[5838]149      Distances = new DoubleMatrix(new double[,] {
[5558]150        {   0, 360, 582, 582, 360 },
151        { 360,   0, 360, 582, 582 },
152        { 582, 360,   0, 360, 582 },
153        { 582, 582, 360,   0, 360 },
154        { 360, 582, 582, 360,   0 }
155      });
156
[5931]157      SolutionCreator.PermutationParameter.ActualName = "Assignment";
158      ParameterizeSolutionCreator();
159      ParameterizeEvaluator();
[5558]160
161      InitializeOperators();
[7351]162      RegisterEventHandlers();
[5558]163    }
164
165    public override IDeepCloneable Clone(Cloner cloner) {
166      return new QuadraticAssignmentProblem(this, cloner);
167    }
168
[6342]169    [StorableHook(HookType.AfterDeserialization)]
170    private void AfterDeserialization() {
171      // BackwardsCompatibility3.3
172      #region Backwards compatible code, remove with 3.4
173      if (!Parameters.ContainsKey("BestKnownSolutions")) {
[6525]174        Parameters.Add(new OptionalValueParameter<ItemSet<Permutation>>("BestKnownSolutions", "The list of best known solutions which is updated whenever a new better solution is found or may be the optimal solution if it is known beforehand.", null));
175      } else if (Parameters["BestKnownSolutions"].GetType().Equals(typeof(OptionalValueParameter<ItemList<Permutation>>))) {
176        ItemList<Permutation> list = ((OptionalValueParameter<ItemList<Permutation>>)Parameters["BestKnownSolutions"]).Value;
[6540]177        Parameters.Remove("BestKnownSolutions");
[6571]178        Parameters.Add(new OptionalValueParameter<ItemSet<Permutation>>("BestKnownSolutions", "The list of best known solutions which is updated whenever a new better solution is found or may be the optimal solution if it is known beforehand.", (list != null ? new ItemSet<Permutation>(list) : null)));
[6342]179      }
180      if (Parameters.ContainsKey("DistanceMatrix")) {
[6525]181        DoubleMatrix d = ((ValueParameter<DoubleMatrix>)Parameters["DistanceMatrix"]).Value;
[6342]182        Parameters.Remove("DistanceMatrix");
[6525]183        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.", d));
[6342]184      }
[7877]185      if (!Parameters.ContainsKey("LowerBound")) {
186        Parameters.Add(new OptionalValueParameter<DoubleValue>("LowerBound", "The Gilmore-Lawler lower bound to the solution quality."));
187        LowerBound = new DoubleValue(GilmoreLawlerBoundCalculator.CalculateLowerBound(Weights, Distances));
188      }
189      if (!Parameters.ContainsKey("AverageQuality")) {
190        Parameters.Add(new OptionalValueParameter<DoubleValue>("AverageQuality", "The expected quality of a random solution."));
[8910]191        AverageQuality = new DoubleValue(ComputeAverageQuality());
[7877]192      }
193      #endregion
[7351]194      RegisterEventHandlers();
[6342]195    }
196
[5558]197    #region Events
[5562]198    protected override void OnSolutionCreatorChanged() {
199      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
200      ParameterizeSolutionCreator();
201      ParameterizeEvaluator();
[5583]202      ParameterizeAnalyzers();
[5562]203      ParameterizeOperators();
204      base.OnSolutionCreatorChanged();
[5558]205    }
[5562]206    protected override void OnEvaluatorChanged() {
[5583]207      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
[5562]208      ParameterizeEvaluator();
[5583]209      ParameterizeAnalyzers();
[5562]210      ParameterizeOperators();
211      base.OnEvaluatorChanged();
[5558]212    }
[5562]213
214    private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
215      ParameterizeEvaluator();
[5583]216      ParameterizeAnalyzers();
[5562]217      ParameterizeOperators();
[5558]218    }
[5583]219    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
220      ParameterizeAnalyzers();
221      ParameterizeOperators();
222    }
[5562]223    private void WeightsParameter_ValueChanged(object sender, EventArgs e) {
224      Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
[5855]225      Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
[7877]226      Weights.ToStringChanged += new EventHandler(Weights_ToStringChanged);
[5562]227      ParameterizeSolutionCreator();
228      ParameterizeEvaluator();
229      ParameterizeOperators();
[5855]230      AdjustDistanceMatrix();
[5558]231    }
[5562]232    private void Weights_RowsChanged(object sender, EventArgs e) {
[5855]233      if (Weights.Rows != Weights.Columns)
234        ((IStringConvertibleMatrix)Weights).Columns = Weights.Rows;
235      else {
236        ParameterizeSolutionCreator();
237        ParameterizeEvaluator();
238        ParameterizeOperators();
239        AdjustDistanceMatrix();
240      }
241    }
242    private void Weights_ColumnsChanged(object sender, EventArgs e) {
243      if (Weights.Rows != Weights.Columns)
244        ((IStringConvertibleMatrix)Weights).Rows = Weights.Columns;
245      else {
246        ParameterizeSolutionCreator();
247        ParameterizeEvaluator();
248        ParameterizeOperators();
249        AdjustDistanceMatrix();
250      }
251    }
[7877]252    private void Weights_ToStringChanged(object sender, EventArgs e) {
253      UpdateParameterValues();
254    }
[5855]255    private void DistancesParameter_ValueChanged(object sender, EventArgs e) {
256      Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
257      Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
[7877]258      Distances.ToStringChanged += new EventHandler(Distances_ToStringChanged);
[5562]259      ParameterizeSolutionCreator();
260      ParameterizeEvaluator();
261      ParameterizeOperators();
[5855]262      AdjustWeightsMatrix();
[5562]263    }
[5855]264    private void Distances_RowsChanged(object sender, EventArgs e) {
265      if (Distances.Rows != Distances.Columns)
266        ((IStringConvertibleMatrix)Distances).Columns = Distances.Rows;
267      else {
268        ParameterizeSolutionCreator();
269        ParameterizeEvaluator();
270        ParameterizeOperators();
271        AdjustWeightsMatrix();
272      }
273    }
274    private void Distances_ColumnsChanged(object sender, EventArgs e) {
275      if (Distances.Rows != Distances.Columns)
276        ((IStringConvertibleMatrix)Distances).Rows = Distances.Columns;
277      else {
278        ParameterizeSolutionCreator();
279        ParameterizeEvaluator();
280        ParameterizeOperators();
281        AdjustWeightsMatrix();
282      }
283    }
[7877]284    private void Distances_ToStringChanged(object sender, EventArgs e) {
285      UpdateParameterValues();
286    }
[5558]287    #endregion
288
[7351]289    private void RegisterEventHandlers() {
[5598]290      SolutionCreator.PermutationParameter.ActualNameChanged += new EventHandler(SolutionCreator_PermutationParameter_ActualNameChanged);
291      Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
[5562]292      WeightsParameter.ValueChanged += new EventHandler(WeightsParameter_ValueChanged);
293      Weights.RowsChanged += new EventHandler(Weights_RowsChanged);
[5855]294      Weights.ColumnsChanged += new EventHandler(Weights_ColumnsChanged);
[7877]295      Weights.ToStringChanged += new EventHandler(Weights_ToStringChanged);
[5855]296      DistancesParameter.ValueChanged += new EventHandler(DistancesParameter_ValueChanged);
297      Distances.RowsChanged += new EventHandler(Distances_RowsChanged);
298      Distances.ColumnsChanged += new EventHandler(Distances_ColumnsChanged);
[7877]299      Distances.ToStringChanged += new EventHandler(Distances_ToStringChanged);
[5558]300    }
301
[7877]302    #region Helpers
[5558]303    private void InitializeOperators() {
[7626]304      var defaultOperators = new HashSet<IPermutationOperator>(new IPermutationOperator[] {
305        new PartiallyMatchedCrossover(),
306        new Swap2Manipulator(),
307        new ExhaustiveSwap2MoveGenerator()
308      });
309      Operators.AddRange(defaultOperators);
310      Operators.AddRange(ApplicationManager.Manager.GetInstances<IPermutationOperator>().Except(defaultOperators, new TypeEqualityComparer<IPermutationOperator>()));
[6088]311      Operators.RemoveAll(x => x is ISingleObjectiveMoveEvaluator);
312      Operators.AddRange(ApplicationManager.Manager.GetInstances<IQAPMoveEvaluator>());
[5583]313      Operators.Add(new BestQAPSolutionAnalyzer());
[6342]314      Operators.Add(new QAPAlleleFrequencyAnalyzer());
315      Operators.Add(new QAPPopulationDiversityAnalyzer());
[11300]316
317      Operators.Add(new QAPExhaustiveInsertionLocalImprovement());
318      Operators.Add(new QAPExhaustiveInversionLocalImprovement());
319      Operators.Add(new QAPStochasticScrambleLocalImprovement());
[6342]320      Operators.Add(new QAPExhaustiveSwap2LocalImprovement());
[11300]321
[9029]322      Operators.Add(new QAPSimilarityCalculator());
[5583]323      ParameterizeAnalyzers();
[5563]324      ParameterizeOperators();
[5558]325    }
326    private void ParameterizeSolutionCreator() {
[5563]327      if (SolutionCreator != null) {
328        SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.Absolute);
329        SolutionCreator.LengthParameter.Value = new IntValue(Weights.Rows);
330      }
[5558]331    }
332    private void ParameterizeEvaluator() {
[5563]333      if (Evaluator != null) {
334        Evaluator.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
[5838]335        Evaluator.DistancesParameter.ActualName = DistancesParameter.Name;
[5563]336        Evaluator.WeightsParameter.ActualName = WeightsParameter.Name;
337      }
[5558]338    }
[5583]339    private void ParameterizeAnalyzers() {
340      if (BestQAPSolutionAnalyzer != null) {
341        BestQAPSolutionAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
[5838]342        BestQAPSolutionAnalyzer.DistancesParameter.ActualName = DistancesParameter.Name;
[5583]343        BestQAPSolutionAnalyzer.WeightsParameter.ActualName = WeightsParameter.Name;
344        BestQAPSolutionAnalyzer.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
345        BestQAPSolutionAnalyzer.ResultsParameter.ActualName = "Results";
346        BestQAPSolutionAnalyzer.BestKnownQualityParameter.ActualName = BestKnownQualityParameter.Name;
[6342]347        BestQAPSolutionAnalyzer.BestKnownSolutionsParameter.ActualName = BestKnownSolutionsParameter.Name;
[5583]348        BestQAPSolutionAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
349      }
[6342]350      if (QAPAlleleFrequencyAnalyzer != null) {
351        QAPAlleleFrequencyAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
352        QAPAlleleFrequencyAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
353        QAPAlleleFrequencyAnalyzer.DistancesParameter.ActualName = DistancesParameter.Name;
354        QAPAlleleFrequencyAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
355        QAPAlleleFrequencyAnalyzer.ResultsParameter.ActualName = "Results";
356        QAPAlleleFrequencyAnalyzer.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
357        QAPAlleleFrequencyAnalyzer.WeightsParameter.ActualName = WeightsParameter.Name;
358      }
359      if (QAPPopulationDiversityAnalyzer != null) {
360        QAPPopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
361        QAPPopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
362        QAPPopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
363        QAPPopulationDiversityAnalyzer.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
364      }
[5583]365    }
[5562]366    private void ParameterizeOperators() {
367      foreach (IPermutationCrossover op in Operators.OfType<IPermutationCrossover>()) {
368        op.ParentsParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
369        op.ChildParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
370      }
371      foreach (IPermutationManipulator op in Operators.OfType<IPermutationManipulator>()) {
372        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
373      }
374      foreach (IPermutationMoveOperator op in Operators.OfType<IPermutationMoveOperator>()) {
375        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
376      }
[5563]377      if (Operators.OfType<IMoveGenerator>().Any()) {
[7768]378        if (Operators.OfType<IMoveGenerator>().OfType<IPermutationInversionMoveOperator>().Any()) {
379          string inversionMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationInversionMoveOperator>().First().InversionMoveParameter.ActualName;
380          foreach (IPermutationInversionMoveOperator op in Operators.OfType<IPermutationInversionMoveOperator>())
381            op.InversionMoveParameter.ActualName = inversionMove;
[5785]382        }
[7768]383        if (Operators.OfType<IMoveGenerator>().OfType<IPermutationTranslocationMoveOperator>().Any()) {
384          string translocationMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationTranslocationMoveOperator>().First().TranslocationMoveParameter.ActualName;
385          foreach (IPermutationTranslocationMoveOperator op in Operators.OfType<IPermutationTranslocationMoveOperator>())
386            op.TranslocationMoveParameter.ActualName = translocationMove;
387        }
388        if (Operators.OfType<IMoveGenerator>().OfType<IPermutationSwap2MoveOperator>().Any()) {
389          string swapMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationSwap2MoveOperator>().First().Swap2MoveParameter.ActualName;
390          foreach (IPermutationSwap2MoveOperator op in Operators.OfType<IPermutationSwap2MoveOperator>()) {
391            op.Swap2MoveParameter.ActualName = swapMove;
392          }
393        }
[5563]394      }
[6042]395      foreach (var op in Operators.OfType<IPermutationMultiNeighborhoodShakingOperator>())
396        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
[6342]397
398      QAPExhaustiveSwap2LocalImprovement localOpt = Operators.OfType<QAPExhaustiveSwap2LocalImprovement>().SingleOrDefault();
399      if (localOpt != null) {
400        localOpt.AssignmentParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
401        localOpt.DistancesParameter.ActualName = DistancesParameter.Name;
402        localOpt.MaximizationParameter.ActualName = MaximizationParameter.Name;
403        localOpt.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
404        localOpt.WeightsParameter.ActualName = WeightsParameter.Name;
405      }
[9029]406
407      QAPSimilarityCalculator similarityCalculator = Operators.OfType<QAPSimilarityCalculator>().SingleOrDefault();
408      if (similarityCalculator != null) {
409        similarityCalculator.SolutionVariableName = SolutionCreator.PermutationParameter.ActualName;
410        similarityCalculator.QualityVariableName = Evaluator.QualityParameter.ActualName;
411      }
[5562]412    }
[5598]413
[5855]414    private void AdjustDistanceMatrix() {
415      if (Distances.Rows != Weights.Rows || Distances.Columns != Weights.Columns) {
416        ((IStringConvertibleMatrix)Distances).Rows = Weights.Rows;
417      }
418    }
419
420    private void AdjustWeightsMatrix() {
421      if (Weights.Rows != Distances.Rows || Weights.Columns != Distances.Columns) {
422        ((IStringConvertibleMatrix)Weights).Rows = Distances.Rows;
423      }
424    }
[7877]425
426    private void UpdateParameterValues() {
[8910]427      Permutation lbSolution;
428      // calculate the optimum of a LAP relaxation and use it as lower bound of our QAP
429      LowerBound = new DoubleValue(GilmoreLawlerBoundCalculator.CalculateLowerBound(Weights, Distances, out lbSolution));
430      // evalute the LAP optimal solution as if it was a QAP solution
431      var lbSolutionQuality = QAPEvaluator.Apply(lbSolution, Weights, Distances);
432      // in case both qualities are the same it means that the LAP optimum is also a QAP optimum
433      if (LowerBound.Value.IsAlmost(lbSolutionQuality)) {
434        BestKnownSolution = lbSolution;
435        BestKnownQuality = new DoubleValue(LowerBound.Value);
436      }
437      AverageQuality = new DoubleValue(ComputeAverageQuality());
[7877]438    }
[8910]439
440    private double ComputeAverageQuality() {
441      double rt = 0, rd = 0, wt = 0, wd = 0;
442      int n = Weights.Rows;
443      for (int i = 0; i < n; i++)
444        for (int j = 0; j < n; j++) {
445          if (i == j) {
446            rd += Distances[i, i];
447            wd += Weights[i, i];
448          } else {
449            rt += Distances[i, j];
450            wt += Weights[i, j];
451          }
452        }
453
454      return rt * wt / (n * (n - 1)) + rd * wd / n;
455    }
[5558]456    #endregion
[5562]457
[7558]458    public void Load(QAPData data) {
459      var weights = new DoubleMatrix(data.Weights);
460      var distances = new DoubleMatrix(data.Distances);
[7641]461      Name = data.Name;
462      Description = data.Description;
[7558]463      Load(weights, distances);
[8553]464      if (data.BestKnownQuality.HasValue) BestKnownQuality = new DoubleValue(data.BestKnownQuality.Value);
[7558]465      EvaluateAndLoadAssignment(data.BestKnownAssignment);
[5562]466      OnReset();
467    }
[5563]468
[7558]469    public void Load(TSPData data) {
470      if (data.Dimension > 1000)
471        throw new System.IO.InvalidDataException("Instances with more than 1000 customers are not supported by the QAP.");
472      var weights = new DoubleMatrix(data.Dimension, data.Dimension);
473      for (int i = 0; i < data.Dimension; i++)
474        weights[i, (i + 1) % data.Dimension] = 1;
475      var distances = new DoubleMatrix(data.GetDistanceMatrix());
[7641]476      Name = data.Name;
477      Description = data.Description;
[7558]478      Load(weights, distances);
[8553]479      if (data.BestKnownQuality.HasValue) BestKnownQuality = new DoubleValue(data.BestKnownQuality.Value);
[7558]480      EvaluateAndLoadAssignment(data.BestKnownTour);
[6891]481      OnReset();
[5563]482    }
[6952]483
[7558]484    public void Load(DoubleMatrix weights, DoubleMatrix distances) {
485      if (weights == null || weights.Rows == 0)
486        throw new System.IO.InvalidDataException("The given instance does not contain weights!");
487      if (weights.Rows != weights.Columns)
488        throw new System.IO.InvalidDataException("The weights matrix is not a square matrix!");
489      if (distances == null || distances.Rows == 0)
490        throw new System.IO.InvalidDataException("The given instance does not contain distances!");
491      if (distances.Rows != distances.Columns)
492        throw new System.IO.InvalidDataException("The distances matrix is not a square matrix!");
493      if (weights.Rows != distances.Columns)
494        throw new System.IO.InvalidDataException("The weights matrix and the distance matrix are not of equal size!");
[6952]495
[7558]496      Weights = weights;
497      Distances = distances;
[6952]498
[7558]499      BestKnownQuality = null;
500      BestKnownSolution = null;
501      BestKnownSolutions = null;
[7877]502      UpdateParameterValues();
[7558]503    }
[6952]504
[7558]505    public void EvaluateAndLoadAssignment(int[] assignment) {
506      if (assignment == null || assignment.Length == 0) return;
507      var vector = new Permutation(PermutationTypes.Absolute, assignment);
508      var result = QAPEvaluator.Apply(vector, Weights, Distances);
509      BestKnownQuality = new DoubleValue(result);
510      BestKnownSolution = vector;
511      BestKnownSolutions = new ItemSet<Permutation>();
512      BestKnownSolutions.Add((Permutation)vector.Clone());
[6952]513    }
[5558]514  }
515}
Note: See TracBrowser for help on using the repository browser.