Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Selection/3.3/NoSameMatesSelector.cs @ 7892

Last change on this file since 7892 was 6051, checked in by swagner, 14 years ago

Changed some more parameters to be hidden per default and corrected wrong layout in some parameter views (#1377)

File size: 13.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using HeuristicLab.Optimization;
9using HeuristicLab.Parameters;
10using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
11
12namespace HeuristicLab.Selection {
13  /// <summary>
14  /// A selector which tries to select two parents which differ in quality
15  /// as described in: "S. Gustafson, E. K. Burke, N. Krasnogor, On improving genetic programming for symbolic regression,
16  /// The 2005 IEEE Congress on Evolutionary Computation, pp. 912-919, 2005."
17  /// </summary>
18  [Item("NoSameMatesSelector", "A selector which tries to select two parents which differ in quality as described in: \"S. Gustafson, E. K. Burke, N. Krasnogor, On improving genetic programming for symbolic regression, The 2005 IEEE Congress on Evolutionary Computation, pp. 912-919, 2005.\"")]
19  [StorableClass]
20  public class NoSameMatesSelector : StochasticSingleObjectiveSelector, ISingleObjectiveSelector {
21    private const string SelectorParameterName = "Selector";
22    private const string QualityDifferencePercentageParameterName = "QualityDifferencePercentage";
23    private const string QualityDifferenceMaxAttemptsParameterName = "QualityDifferenceMaxAttempts";
24    private const string QualityDifferenceUseRangeParameterName = "QualityDifferenceUseRange";
25
26    #region Parameters
27    public IValueParameter<ISingleObjectiveSelector> SelectorParameter {
28      get { return (IValueParameter<ISingleObjectiveSelector>)Parameters[SelectorParameterName]; }
29    }
30    public IFixedValueParameter<PercentValue> QualityDifferencePercentageParameter {
31      get { return (IFixedValueParameter<PercentValue>)Parameters[QualityDifferencePercentageParameterName]; }
32    }
33    public IFixedValueParameter<IntValue> QualityDifferenceMaxAttemptsParameter {
34      get { return (IFixedValueParameter<IntValue>)Parameters[QualityDifferenceMaxAttemptsParameterName]; }
35    }
36    public IFixedValueParameter<BoolValue> QualityDifferenceUseRangeParameter {
37      get { return (IFixedValueParameter<BoolValue>)Parameters[QualityDifferenceUseRangeParameterName]; }
38    }
39    #endregion
40
41    #region Properties
42    public ISingleObjectiveSelector Selector {
43      get { return SelectorParameter.Value; }
44      set { SelectorParameter.Value = value; }
45    }
46    public PercentValue QualityDifferencePercentage {
47      get { return QualityDifferencePercentageParameter.Value; }
48    }
49    public IntValue QualityDifferenceMaxAttempts {
50      get { return QualityDifferenceMaxAttemptsParameter.Value; }
51    }
52    public BoolValue QualityDifferenceUseRange {
53      get { return QualityDifferenceUseRangeParameter.Value; }
54    }
55    #endregion
56
57    [StorableConstructor]
58    protected NoSameMatesSelector(bool deserializing) : base(deserializing) { }
59    protected NoSameMatesSelector(NoSameMatesSelector original, Cloner cloner)
60      : base(original, cloner) {
61      RegisterParameterEventHandlers();
62    }
63    public override IDeepCloneable Clone(Cloner cloner) {
64      return new NoSameMatesSelector(this, cloner);
65    }
66
67    public NoSameMatesSelector()
68      : base() {
69      #region Create parameters
70      Parameters.Add(new ValueParameter<ISingleObjectiveSelector>(SelectorParameterName, "The inner selection operator to select the parents.", new TournamentSelector()));
71      Parameters.Add(new FixedValueParameter<PercentValue>(QualityDifferencePercentageParameterName, "The minimum quality difference from parent1 to parent2 to accept the selection.", new PercentValue(0.05)));
72      Parameters.Add(new FixedValueParameter<IntValue>(QualityDifferenceMaxAttemptsParameterName, "The maximum number of attempts to find parents which differ in quality.", new IntValue(5)));
73      Parameters.Add(new FixedValueParameter<BoolValue>(QualityDifferenceUseRangeParameterName, "Use the range from minimum to maximum quality as basis for QualityDifferencePercentage.", new BoolValue(true)));
74      #endregion
75
76      RegisterParameterEventHandlers();
77    }
78
79    [StorableHook(HookType.AfterDeserialization)]
80    private void AfterDeserialization() {
81      #region conversion of old NSM parameters
82      if (Parameters.ContainsKey(SelectorParameterName)) { // change SelectorParameter type from ISelector to ISingleObjectiveSelector
83        ValueParameter<ISelector> param = Parameters[SelectorParameterName] as ValueParameter<ISelector>;
84        if (param != null) {
85          ISingleObjectiveSelector selector = param.Value as ISingleObjectiveSelector;
86          if (selector == null) selector = new TournamentSelector();
87          Parameters.Remove(SelectorParameterName);
88          Parameters.Add(new ValueParameter<ISingleObjectiveSelector>(SelectorParameterName, "The inner selection operator to select the parents.", selector));
89        }
90      }
91      // FixedValueParameter for quality difference percentage, max attempts, use range
92      if (Parameters.ContainsKey(QualityDifferencePercentageParameterName)) {
93        ValueParameter<PercentValue> param = Parameters[QualityDifferencePercentageParameterName] as ValueParameter<PercentValue>;
94        if (!(param is FixedValueParameter<PercentValue>)) {
95          PercentValue diff = param != null ? param.Value as PercentValue : null;
96          if (diff == null) diff = new PercentValue(0.05);
97          Parameters.Remove(QualityDifferencePercentageParameterName);
98          Parameters.Add(new FixedValueParameter<PercentValue>(QualityDifferencePercentageParameterName, "The minimum quality difference from parent1 to parent2 to accept the selection.", diff));
99        }
100      }
101      if (Parameters.ContainsKey(QualityDifferenceMaxAttemptsParameterName)) {
102        ValueParameter<IntValue> param = Parameters[QualityDifferenceMaxAttemptsParameterName] as ValueParameter<IntValue>;
103        if (!(param is FixedValueParameter<IntValue>)) {
104          IntValue attempts = param != null ? param.Value as IntValue : null;
105          if (attempts == null) attempts = new IntValue(5);
106          Parameters.Remove(QualityDifferenceMaxAttemptsParameterName);
107          Parameters.Add(new FixedValueParameter<IntValue>(QualityDifferenceMaxAttemptsParameterName, "The maximum number of attempts to find parents which differ in quality.", attempts));
108        }
109      }
110      if (Parameters.ContainsKey(QualityDifferenceUseRangeParameterName)) {
111        ValueParameter<BoolValue> param = Parameters[QualityDifferenceUseRangeParameterName] as ValueParameter<BoolValue>;
112        if (!(param is FixedValueParameter<BoolValue>)) {
113          BoolValue range = param != null ? param.Value as BoolValue : null;
114          if (range == null) range = new BoolValue(true);
115          Parameters.Remove(QualityDifferenceUseRangeParameterName);
116          Parameters.Add(new FixedValueParameter<BoolValue>(QualityDifferenceUseRangeParameterName, "Use the range from minimum to maximum quality as basis for QualityDifferencePercentage.", range));
117        }
118      }
119      if (!Parameters.ContainsKey(QualityDifferenceUseRangeParameterName)) // add use range parameter
120        Parameters.Add(new FixedValueParameter<BoolValue>(QualityDifferenceUseRangeParameterName, "Use the range from minimum to maximum quality as basis for QualityDifferencePercentage.", new BoolValue(true)));
121      #endregion
122
123      RegisterParameterEventHandlers();
124    }
125
126    protected override IScope[] Select(List<IScope> scopes) {
127      int parentsToSelect = NumberOfSelectedSubScopesParameter.ActualValue.Value;
128      if (parentsToSelect % 2 > 0) throw new InvalidOperationException(Name + ": There must be an equal number of sub-scopes to be selected.");
129      IScope[] selected = new IScope[parentsToSelect];
130      IScope[] parentsPool = new IScope[parentsToSelect];
131
132      double qualityDifferencePercentage = QualityDifferencePercentage.Value;
133      int qualityDifferenceMaxAttempts = QualityDifferenceMaxAttempts.Value;
134      bool qualityDifferenceUseRange = QualityDifferenceUseRange.Value;
135      string qualityName = QualityParameter.ActualName;
136
137      // calculate quality offsets   
138      double absoluteQualityOffset = 0;
139      double minRelativeQualityOffset = 0;
140      double maxRelativeQualityOffset = 0;
141      if (qualityDifferenceUseRange) {
142        // maximization flag is not needed because only the range is relevant
143        double minQuality = QualityParameter.ActualValue.Min(x => x.Value);
144        double maxQuality = QualityParameter.ActualValue.Max(x => x.Value);
145        absoluteQualityOffset = (maxQuality - minQuality) * qualityDifferencePercentage;
146      } else {
147        maxRelativeQualityOffset = 1.0 + qualityDifferencePercentage;
148        minRelativeQualityOffset = 1.0 - qualityDifferencePercentage;
149      }
150
151      int selectedParents = 0;
152      int poolCount = 0;
153      // repeat until enough parents are selected or max attempts are reached
154      for (int attempts = 1; attempts <= qualityDifferenceMaxAttempts && selectedParents < parentsToSelect - 1; attempts++) {
155        ApplyInnerSelector();
156        ScopeList parents = CurrentScope.SubScopes[1].SubScopes;
157
158        for (int indexParent1 = 0, indexParent2 = 1;
159             indexParent1 < parents.Count - 1 && selectedParents < parentsToSelect - 1;
160             indexParent1 += 2, indexParent2 += 2) {
161          double qualityParent1 = ((DoubleValue)parents[indexParent1].Variables[qualityName].Value).Value;
162          double qualityParent2 = ((DoubleValue)parents[indexParent2].Variables[qualityName].Value).Value;
163
164          bool parentsDifferent;
165          if (qualityDifferenceUseRange) {
166            parentsDifferent = (qualityParent2 > qualityParent1 - absoluteQualityOffset ||
167                                qualityParent2 < qualityParent1 + absoluteQualityOffset);
168          } else {
169            parentsDifferent = (qualityParent2 > qualityParent1 * maxRelativeQualityOffset ||
170                                qualityParent2 < qualityParent1 * minRelativeQualityOffset);
171          }
172
173          if (parentsDifferent) {
174            // inner selector already copied scopes, no cloning necessary here
175            selected[selectedParents++] = parents[indexParent1];
176            selected[selectedParents++] = parents[indexParent2];
177          } else if (attempts == qualityDifferenceMaxAttempts &&
178                     poolCount < parentsToSelect - selectedParents) {
179            // last attempt: save parents to fill remaining positions
180            parentsPool[poolCount++] = parents[indexParent1];
181            parentsPool[poolCount++] = parents[indexParent2];
182          }
183        }
184        // modify scopes
185        ScopeList remaining = CurrentScope.SubScopes[0].SubScopes;
186        CurrentScope.SubScopes.Clear();
187        CurrentScope.SubScopes.AddRange(remaining);
188      }
189      // fill remaining positions with parents which don't meet the difference criterion
190      if (selectedParents < parentsToSelect - 1) {
191        Array.Copy(parentsPool, 0, selected, selectedParents, parentsToSelect - selectedParents);
192      }
193      return selected;
194    }
195
196    #region Events
197    private void RegisterParameterEventHandlers() {
198      SelectorParameter.ValueChanged += new EventHandler(SelectorParameter_ValueChanged);
199      CopySelected.ValueChanged += new EventHandler(CopySelected_ValueChanged);
200    }
201
202    private void SelectorParameter_ValueChanged(object sender, EventArgs e) {
203      ParameterizeSelector(Selector);
204    }
205
206    private void CopySelected_ValueChanged(object sender, EventArgs e) {
207      if (CopySelected.Value != true) {
208        CopySelected.Value = true;
209      }
210    }
211    #endregion
212
213    #region Helpers
214    private void ParameterizeSelector(ISingleObjectiveSelector selector) {
215      selector.CopySelected = new BoolValue(true); // must always be true
216      selector.MaximizationParameter.ActualName = MaximizationParameter.Name;
217      selector.QualityParameter.ActualName = QualityParameter.Name;
218
219      IStochasticOperator stoOp = (selector as IStochasticOperator);
220      if (stoOp != null) stoOp.RandomParameter.ActualName = RandomParameter.Name;
221    }
222
223    private void ApplyInnerSelector() {
224      // necessary for inner GenderSpecificSelector to execute all operations in OperationCollection
225      Stack<IOperation> executionStack = new Stack<IOperation>();
226      executionStack.Push(ExecutionContext.CreateChildOperation(Selector));
227      while (executionStack.Count > 0) {
228        CancellationToken.ThrowIfCancellationRequested();
229        IOperation next = executionStack.Pop();
230        if (next is OperationCollection) {
231          OperationCollection coll = (OperationCollection)next;
232          for (int i = coll.Count - 1; i >= 0; i--)
233            if (coll[i] != null) executionStack.Push(coll[i]);
234        } else if (next is IAtomicOperation) {
235          IAtomicOperation operation = (IAtomicOperation)next;
236          next = operation.Operator.Execute((IExecutionContext)operation, CancellationToken);
237          if (next != null) executionStack.Push(next);
238        }
239      }
240    }
241    #endregion
242  }
243}
Note: See TracBrowser for help on using the repository browser.