source: branches/2521_ProblemRefactoring/HeuristicLab.Optimization/3.3/BasicProblems/SingleObjectiveProblem.cs @ 17546

Last change on this file since 17546 was 17546, checked in by abeham, 4 months ago

#2521: Introduce class to make parameter change handling easier, fix bug in SingleObjectiveProblem regarding MaximizationChanged

File size: 10.4 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.Collections.Generic;
24using System.Linq;
25using System.Threading;
26using HEAL.Attic;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Parameters;
31
32namespace HeuristicLab.Optimization {
33  [StorableType("2697320D-0259-44BB-BD71-7EE1B10F664C")]
34  public abstract class SingleObjectiveProblem<TEncoding, TEncodedSolution> :
35    Problem<TEncoding, TEncodedSolution, SingleObjectiveEvaluator<TEncodedSolution>>,
36    ISingleObjectiveProblem<TEncoding, TEncodedSolution>,
37    ISingleObjectiveProblemDefinition<TEncoding, TEncodedSolution>
38    where TEncoding : class, IEncoding<TEncodedSolution>
39    where TEncodedSolution : class, IEncodedSolution {
40
41    [Storable] protected IValueParameter<DoubleValue> BestKnownQualityParameter { get; private set; }
42    [Storable] protected IValueParameter<BoolValue> MaximizationParameter { get; private set; }
43
44    public double BestKnownQuality {
45      get {
46        if (BestKnownQualityParameter.Value == null) return double.NaN;
47        return BestKnownQualityParameter.Value.Value;
48      }
49      set {
50        if (double.IsNaN(value)) {
51          BestKnownQualityParameter.Value = null;
52          return;
53        }
54        if (BestKnownQualityParameter.Value == null) BestKnownQualityParameter.Value = new DoubleValue(value);
55        else BestKnownQualityParameter.Value.Value = value;
56      }
57    }
58
59    public bool Maximization {
60      get { return MaximizationParameter.Value.Value; }
61      protected set {
62        if (Maximization == value) return;
63        MaximizationParameter.ForceValue(new BoolValue(value, @readonly: true));
64      }
65    }
66
67    [StorableConstructor]
68    protected SingleObjectiveProblem(StorableConstructorFlag _) : base(_) { }
69
70    protected SingleObjectiveProblem(SingleObjectiveProblem<TEncoding, TEncodedSolution> original, Cloner cloner)
71      : base(original, cloner) {
72      BestKnownQualityParameter = cloner.Clone(original.BestKnownQualityParameter);
73      MaximizationParameter = cloner.Clone(original.MaximizationParameter);
74      ParameterizeOperators();
75      RegisterEventHandlers();
76    }
77
78    protected SingleObjectiveProblem() : base() {
79      MaximizationParameter = new ValueParameter<BoolValue>("Maximization", "Whether the problem should be maximized (True) or minimized (False).", new BoolValue(false).AsReadOnly()) { Hidden = true, ReadOnly = true };
80      BestKnownQualityParameter = new OptionalValueParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution of this problem.");
81
82      Parameters.Add(MaximizationParameter);
83      Parameters.Add(BestKnownQualityParameter);
84
85      Operators.Add(Evaluator);
86      Operators.Add(new SingleObjectiveAnalyzer<TEncodedSolution>());
87      Operators.Add(new SingleObjectiveImprover<TEncodedSolution>());
88      Operators.Add(new SingleObjectiveMoveEvaluator<TEncodedSolution>());
89      Operators.Add(new SingleObjectiveMoveGenerator<TEncodedSolution>());
90      Operators.Add(new SingleObjectiveMoveMaker<TEncodedSolution>());
91
92      ParameterizeOperators();
93      RegisterEventHandlers();
94    }
95
96    protected SingleObjectiveProblem(TEncoding encoding) : base(encoding) {
97      Parameters.Add(MaximizationParameter = new ValueParameter<BoolValue>("Maximization", "Set to false if the problem should be minimized.", new BoolValue(false).AsReadOnly()) { Hidden = true, ReadOnly = true });
98      Parameters.Add(BestKnownQualityParameter = new OptionalValueParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution of this problem."));
99
100      Operators.Add(Evaluator);
101      Operators.Add(new SingleObjectiveAnalyzer<TEncodedSolution>());
102      Operators.Add(new SingleObjectiveImprover<TEncodedSolution>());
103      Operators.Add(new SingleObjectiveMoveEvaluator<TEncodedSolution>());
104      Operators.Add(new SingleObjectiveMoveGenerator<TEncodedSolution>());
105      Operators.Add(new SingleObjectiveMoveMaker<TEncodedSolution>());
106
107      ParameterizeOperators();
108      RegisterEventHandlers();
109    }
110
111    [StorableHook(HookType.AfterDeserialization)]
112    private void AfterDeserialization() {
113      ParameterizeOperators();
114      RegisterEventHandlers();
115    }
116
117    public ISingleObjectiveEvaluationResult Evaluate(TEncodedSolution solution, IRandom random) {
118      return Evaluate(solution, random, CancellationToken.None);
119    }
120    public abstract ISingleObjectiveEvaluationResult Evaluate(TEncodedSolution solution, IRandom random, CancellationToken cancellationToken);
121
122    public void Evaluate(ISingleObjectiveSolutionContext<TEncodedSolution> solutionContext, IRandom random) {
123      Evaluate(solutionContext, random, CancellationToken.None);
124    }
125    public virtual void Evaluate(ISingleObjectiveSolutionContext<TEncodedSolution> solutionContext, IRandom random, CancellationToken cancellationToken) {
126      var evaluationResult = Evaluate(solutionContext.EncodedSolution, random, cancellationToken);
127      solutionContext.EvaluationResult = evaluationResult;
128    }
129
130    public virtual void Analyze(TEncodedSolution[] solutions, double[] qualities, ResultCollection results, IRandom random) { }
131    public virtual void Analyze(ISingleObjectiveSolutionContext<TEncodedSolution>[] solutionContexts, ResultCollection results, IRandom random) {
132      var solutions = solutionContexts.Select(c => c.EncodedSolution).ToArray();
133      var qualities = solutionContexts.Select(c => c.EvaluationResult.Quality).ToArray();
134      Analyze(solutions, qualities, results, random);
135    }
136
137    public virtual IEnumerable<TEncodedSolution> GetNeighbors(TEncodedSolution solutions, IRandom random) {
138      return Enumerable.Empty<TEncodedSolution>();
139    }
140    public virtual IEnumerable<ISingleObjectiveSolutionContext<TEncodedSolution>> GetNeighbors(ISingleObjectiveSolutionContext<TEncodedSolution> solutionContext, IRandom random) {
141      return GetNeighbors(solutionContext.EncodedSolution, random).Select(n => new SingleObjectiveSolutionContext<TEncodedSolution>(n));
142    }
143
144    public static bool IsBetter(bool maximization, double quality, double bestQuality) {
145      return (maximization && quality > bestQuality || !maximization && quality < bestQuality);
146    }
147
148    public virtual bool IsBetter(double quality, double bestQuality) {
149      return IsBetter(Maximization, quality, bestQuality);
150    }
151
152    //TODO refactor to solution contexts
153    protected ISingleObjectiveSolutionContext<TEncodedSolution> GetBest(ISingleObjectiveSolutionContext<TEncodedSolution>[] solutionContexts) {
154      return Maximization ? solutionContexts.MaxItems(x => x.EvaluationResult.Quality).First()
155        : solutionContexts.MinItems(x => x.EvaluationResult.Quality).First();
156    }
157    protected Tuple<TEncodedSolution, double> GetBestSolution(TEncodedSolution[] solutions, double[] qualities) {
158      return GetBestSolution(solutions, qualities, Maximization);
159    }
160    public static Tuple<TEncodedSolution, double> GetBestSolution(TEncodedSolution[] solutions, double[] qualities, bool maximization) {
161      var zipped = solutions.Zip(qualities, (s, q) => new { Solution = s, Quality = q });
162      var best = (maximization ? zipped.OrderByDescending(z => z.Quality) : zipped.OrderBy(z => z.Quality)).First();
163      return Tuple.Create(best.Solution, best.Quality);
164    }
165
166    protected override void OnOperatorsChanged() {
167      if (Encoding != null) {
168        PruneMultiObjectiveOperators(Encoding);
169        var combinedEncoding = Encoding as CombinedEncoding;
170        if (combinedEncoding != null) {
171          foreach (var encoding in combinedEncoding.Encodings.ToList()) {
172            PruneMultiObjectiveOperators(encoding);
173          }
174        }
175      }
176      base.OnOperatorsChanged();
177    }
178
179    private void PruneMultiObjectiveOperators(IEncoding encoding) {
180      if (encoding.Operators.Any(x => x is IMultiObjectiveOperator && !(x is ISingleObjectiveOperator)))
181        encoding.Operators = encoding.Operators.Where(x => !(x is IMultiObjectiveOperator) || x is ISingleObjectiveOperator).ToList();
182
183      foreach (var multiOp in Encoding.Operators.OfType<IMultiOperator>()) {
184        foreach (var moOp in multiOp.Operators.Where(x => x is IMultiObjectiveOperator).ToList()) {
185          multiOp.RemoveOperator(moOp);
186        }
187      }
188    }
189
190    protected override void OnEvaluatorChanged() {
191      base.OnEvaluatorChanged();
192      ParameterizeOperators();
193    }
194
195    private void ParameterizeOperators() {
196      foreach (var op in Operators.OfType<ISingleObjectiveEvaluationOperator<TEncodedSolution>>())
197        op.Evaluate = Evaluate;
198      foreach (var op in Operators.OfType<ISingleObjectiveAnalysisOperator<TEncodedSolution>>())
199        op.Analyze = Analyze;
200      foreach (var op in Operators.OfType<INeighborBasedOperator<TEncodedSolution>>())
201        op.GetNeighbors = GetNeighbors;
202    }
203
204    private void RegisterEventHandlers() {
205      BoolValueParameterChangeHandler.Create(MaximizationParameter, OnMaximizationChanged);
206    }
207
208    #region ISingleObjectiveHeuristicOptimizationProblem Members
209    IParameter ISingleObjectiveHeuristicOptimizationProblem.MaximizationParameter {
210      get { return Parameters["Maximization"]; }
211    }
212    IParameter ISingleObjectiveHeuristicOptimizationProblem.BestKnownQualityParameter {
213      get { return Parameters["BestKnownQuality"]; }
214    }
215    ISingleObjectiveEvaluator ISingleObjectiveHeuristicOptimizationProblem.Evaluator {
216      get { return Evaluator; }
217    }
218    #endregion
219
220    public event EventHandler MaximizationChanged;
221    protected void OnMaximizationChanged() {
222      MaximizationChanged?.Invoke(this, EventArgs.Empty);
223    }
224  }
225}
Note: See TracBrowser for help on using the repository browser.