Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Operators/3.3/StochasticMultiBranch.cs @ 13378

Last change on this file since 13378 was 5856, checked in by svonolfe, 14 years ago

Made the SelectedOperator parameter of the StochasticMultiBranch visible, so the name can be changed (#1392)

File size: 9.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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 HeuristicLab.Collections;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Parameters;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31
32namespace HeuristicLab.Operators {
33  /// <summary>
34  /// Selects one of its branches (if there are any) given a list of relative probabilities.
35  /// </summary>
36  [Item("StochasticMultiBranch", "Selects one of its branches (if there are any) given a list of relative probabilities.")]
37  [StorableClass]
38  public abstract class StochasticMultiBranch<T> : CheckedMultiOperator<T> where T : class, IOperator {
39    /// <summary>
40    /// Should return true if the StochasticMultiOperator should create a new child operation with the selected successor
41    /// or if it should create a new operation. If you need to shield the parameters of the successor you should return true here.
42    /// </summary>
43    protected abstract bool CreateChildOperation { get; }
44
45    public ValueLookupParameter<DoubleArray> ProbabilitiesParameter {
46      get { return (ValueLookupParameter<DoubleArray>)Parameters["Probabilities"]; }
47    }
48    public ILookupParameter<IRandom> RandomParameter {
49      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
50    }
51    public ValueParameter<BoolValue> TraceSelectedOperatorParameter {
52      get { return (ValueParameter<BoolValue>)Parameters["TraceSelectedOperator"]; }
53    }
54    public LookupParameter<StringValue> SelectedOperatorParameter {
55      get { return (LookupParameter<StringValue>)Parameters["SelectedOperator"]; }
56    }
57
58    public DoubleArray Probabilities {
59      get { return ProbabilitiesParameter.Value; }
60      set { ProbabilitiesParameter.Value = value; }
61    }
62
63    [StorableHook(HookType.AfterDeserialization)]
64    private void AfterDeserializationHook() {
65      #region Backwards Compatibility
66      if (!Parameters.ContainsKey("SelectedOperator")) {
67        Parameters.Add(new LookupParameter<StringValue>("SelectedOperator", "If the TraceSelectedOperator flag is set, the name of the operator is traced in this parameter."));
68        SelectedOperatorParameter.Hidden = false;
69      }
70      if (!Parameters.ContainsKey("TraceSelectedOperator")) {
71        Parameters.Add(new ValueParameter<BoolValue>("TraceSelectedOperator", "Indicates, if the selected operator should be traced.", new BoolValue(false)));
72      }
73      #endregion
74    }
75
76    [StorableConstructor]
77    protected StochasticMultiBranch(bool deserializing) : base(deserializing) { }
78    protected StochasticMultiBranch(StochasticMultiBranch<T> original, Cloner cloner)
79      : base(original, cloner) {
80    }
81    /// <summary>
82    /// Initializes a new instance of <see cref="StochasticMultiOperator"/> with two parameters
83    /// (<c>Probabilities</c> and <c>Random</c>).
84    /// </summary>
85    public StochasticMultiBranch()
86      : base() {
87      Parameters.Add(new ValueLookupParameter<DoubleArray>("Probabilities", "The array of relative probabilities for each operator.", new DoubleArray()));
88      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
89      Parameters.Add(new LookupParameter<StringValue>("SelectedOperator", "If the TraceSelectedOperator flag is set, the name of the operator is traced in this parameter."));
90      Parameters.Add(new ValueParameter<BoolValue>("TraceSelectedOperator", "Indicates, if the selected operator should be traced.", new BoolValue(false)));
91      SelectedOperatorParameter.Hidden = false;
92    }
93
94    protected override void Operators_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
95      base.Operators_ItemsRemoved(sender, e);
96      if (Probabilities != null && Probabilities.Length > Operators.Count) {
97        List<double> probs = new List<double>(Probabilities.Cast<double>());
98        var sorted = e.Items.OrderByDescending(x => x.Index);
99        foreach (IndexedItem<T> item in sorted)
100          if (probs.Count > item.Index) probs.RemoveAt(item.Index);
101        Probabilities = new DoubleArray(probs.ToArray());
102      }
103    }
104
105    protected override void Operators_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
106      base.Operators_ItemsAdded(sender, e);
107      if (Probabilities != null && Probabilities.Length < Operators.Count) {
108        double avg = (Probabilities.Where(x => x > 0).Count() > 0) ? (Probabilities.Where(x => x > 0).Average()) : (1);
109        // add the average of all probabilities in the respective places (the new operators)
110        var added = e.Items.OrderBy(x => x.Index).ToList();
111        int insertCount = 0;
112        DoubleArray probs = new DoubleArray(Operators.Count);
113        for (int i = 0; i < Operators.Count; i++) {
114          if (insertCount < added.Count && i == added[insertCount].Index) {
115            probs[i] = avg;
116            insertCount++;
117          } else if (i - insertCount < Probabilities.Length) {
118            probs[i] = Probabilities[i - insertCount];
119          } else probs[i] = avg;
120        }
121        Probabilities = probs;
122      }
123    }
124
125    /// <summary>
126    /// Applies an operator of the branches to the current scope with a
127    /// specific probability.
128    /// </summary>
129    /// <exception cref="InvalidOperationException">Thrown when the list of probabilites does not
130    /// match the number of operators, the list of selected operators is empty,
131    /// or all selected operators have zero probabitlity.</exception>
132    /// <returns>A new operation with the operator that was selected followed by the current operator's successor.</returns>
133    public override IOperation Apply() {
134      IRandom random = RandomParameter.ActualValue;
135      DoubleArray probabilities = ProbabilitiesParameter.ActualValue;
136      if (probabilities.Length != Operators.Count) {
137        throw new InvalidOperationException(Name + ": The list of probabilities has to match the number of operators");
138      }
139      IOperator successor = null;
140      int index = -1;
141      var checkedOperators = Operators.CheckedItems;
142      if (checkedOperators.Count() > 0) {
143        // select a random operator from the checked operators
144        double sum = (from indexedItem in checkedOperators select probabilities[indexedItem.Index]).Sum();
145        if (sum == 0) throw new InvalidOperationException(Name + ": All selected operators have zero probability.");
146        double r = random.NextDouble() * sum;
147        sum = 0;
148        foreach (var indexedItem in checkedOperators) {
149          sum += probabilities[indexedItem.Index];
150          if (sum > r) {
151            successor = indexedItem.Value;
152            index = indexedItem.Index;
153            break;
154          }
155        }
156      }
157      OperationCollection next = new OperationCollection(base.Apply());
158      if (successor != null) {
159        if (TraceSelectedOperatorParameter.Value.Value)
160          SelectedOperatorParameter.ActualValue = new StringValue(index + ": " + successor.Name);
161
162        if (CreateChildOperation)
163          next.Insert(0, ExecutionContext.CreateChildOperation(successor));
164        else next.Insert(0, ExecutionContext.CreateOperation(successor));
165      } else {
166        if (TraceSelectedOperatorParameter.Value.Value)
167          SelectedOperatorParameter.ActualValue = new StringValue("");
168      }
169      return next;
170    }
171  }
172
173  /// <summary>
174  /// Selects one of its branches (if there are any) given a list of relative probabilities.
175  /// </summary>
176  [Item("StochasticMultiBranch", "Selects one of its branches (if there are any) given a list of relative probabilities.")]
177  [StorableClass]
178  public class StochasticMultiBranch : StochasticMultiBranch<IOperator> {
179    [StorableConstructor]
180    protected StochasticMultiBranch(bool deserializing) : base(deserializing) { }
181    protected StochasticMultiBranch(StochasticMultiBranch original, Cloner cloner)
182      : base(original, cloner) {
183    }
184    public StochasticMultiBranch() { }
185
186    public override IDeepCloneable Clone(Cloner cloner) {
187      return new StochasticMultiBranch(this, cloner);
188    }
189
190    protected override bool CreateChildOperation {
191      get { return false; }
192    }
193  }
194}
Note: See TracBrowser for help on using the repository browser.