source: trunk/sources/HeuristicLab.Operators/3.3/StochasticMultiOperator.cs @ 3425

Last change on this file since 3425 was 3425, checked in by abeham, 11 years ago

Changed MultiCrossover to StochasticMultiOperator
Derived StochasticMultiBranch from StochasticMultiOperator
Derived encoding specific mutation/crossover operators from StochasticMultiOperator
#976

File size: 7.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Core;
27using HeuristicLab.Data;
28using HeuristicLab.Parameters;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Operators {
33  /// <summary>
34  /// Base class for stochastic multi operators.
35  /// </summary>
36  [Item("StochasticMultiOperator", "Base class for stochastic multi operators.")]
37  [StorableClass]
38  public abstract class StochasticMultiOperator<T> : MultiOperator<T> where T : class, IOperator {
39    /// <summary>
40    /// Returns false by default. If this is overriden to return true, there will be an automatic type discovery
41    /// of all instantiable types of T (except the own type) and instances will be added to the Operators list.
42    /// </summary>
43    public virtual bool AutomaticTypeDiscovery { get { return false; } }
44    /// <summary>
45    /// Should return true if the StochasticMultiOperator should create a new child operation with the selected successor
46    /// or if it should create a new operation. If you need to shield the parameters of the successor you should return true here.
47    /// </summary>
48    protected abstract bool CreateChildOperation { get; }
49
50    public ValueLookupParameter<DoubleArray> ProbabilitiesParameter {
51      get { return (ValueLookupParameter<DoubleArray>)Parameters["Probabilities"]; }
52    }
53    public ILookupParameter<IRandom> RandomParameter {
54      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
55    }
56
57    public DoubleArray Probabilities {
58      get { return ProbabilitiesParameter.Value; }
59      set { ProbabilitiesParameter.Value = value; }
60    }
61
62    [StorableConstructor]
63    protected StochasticMultiOperator(bool deserializing) : base(deserializing) { }
64    /// <summary>
65    /// Initializes a new instance of <see cref="StochasticMultiBranch"/> with two parameters
66    /// (<c>Probabilities</c> and <c>Random</c>).
67    /// </summary>
68    public StochasticMultiOperator()
69      : base() {
70      Parameters.Add(new ValueLookupParameter<DoubleArray>("Probabilities", "The array of relative probabilities for each operator.", new DoubleArray()));
71      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
72      Initialize();
73    }
74
75    [StorableHook(HookType.AfterDeserialization)]
76    private void Initialize() {
77      Operators.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Operators_ItemsAdded);
78      Operators.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Operators_ItemsRemoved);
79      Operators.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<T>>(Operators_ItemsMoved);
80      if (AutomaticTypeDiscovery) {
81        IEnumerable<Type> types = ApplicationManager.Manager.GetTypes(typeof(T), true);
82        foreach (Type type in types.OrderBy(x => x.FullName)) {
83          if (type != this.GetType())
84            Operators.Add((T)Activator.CreateInstance(type));
85        }
86      }
87    }
88
89    void Operators_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
90      if (Probabilities != null) {
91        DoubleArray oldProb = (DoubleArray)Probabilities.Clone();
92        foreach (IndexedItem<T> old in e.OldItems) {
93          foreach (IndexedItem<T> item in e.Items) {
94            if (old.Value == item.Value && item.Index < Probabilities.Length && old.Index < oldProb.Length)
95              Probabilities[item.Index] = oldProb[old.Index];
96          }
97        }
98      }
99    }
100
101    void Operators_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
102      if (Probabilities != null && Probabilities.Length > Operators.Count) {
103        List<double> probs = new List<double>(Probabilities.Cast<double>());
104        var sorted = e.Items.OrderByDescending(x => x.Index);
105        foreach (IndexedItem<T> item in sorted)
106          if (probs.Count > item.Index) probs.RemoveAt(item.Index);
107        Probabilities = new DoubleArray(probs.ToArray());
108      }
109    }
110
111    private void Operators_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IndexedItem<T>> e) {
112      if (Probabilities != null && Probabilities.Length < Operators.Count) {
113        DoubleArray probs = new DoubleArray(Operators.Count);
114        double avg = 0;
115        if (Probabilities.Length > 0) {
116          for (int i = 0; i < Probabilities.Length; i++)
117            avg += Probabilities[i];
118          avg /= (double)Probabilities.Length;
119        } else avg = 1;
120
121        var added = e.Items.OrderBy(x => x.Index).ToList();
122        int insertCount = 0;
123        for (int i = 0; i < Operators.Count; i++) {
124          if (insertCount < added.Count && i == added[insertCount].Index) {
125            probs[i] = avg;
126            insertCount++;
127          } else if (i - insertCount < Probabilities.Length) {
128            probs[i] = Probabilities[i - insertCount];
129          } else probs[i] = avg;
130        }
131        Probabilities = probs;
132      }
133    }
134
135    /// <summary>
136    /// Applies an operator of the branches to the current scope with a
137    /// specific probability.
138    /// </summary>
139    /// <exception cref="InvalidOperationException">Thrown when the list of probabilites does not
140    /// match the number of operators.</exception>
141    /// <returns>A new operation with the operator that was selected followed by the current operator's successor.</returns>
142    public override IOperation Apply() {
143      IRandom random = RandomParameter.ActualValue;
144      DoubleArray probabilities = ProbabilitiesParameter.ActualValue;
145      if(probabilities.Length != Operators.Count) {
146        throw new InvalidOperationException("MultiCrossover: The list of probabilities has to match the number of operators");
147      }
148      double sum = 0;
149      for (int i = 0; i < Operators.Count; i++) {
150        sum += probabilities[i];
151      }
152      double r = random.NextDouble() * sum;
153      sum = 0;
154      IOperator successor = null;
155      for(int i = 0; i < Operators.Count; i++) {
156        sum += probabilities[i];
157        if(sum > r) {
158          successor = Operators[i];
159          break;
160        }
161      }
162      OperationCollection next = new OperationCollection(base.Apply());
163      if (successor != null) {
164        if (CreateChildOperation)
165          next.Insert(0, ExecutionContext.CreateChildOperation(successor));
166        else next.Insert(0, ExecutionContext.CreateOperation(successor));
167      }
168      return next;
169    }
170  }
171}
Note: See TracBrowser for help on using the repository browser.