Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Problems.LinearAssignment/3.3/LinearAssignmentProblem.cs @ 17695

Last change on this file since 17695 was 17695, checked in by abeham, 4 years ago

#2521:

  • Moving solution creator parameter from problems to algorithms (breaking wiring in some HeuristicOptimizationProblems)
  • Disallowing evaluator or encoding changes in encoding-specific base problems (to avoid confusion in derived problems whether this needs to be handled or not)
  • Added private set to ReferenceParameter property (serialization)
File size: 11.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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.Drawing;
24using System.Linq;
25using System.Threading;
26using HEAL.Attic;
27using HeuristicLab.Analysis;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.PermutationEncoding;
32using HeuristicLab.Optimization;
33using HeuristicLab.Optimization.Operators;
34using HeuristicLab.Parameters;
35using HeuristicLab.PluginInfrastructure;
36
37namespace HeuristicLab.Problems.LinearAssignment {
38  [Item("Linear Assignment Problem (LAP)", "In the linear assignment problem (LAP) an assignment of workers to jobs has to be found such that each worker is assigned to exactly one job, each job is assigned to exactly one worker and the sum of the resulting costs is minimal (or maximal).")]
39  [Creatable(CreatableAttribute.Categories.CombinatorialProblems, Priority = 130)]
40  [StorableType("7766E004-A93D-4CA6-8012-AE5E8F4C4D85")]
41  public sealed class LinearAssignmentProblem : PermutationProblem {
42    public static readonly string CostsDescription = "The cost matrix that describes the assignment of rows to columns.";
43    public static readonly string RowNamesDescription = "The elements represented by the rows of the costs matrix.";
44    public static readonly string ColumnNamesDescription = "The elements represented by the columns of the costs matrix.";
45
46    public override Image ItemImage {
47      get { return HeuristicLab.Common.Resources.VSImageLibrary.Type; }
48    }
49
50    #region Parameter Properties
51    public IValueParameter<DoubleMatrix> CostsParameter {
52      get { return (IValueParameter<DoubleMatrix>)Parameters["Costs"]; }
53    }
54    public IValueParameter<ItemSet<Permutation>> BestKnownSolutionsParameter {
55      get { return (IValueParameter<ItemSet<Permutation>>)Parameters["BestKnownSolutions"]; }
56    }
57    public IValueParameter<Permutation> BestKnownSolutionParameter {
58      get { return (IValueParameter<Permutation>)Parameters["BestKnownSolution"]; }
59    }
60    public IValueParameter<StringArray> RowNamesParameter {
61      get { return (IValueParameter<StringArray>)Parameters["RowNames"]; }
62    }
63    public IValueParameter<StringArray> ColumnNamesParameter {
64      get { return (IValueParameter<StringArray>)Parameters["ColumnNames"]; }
65    }
66    private IResultParameter<LAPAssignment> BestLAPSolutionParameter {
67      get { return (IResultParameter<LAPAssignment>)Parameters["Best LAP Solution"]; }
68    }
69    #endregion
70
71    #region Properties
72    public DoubleMatrix Costs {
73      get { return CostsParameter.Value; }
74      set { CostsParameter.Value = value; }
75    }
76    public StringArray RowNames {
77      get { return RowNamesParameter.Value; }
78      set { RowNamesParameter.Value = value; }
79    }
80    public StringArray ColumnNames {
81      get { return ColumnNamesParameter.Value; }
82      set { ColumnNamesParameter.Value = value; }
83    }
84    public ItemSet<Permutation> BestKnownSolutions {
85      get { return BestKnownSolutionsParameter.Value; }
86      set { BestKnownSolutionsParameter.Value = value; }
87    }
88    public Permutation BestKnownSolution {
89      get { return BestKnownSolutionParameter.Value; }
90      set { BestKnownSolutionParameter.Value = value; }
91    }
92    #endregion
93
94    [StorableConstructor]
95    private LinearAssignmentProblem(StorableConstructorFlag _) : base(_) { }
96    private LinearAssignmentProblem(LinearAssignmentProblem original, Cloner cloner)
97      : base(original, cloner) {
98      AttachEventHandlers();
99    }
100    public LinearAssignmentProblem()
101      : base(new PermutationEncoding("Assignment")) {
102      Encoding.LengthParameter.ReadOnly = DimensionRefParameter.ReadOnly = true;
103
104      Parameters.Add(new ValueParameter<DoubleMatrix>("Costs", CostsDescription, new DoubleMatrix(3, 3)));
105      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));
106      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));
107      Parameters.Add(new OptionalValueParameter<StringArray>("RowNames", RowNamesDescription));
108      Parameters.Add(new OptionalValueParameter<StringArray>("ColumnNames", ColumnNamesDescription));
109      Parameters.Add(new ResultParameter<LAPAssignment>("Best LAP Solution", "The best so far LAP solution found."));
110
111      ((ValueParameter<DoubleMatrix>)CostsParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
112      ((OptionalValueParameter<StringArray>)RowNamesParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
113      ((OptionalValueParameter<StringArray>)ColumnNamesParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
114
115      RowNames = new StringArray(new string[] { "Eric", "Robert", "Allison" });
116      ColumnNames = new StringArray(new string[] { "MRI", "Blood test", "Angiogram" });
117      Costs[0, 0] = 4; Costs[0, 1] = 5; Costs[0, 2] = 3;
118      Costs[1, 0] = 6; Costs[1, 1] = 6; Costs[1, 2] = 4;
119      Costs[2, 0] = 5; Costs[2, 1] = 5; Costs[2, 2] = 1;
120
121      InitializeOperators();
122      Parameterize();
123      AttachEventHandlers();
124    }
125
126    public override IDeepCloneable Clone(Cloner cloner) {
127      return new LinearAssignmentProblem(this, cloner);
128    }
129
130    public override ISingleObjectiveEvaluationResult Evaluate(Permutation assignment, IRandom random, CancellationToken cancellationToken) {
131      var costs = Costs;
132
133      int len = assignment.Length;
134      double quality = 0;
135      for (int i = 0; i < len; i++) {
136        quality += costs[i, assignment[i]];
137      }
138
139      return new SingleObjectiveEvaluationResult(quality);
140    }
141
142    public override void Analyze(Permutation[] permutations, double[] qualities, ResultCollection results, IRandom random) {
143      base.Analyze(permutations, qualities, results, random);
144
145      var costs = Costs;
146      var rowNames = RowNames;
147      var columnNames = ColumnNames;
148      bool max = Maximization;
149
150      var sorted = qualities.Select((x, index) => new { Index = index, Quality = x }).OrderBy(x => x.Quality).ToArray();
151      if (max) Array.Reverse(sorted);
152      int i = sorted[0].Index;
153      var best = Tuple.Create(permutations[i], qualities[i]);
154
155      if (double.IsNaN(BestKnownQuality) || IsBetter(best.Item2, BestKnownQuality)) {
156        // if there isn't a best-known quality or we improved the best-known quality we'll add the current solution as best-known
157        BestKnownQuality = best.Item2;
158        BestKnownSolution = (Permutation)best.Item1.Clone();
159        BestKnownSolutions = new ItemSet<Permutation>(new PermutationEqualityComparer());
160        BestKnownSolutions.Add((Permutation)best.Item1.Clone());
161      } else if (BestKnownQuality == best.Item2) {
162        // if we matched the best-known quality we'll try to set the best-known solution if it isn't null
163        // and try to add it to the pool of best solutions if it is different
164        if (BestKnownSolution == null) BestKnownSolution = (Permutation)best.Item1.Clone();
165        if (BestKnownSolutions == null) BestKnownSolutions = new ItemSet<Permutation>(new PermutationEqualityComparer());
166
167        foreach (var k in sorted) { // for each solution that we found check if it is in the pool of best-knowns
168          if (IsBetter(best.Item2, k.Quality)) break; // stop when we reached a solution worse than the best-known quality
169          var p = permutations[k.Index];
170          if (!BestKnownSolutions.Contains(p))
171            BestKnownSolutions.Add((Permutation)permutations[k.Index].Clone());
172        }
173      }
174
175      LAPAssignment solution = BestLAPSolutionParameter.ActualValue;
176      if (solution == null) {
177        solution = new LAPAssignment(costs, rowNames, columnNames, (Permutation)best.Item1.Clone(), new DoubleValue(best.Item2));
178        BestLAPSolutionParameter.ActualValue = solution;
179      } else {
180        if (IsBetter(best.Item2, solution.Quality.Value)) {
181          solution.Costs = costs;
182          solution.Assignment = (Permutation)best.Item1.Clone();
183          solution.Quality.Value = best.Item2;
184          if (rowNames != null)
185            solution.RowNames = rowNames;
186          else solution.RowNames = null;
187          if (columnNames != null)
188            solution.ColumnNames = columnNames;
189          else solution.ColumnNames = null;
190        }
191      }
192
193    }
194
195    #region Events
196    protected override void OnOperatorsChanged() {
197      base.OnOperatorsChanged();
198      Parameterize();
199    }
200    private void Costs_RowsChanged(object sender, EventArgs e) {
201      if (Costs.Rows != Costs.Columns) {
202        ((IStringConvertibleMatrix)Costs).Columns = Costs.Rows;
203        Parameterize();
204      }
205    }
206    private void Costs_ColumnsChanged(object sender, EventArgs e) {
207      if (Costs.Rows != Costs.Columns) {
208        ((IStringConvertibleMatrix)Costs).Rows = Costs.Columns;
209        Parameterize();
210      }
211    }
212    private void Costs_Reset(object sender, EventArgs e) {
213      Parameterize();
214    }
215    private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
216      Parameterize();
217    }
218    #endregion
219
220    #region Helpers
221    [StorableHook(HookType.AfterDeserialization)]
222    private void AfterDeserialization() {
223      AttachEventHandlers();
224    }
225
226    private void AttachEventHandlers() {
227      Costs.RowsChanged += new EventHandler(Costs_RowsChanged);
228      Costs.ColumnsChanged += new EventHandler(Costs_ColumnsChanged);
229      Costs.Reset += new EventHandler(Costs_Reset);
230    }
231
232    private void InitializeOperators() {
233      Operators.AddRange(ApplicationManager.Manager.GetInstances<IPermutationOperator>());
234      Operators.RemoveAll(x => x is IMoveOperator);
235
236      Operators.Add(new HammingSimilarityCalculator());
237      Operators.Add(new QualitySimilarityCalculator());
238      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
239    }
240
241    private void Parameterize() {
242      if (Costs.Rows != Dimension) Dimension = Costs.Rows;
243      foreach (var similarityCalculator in Operators.OfType<ISolutionSimilarityCalculator>()) {
244        similarityCalculator.SolutionVariableName = Encoding.Name;
245        similarityCalculator.QualityVariableName = Evaluator.QualityParameter.ActualName;
246      }
247    }
248    #endregion
249  }
250}
Note: See TracBrowser for help on using the repository browser.