Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 5658 was 5646, checked in by cfischer, 14 years ago

#1364 implemented QualityDifferenceUseRange option

File size: 9.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using HeuristicLab.Common;
5using HeuristicLab.Core;
6using HeuristicLab.Data;
7using HeuristicLab.Optimization;
8using HeuristicLab.Parameters;
9using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
10
11namespace HeuristicLab.Selection {
12  /// <summary>
13  /// A selector which tries to select two parents which differ in quality.
14  /// </summary>
15  [Item("NoSameMatesSelector", "A selector which tries to select two parents which differ in quality.")]
16  [StorableClass]
17  public class NoSameMatesSelector : StochasticSingleObjectiveSelector, ISingleObjectiveSelector {
18    private const string SelectorParameterName = "Selector";
19    private const string QualityDifferencePercentageParameterName = "QualityDifferencePercentage";
20    private const string QualityDifferenceMaxAttemptsParameterName = "QualityDifferenceMaxAttempts";
21    private const string QualityDifferenceUseRangeParameterName = "QualityDifferenceUseRange";
22
23    #region Parameters
24    public IValueParameter<ISelector> SelectorParameter {
25      get { return (IValueParameter<ISelector>)Parameters[SelectorParameterName]; }
26    }
27    public IValueParameter<PercentValue> QualityDifferencePercentageParameter {
28      get { return (IValueParameter<PercentValue>)Parameters[QualityDifferencePercentageParameterName]; }
29    }
30    public IValueParameter<IntValue> QualityDifferenceMaxAttemptsParameter {
31      get { return (IValueParameter<IntValue>)Parameters[QualityDifferenceMaxAttemptsParameterName]; }
32    }
33    public IValueParameter<BoolValue> QualityDifferenceUseRangeParameter {
34      get { return (IValueParameter<BoolValue>)Parameters[QualityDifferenceUseRangeParameterName]; }
35    }
36    #endregion
37
38    #region Properties
39    public IntValue NumberOfSelectedSubScopes {
40      get { return NumberOfSelectedSubScopesParameter.ActualValue; }
41    }
42    public ISelector 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) : base(original, cloner) { }
60    public override IDeepCloneable Clone(Cloner cloner) {
61      return new NoSameMatesSelector(this, cloner);
62    }
63
64    public NoSameMatesSelector() : base() {
65      #region Create parameters
66      Parameters.Add(new ValueParameter<ISelector>(SelectorParameterName, "The inner selection operator to select the parents."));
67      Parameters.Add(new ValueParameter<PercentValue>(QualityDifferencePercentageParameterName, "The minimum quality difference from parent1 to parent2 to accept the selection.", new PercentValue(0.05)));
68      Parameters.Add(new ValueParameter<IntValue>(QualityDifferenceMaxAttemptsParameterName, "The maximum number of attempts to find parents which differ in quality.", new IntValue(5)));
69      Parameters.Add(new ValueParameter<BoolValue>(QualityDifferenceUseRangeParameterName, "Use the range from minimum to maximum quality as basis for QualityDifferencePercentage.", new BoolValue(false)));
70      #endregion
71
72      Initialize();
73    }
74
75    [StorableHook(HookType.AfterDeserialization)]
76    private void AfterDeserialization() {
77      if (!Parameters.ContainsKey(QualityDifferenceUseRangeParameterName))
78        Parameters.Add(new ValueParameter<BoolValue>(QualityDifferenceUseRangeParameterName, "Use the range from minimum to maximum quality as basis for QualityDifferencePercentage.", new BoolValue(false)));
79      Initialize();
80    }
81
82    protected override IScope[] Select(List<IScope> scopes) {
83      int count = NumberOfSelectedSubScopes.Value;
84      if (count % 2 > 0) throw new InvalidOperationException(Name + ": There must be an equal number of sub-scopes to be selected.");
85      int limit = count - 1;
86      IScope[] selected = new IScope[count];
87
88      double qualityDifferencePercentage = QualityDifferencePercentage.Value;
89      int qualityDifferenceMaxAttempts = QualityDifferenceMaxAttempts.Value;
90      bool qualityDifferenceUseRange = QualityDifferenceUseRange.Value;
91      string qualityName = QualityParameter.ActualName;
92     
93      // get minimum and maximum quality, calculate quality offsets
94      double minQualityOffset = 0;
95      double maxQualityOffset = 0;
96      if (qualityDifferenceUseRange) {
97        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
98        double minQuality = double.MaxValue, maxQuality = double.MinValue;
99        for (int l = 0; l < qualities.Length; l++) {
100          if (qualities[l].Value < minQuality) minQuality = qualities[l].Value;
101          if (qualities[l].Value > maxQuality) maxQuality = qualities[l].Value;
102        } // maximization flag is not needed because only the range is relevant
103        minQualityOffset = (maxQuality - minQuality) * qualityDifferencePercentage;
104      } else {
105        maxQualityOffset = 1.0 + qualityDifferencePercentage;
106        minQualityOffset = 1.0 - qualityDifferencePercentage;
107      }
108
109      ScopeList parents, remaining;
110      double qualityParent1, qualityParent2;
111      bool parentsDifferent;
112      int attempts = 1;
113      int i, j, k = 0;
114      while (k < limit) { // repeat until enough parents are selected
115        ApplyInnerSelector();
116        parents = CurrentScope.SubScopes[1].SubScopes;
117
118        for (i = 0; k < limit && i < parents.Count - 1; i += 2) {
119          j = i + 1;
120          qualityParent1 = ((DoubleValue)parents[i].Variables[qualityName].Value).Value;
121          qualityParent2 = ((DoubleValue)parents[j].Variables[qualityName].Value).Value;
122
123          if (qualityDifferenceUseRange) {
124            parentsDifferent = (qualityParent2 > qualityParent1 - minQualityOffset ||
125                                qualityParent2 < qualityParent1 + minQualityOffset);
126          } else {
127            parentsDifferent = (qualityParent2 > qualityParent1 * maxQualityOffset ||
128                                qualityParent2 < qualityParent1 * minQualityOffset);
129          }
130
131          // parents meet difference criterion or max attempts reached
132          if (attempts >= qualityDifferenceMaxAttempts || parentsDifferent) {
133            // inner selector already copied scopes
134            selected[k++] = parents[i];
135            selected[k++] = parents[j];
136            if (!CopySelected.Value) {
137              scopes.Remove(parents[i]);
138              scopes.Remove(parents[j]);
139            }
140            attempts = 1;
141          } else { // skip parents
142            attempts++;
143          }
144        }
145        // modify scopes
146        remaining = CurrentScope.SubScopes[0].SubScopes;
147        CurrentScope.SubScopes.Clear();
148        CurrentScope.SubScopes.AddRange(remaining);
149      }
150      return selected;
151    }
152
153    #region Events
154    private void SelectorParameter_ValueChanged(object sender, EventArgs e) {
155      IValueParameter<ISelector> selectorParam = (sender as IValueParameter<ISelector>);
156      if (selectorParam != null)
157        ParameterizeSelector(selectorParam.Value);
158    }
159    #endregion
160
161    #region Helpers
162    private void ApplyInnerSelector() {
163      IOperation next;
164      IAtomicOperation operation;
165      OperationCollection coll;
166      Stack<IOperation> executionStack = new Stack<IOperation>();
167
168      executionStack.Push(ExecutionContext.CreateChildOperation(Selector));
169      while (executionStack.Count > 0) {
170        CancellationToken.ThrowIfCancellationRequested();
171        next = executionStack.Pop();
172        if (next is OperationCollection) {
173          coll = (OperationCollection)next;
174          for (int i = coll.Count - 1; i >= 0; i--)
175            if (coll[i] != null) executionStack.Push(coll[i]);
176        } else if (next is IAtomicOperation) {
177          operation = (IAtomicOperation)next;
178          next = operation.Operator.Execute((IExecutionContext)operation, CancellationToken);
179          if (next != null) executionStack.Push(next);
180        }
181      }
182    }
183
184    private void Initialize() {
185      SelectorParameter.ValueChanged += new EventHandler(SelectorParameter_ValueChanged);
186      if (Selector == null) Selector = new TournamentSelector();
187    }
188
189    private void ParameterizeSelector(ISelector selector) {
190      selector.CopySelected = new BoolValue(true); // must always be true
191      IStochasticOperator stoOp = (selector as IStochasticOperator);
192      if (stoOp != null) stoOp.RandomParameter.ActualName = RandomParameter.Name;
193      ISingleObjectiveSelector soSelector = (selector as ISingleObjectiveSelector);
194      if (soSelector != null) {
195        soSelector.MaximizationParameter.ActualName = MaximizationParameter.Name;
196        soSelector.QualityParameter.ActualName = QualityParameter.Name;
197      }
198    }
199    #endregion
200  }
201}
Note: See TracBrowser for help on using the repository browser.