Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Operator Architecture Refactoring/HeuristicLab.Random/3.3/NormalRandomAdder.cs @ 2311

Last change on this file since 2311 was 1853, checked in by epitzer, 16 years ago

Fix EmptyStorableClass attributes. (#603)

File size: 8.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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.Text;
25using HeuristicLab.Core;
26using HeuristicLab.Data;
27using HeuristicLab.Constraints;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Random {
31  /// <summary>
32  /// Normally distributed random number generator that adds the generated value to the existing value
33  /// in the specified scope.
34  /// </summary>
35  [EmptyStorableClass]
36  public class NormalRandomAdder : OperatorBase {
37    private static int MAX_NUMBER_OF_TRIES = 100;
38
39    /// <inheritdoc select="summary"/>
40    public override string Description {
41      get {
42        return @"Samples a normally distributed (mu, sigma * shakingFactor) random variable and adds the result to variable 'Value'.
43       
44If a constraint for the allowed range of 'Value' is defined and the result of the operation would be smaller then
45the smallest allowed value then 'Value' is set to the lower bound and vice versa for the upper bound.";
46      }
47    }
48
49    /// <summary>
50    /// Gets or sets the value for µ.
51    /// </summary>
52    /// <remarks>Gets or sets the variable with the name <c>Mu</c> through the method
53    /// <see cref="OperatorBase.GetVariable"/> of class <see cref="OperatorBase"/>.</remarks>
54    public double Mu {
55      get { return ((DoubleData)GetVariable("Mu").Value).Data; }
56      set { ((DoubleData)GetVariable("Mu").Value).Data = value; }
57    }
58    /// <summary>
59    /// Gets or sets the value for sigma.
60    /// </summary>
61    /// <remarks>Gets or sets the variable with the name <c>Sigma</c> through the method
62    /// <see cref="OperatorBase.GetVariable"/> of class <see cref="OperatorBase"/>.</remarks>
63    public double Sigma {
64      get { return ((DoubleData)GetVariable("Sigma").Value).Data; }
65      set { ((DoubleData)GetVariable("Sigma").Value).Data = value; }
66    }
67
68    /// <summary>
69    /// Initializes a new instance of <see cref="NormalRandomAdder"/> with five variable infos
70    /// (<c>Mu</c>, <c>Sigma</c>, <c>Value</c>, <c>ShakingFactor</c> and <c>Random</c>).
71    /// </summary>
72    public NormalRandomAdder() {
73      AddVariableInfo(new VariableInfo("Mu", "Parameter mu of the normal distribution", typeof(DoubleData), VariableKind.None));
74      GetVariableInfo("Mu").Local = true;
75      AddVariable(new Variable("Mu", new DoubleData(0.0)));
76
77      AddVariableInfo(new VariableInfo("Sigma", "Parameter sigma of the normal distribution", typeof(DoubleData), VariableKind.None));
78      GetVariableInfo("Sigma").Local = true;
79      AddVariable(new Variable("Sigma", new DoubleData(1.0)));
80
81      AddVariableInfo(new VariableInfo("Value", "The value to manipulate (actual type is one of: IntData, DoubleData, ConstrainedIntData, ConstrainedDoubleData)", typeof(IObjectData), VariableKind.In));
82      AddVariableInfo(new VariableInfo("ShakingFactor", "Determines the force of the shaking factor (effective sigma = sigma * shakingFactor)", typeof(DoubleData), VariableKind.In));
83      AddVariableInfo(new VariableInfo("Random", "The random generator to use", typeof(MersenneTwister), VariableKind.In));
84    }
85
86    /// <summary>
87    /// Generates a new normally distributed random number and adds it to the specified value in the
88    /// given <paramref name="scope"/>.
89    /// </summary>
90    /// <param name="scope">The scope where to add the generated random number.</param>
91    /// <returns><c>null</c>.</returns>
92    public override IOperation Apply(IScope scope) {
93      IObjectData value = GetVariableValue<IObjectData>("Value", scope, false);
94      MersenneTwister mt = GetVariableValue<MersenneTwister>("Random", scope, true);
95      double factor = GetVariableValue<DoubleData>("ShakingFactor", scope, true).Data;
96      double mu = GetVariableValue<DoubleData>("Mu", scope, true).Data;
97      double sigma = GetVariableValue<DoubleData>("Sigma", scope, true).Data;
98      NormalDistributedRandom normal = new NormalDistributedRandom(mt, mu, sigma * factor);
99
100      AddNormal(value, normal);
101      return null;
102    }
103
104    private void AddNormal(IObjectData value, NormalDistributedRandom normal) {
105      // dispatch manually based on dynamic type
106      if (value is IntData)
107        AddNormal((IntData)value, normal);
108      else if (value is ConstrainedIntData)
109        AddNormal((ConstrainedIntData)value, normal);
110      else if (value is ConstrainedDoubleData)
111        AddNormal((ConstrainedDoubleData)value, normal);
112      else if (value is DoubleData)
113        AddNormal((DoubleData)value, normal);
114      else throw new InvalidOperationException("Can't handle type " + value.GetType().Name);
115    }
116    /// <summary>
117    /// Generates a new double random number and adds it to the value of
118    /// the given <paramref name="data"/>.
119    /// </summary>
120    /// <param name="data">The double object where to add the random number.</param>
121    /// <param name="normal">The continuous, normally distributed random variable.</param>
122    public void AddNormal(DoubleData data, NormalDistributedRandom normal) {
123      data.Data += normal.NextDouble();
124    }
125
126    /// <summary>
127    /// Generates a new double random number and adds it to the value of the given <paramref name="data"/>
128    /// checking its constraints.
129    /// </summary>
130    /// <exception cref="InvalidProgramException">Thrown when with the current settings no valid value
131    /// could be found.</exception>
132    /// <param name="data">The double object where to add the random number and whose constraints
133    /// to fulfill.</param>
134    /// <param name="normal">The continuous, normally distributed random variable.</param>
135    public void AddNormal(ConstrainedDoubleData data, NormalDistributedRandom normal) {
136      for (int tries = MAX_NUMBER_OF_TRIES; tries >= 0; tries--) {
137        double newValue = data.Data + normal.NextDouble();
138        if (IsIntegerConstrained(data)) {
139          newValue = Math.Round(newValue);
140        }
141        if (data.TrySetData(newValue)) {
142          return;
143        }
144      }
145      throw new InvalidProgramException("Coudn't find a valid value");
146    }
147
148    /// <summary>
149    /// Generates a new int random number and adds it to value of the given <paramref name="data"/>.
150    /// </summary>
151    /// <param name="data">The int object where to add the random number.</param>
152    /// <param name="normal">The continuous, normally distributed random variable.</param>
153    public void AddNormal(IntData data, NormalDistributedRandom normal) {
154      data.Data = (int)Math.Round(data.Data + normal.NextDouble());
155    }
156
157    /// <summary>
158    /// Generates a new int random number and adds it to the value of the given <paramref name="data"/>
159    /// checking its constraints.
160    /// </summary>
161    /// <exception cref="InvalidProgramException">Thrown when with the current settings no valid value
162    /// could be found.</exception>
163    /// <param name="data">The int object where to add the generated value and whose contraints to check.</param>
164    /// <param name="normal">The continuous, normally distributed random variable.</param>
165    public void AddNormal(ConstrainedIntData data, NormalDistributedRandom normal) {
166      for (int tries = MAX_NUMBER_OF_TRIES; tries >= 0; tries--) {
167        if (data.TrySetData((int)Math.Round(data.Data + normal.NextDouble())))
168          return;
169      }
170      throw new InvalidProgramException("Couldn't find a valid value.");
171    }
172
173    private bool IsIntegerConstrained(ConstrainedDoubleData data) {
174      foreach (IConstraint constraint in data.Constraints) {
175        if (constraint is IsIntegerConstraint) {
176          return true;
177        }
178      }
179      return false;
180    }
181  }
182}
Note: See TracBrowser for help on using the repository browser.