source: trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/ValueGenerator.cs @ 11434

Last change on this file since 11434 was 11434, checked in by mkommend, 6 years ago

#2259: Changed ValueGenerator to work with decimals instead of doubles to achieve a higher accuracy and adapted all problem instance providers accordingly.

File size: 7.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 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.Common;
26using HeuristicLab.Random;
27
28namespace HeuristicLab.Problems.Instances.DataAnalysis {
29  public static class ValueGenerator {
30    private static FastRandom rand = new FastRandom();
31
32    /// <summary>
33    /// Generates a sequence of evenly spaced points by returning the start value and adding the stepwidth until the end is reached or surpassed.
34    ///
35    /// </summary>
36    /// <param name="start">The smallest and first value of the sequence.</param>
37    /// <param name="end">The largest and last value of the sequence.</param>
38    /// <param name="stepWidth">The step size between subsequent values.</param>
39    /// <returns>A sequence of values from start to end (inclusive)</returns>
40    [Obsolete("It is recommended to use the decimal overload to achieve a higher numerical accuracy.")]
41    public static IEnumerable<double> GenerateSteps(double start, double end, double stepWidth) {
42      //mkommend: IEnumerable.Cast fails due to boxing and unboxing of the involved types
43      // http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs#27bb217a6d5457ec
44      // http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx     
45
46      return GenerateSteps((decimal)start, (decimal)end, (decimal)stepWidth).Select(x => (double)x);
47    }
48
49    /// <summary>
50    /// Generates a sequence of evenly spaced points by returning the start value and adding the stepwidth until the end is reached or surpassed.
51    /// </summary>
52    /// <param name="start">The smallest and first value of the sequence.</param>
53    /// <param name="end">The largest and last value of the sequence.</param>
54    /// <param name="stepWidth">The step size between subsequent values.</param>
55    /// <returns>A sequence of values from start to end</returns>
56    public static IEnumerable<decimal> GenerateSteps(decimal start, decimal end, decimal stepWidth) {
57      if (stepWidth == 0)
58        throw new ArgumentException("The step width cannot be zero.");
59      if (start < end && stepWidth < 0)
60        throw new ArgumentException("The step width must be larger than zero for increasing sequences (start < end).");
61      if (start > end && stepWidth > 0)
62        throw new ArgumentException("The step width must be smaller than zero for decreasing sequences (start > end).");
63
64      decimal x = start;
65      while (x <= end) {
66        yield return x;
67        x += stepWidth;
68      }
69    }
70
71    /// <summary>
72    /// Generates a sequence of points between start and end according to given transformation
73    /// </summary>
74    /// <param name="start">The smallest and first value of the sequence.</param>
75    /// <param name="end">The largest and last value of the sequence.</param>
76    /// <param name="stepWidth">The step size between subsequent values (before transform)</param>
77    /// <param name="transform">The transform function</param>
78    /// <returns></returns>
79    [Obsolete("It is recommended to use the decimal overload to achieve a higher numerical accuracy.")]
80    public static IEnumerable<double> GenerateSteps(double start, double end, double stepWidth, Func<double, double> transform) {
81      return GenerateSteps(start,end, stepWidth).Select(transform);
82    }
83
84    /// <summary>
85    /// Generates a sequence of points between start and end according to given transformation
86    /// </summary>
87    /// <param name="start">The smallest and first value of the sequence.</param>
88    /// <param name="end">The largest and last value of the sequence.</param>
89    /// <param name="stepWidth">The step size between subsequent values (before transform)</param>
90    /// <param name="transform">The transform function</param>
91    /// <returns></returns>
92    public static IEnumerable<decimal> GenerateSteps(decimal start, decimal end, decimal stepWidth, Func<decimal, decimal> transform) {
93      return GenerateSteps(start, end, stepWidth).Select(transform);
94    }
95
96    /// <summary>
97    /// Generates uniformly distributed values between start and end (inclusive!)
98    /// </summary>
99    /// <param name="n">Number of values to generate.</param>
100    /// <param name="start">The lower value (inclusive)</param>
101    /// <param name="end">The upper value (inclusive)</param>
102    /// <returns>An enumerable including n values in [start, end]</returns>
103    public static IEnumerable<double> GenerateUniformDistributedValues(int n, double start, double end) {
104      for (int i = 0; i < n; i++) {
105        // we need to return a random value including end.
106        // so we cannot use rand.NextDouble() as it returns a value strictly smaller than 1.
107        double r = rand.NextUInt() / (double)uint.MaxValue;    // r \in [0,1]
108        yield return r * (end - start) + start;
109      }
110    }
111
112    /// <summary>
113    /// Generates normally distributed values sampling from N(mu, sigma)
114    /// </summary>
115    /// <param name="n">Number of values to generate.</param>
116    /// <param name="mu">The mu parameter of the normal distribution</param>
117    /// <param name="sigma">The sigma parameter of the normal distribution</param>
118    /// <returns>An enumerable including n values ~ N(mu, sigma)</returns>
119    public static IEnumerable<double> GenerateNormalDistributedValues(int n, double mu, double sigma) {
120      for (int i = 0; i < n; i++)
121        yield return NormalDistributedRandom.NextDouble(rand, mu, sigma);
122    }
123
124    // iterative approach
125    public static IEnumerable<IEnumerable<double>> GenerateAllCombinationsOfValuesInLists(List<List<double>> lists) {
126      List<List<double>> allCombinations = new List<List<double>>();
127      if (lists.Count < 1) {
128        return allCombinations;
129      }
130
131      List<IEnumerator<double>> enumerators = new List<IEnumerator<double>>();
132      foreach (var list in lists) {
133        allCombinations.Add(new List<double>());
134        enumerators.Add(list.GetEnumerator());
135      }
136
137      bool finished = !enumerators.All(x => x.MoveNext());
138
139      while (!finished) {
140        GetCurrentCombination(enumerators, allCombinations);
141        finished = MoveNext(enumerators, lists);
142      }
143      return allCombinations;
144    }
145
146    private static bool MoveNext(List<IEnumerator<double>> enumerators, List<List<double>> lists) {
147      int cur = enumerators.Count - 1;
148      while (cur >= 0 && !enumerators[cur].MoveNext()) {
149        enumerators[cur] = lists[cur].GetEnumerator();
150        enumerators[cur].MoveNext();
151        cur--;
152      }
153      return cur < 0;
154    }
155
156    private static void GetCurrentCombination(List<IEnumerator<double>> enumerators, List<List<double>> allCombinations) {
157      for (int i = 0; i < enumerators.Count(); i++) {
158        allCombinations[i].Add(enumerators[i].Current);
159      }
160    }
161  }
162}
Note: See TracBrowser for help on using the repository browser.