Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Random/3.2/NormalRandomAdder.cs @ 2940

Last change on this file since 2940 was 2365, checked in by gkronber, 15 years ago

Fixed #747 (GP engines create model with non-zero time-offsets).

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