1 #Region "Microsoft.VisualBasic::e0858066f6059c99d992433f06e94812, Microsoft.VisualBasic.Core\Extensions\Math\Random\RandomExtensions.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Delegate Function
35     
36     
37     '     Delegate Function
38     
39     
40     '     Module RandomExtensions
41     
42     '         Function: (+2 OverloadsGetRandomValue, NextBoolean, (+2 OverloadsNextDouble, NextGaussian, NextTriangular
43     '                   Permutation, randf, RandomSingle, Seed
44     
45     '         Sub: (+2 Overloads) Shuffle
46     
47     
48     
49     
50     
51     ' /********************************************************************************/
52
53 #End Region
54
55 Imports System.Runtime.CompilerServices
56 Imports Microsoft.VisualBasic.CommandLine.Reflection
57 Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
58 Imports Microsoft.VisualBasic.Language.C
59 Imports Microsoft.VisualBasic.Scripting.MetaData
60 Imports sys = System.Math
61
62 Namespace Math
63
64     ''' <summary>
65     ''' Generates a random number.
66     ''' (事实上这个函数指针的功能仅仅是返回一个实数,所以这里不仅仅是局限于随机数,也可以是一个固定值的实数)
67     ''' </summary>
68     ''' <returns></returns>
69     Public Delegate Function IValueProvider() As Double
70
71     ''' <summary>
72     ''' Tells the function how to generates a new random seed?
73     ''' </summary>
74     ''' <returns></returns>
75     Public Delegate Function IRandomSeeds() As Random
76
77     ''' <summary>
78     ''' Some extension methods for <see cref="System.Random"/> for creating a few more kinds of random stuff.
79     ''' </summary>
80     ''' <remarks>Imports from https://github.com/rvs76/superbest-random.git </remarks>
81     ''' 
82     <Package("Random", Publisher:="rvs76", Description:="Some extension methods for Random for creating a few more kinds of random stuff.")>
83     Public Module RandomExtensions
84
85         ''' <summary>
86         ''' A number used to calculate a starting value for the pseudo-random number sequence.
87         ''' If a negative number is specified, the absolute value of the number is used.
88         ''' </summary>
89         ''' <returns></returns>
90         Public Function Seed() As Integer
91             Dim seeds& = CLng(Integer.MaxValue) * 2
92             VisualBasic.Randomize()
93             seeds = (Rnd() * SecurityString.ToLong(SecurityString.GetMd5Hash(Now.ToString))) / seeds
94             Return CInt(seeds)
95         End Function
96
97         ''' <summary>
98         ''' 返回<paramref name="min"/>到<paramref name="max"/>区间之内的一个和实数
99         ''' </summary>
100         ''' <param name="min"></param>
101         ''' <param name="max"></param>
102         ''' <returns></returns>
103         Public Function randf(min As Double, max As DoubleAs Double
104             Dim minInteger& = CLng(sys.Truncate(min * 10000))
105             Dim maxInteger& = CLng(sys.Truncate(max * 10000))
106             Dim randInteger& = CLng(RandomNumbers.rand()) * CLng(RandomNumbers.rand())
107             Dim diffInteger& = maxInteger - minInteger
108             Dim resultInteger& = randInteger Mod diffInteger + minInteger
109             Return resultInteger / 10000.0
110         End Function
111
112         ReadOnly __randomSeeds As New Random(Rnd() * 10000)
113
114         Public Function RandomSingle() As Single
115             Dim result = __randomSeeds.NextDouble()
116             Return CSng(result)
117         End Function
118
119         <Extension>
120         Public Function GetRandomValue(rng As DoubleRange) As Double
121             SyncLock __randomSeeds
122                 Return __randomSeeds.NextDouble(range:=rng)
123             End SyncLock
124         End Function
125
126         ''' <summary>
127         ''' Returns a random floating-point number that is greater than or equal to min of the range,
128         ''' and less than the max of the range.
129         ''' </summary>
130         ''' <param name="rnd"></param>
131         ''' <param name="range"></param>
132         ''' <returns></returns>
133         <Extension>
134         Public Function NextDouble(rnd As Random, range As DoubleRange) As Double
135             Return range.Length * rnd.NextDouble + range.Min
136         End Function
137
138         <Extension>
139         Public Function NextDouble(rand As Random, min#, max#) As Double
140             Return (max - min) * rand.NextDouble + min
141         End Function
142
143         <Extension>
144         Public Function GetRandomValue(rng As IntRange) As Integer
145             Return rng.Length * __randomSeeds.NextDouble + rng.Min
146         End Function
147
148         ''' <summary>
149         ''' Generates normally distributed numbers. Each operation makes two Gaussians for the price of one, and apparently they can be cached or something for better performance, but who cares.
150         ''' </summary>
151         ''' <param name="r"></param>
152         ''' <param name = "mu">Mean of the distribution</param>
153         ''' <param name = "sigma">Standard deviation</param>
154         ''' <returns></returns>
155         ''' 
156         <ExportAPI("NextGaussian")>
157         <Extension> Public Function NextGaussian(r As Random, Optional mu As Double = 0, Optional sigma As Double = 1) As Double
158             Dim u1 As Double = r.NextDouble()
159             Dim u2 As Double = r.NextDouble()
160
161             Dim rand_std_normal = sys.Sqrt(-2.0 * sys.Log(u1)) * sys.Sin(2.0 * sys.PI * u2)
162             Dim rand_normal = mu + sigma * rand_std_normal
163
164             Return rand_normal
165         End Function
166
167         ''' <summary>
168         ''' Generates values from a triangular distribution.
169         ''' </summary>
170         ''' <remarks>
171         ''' See http://en.wikipedia.org/wiki/Triangular_distribution for a description of the triangular probability distribution and the algorithm for generating one.
172         ''' </remarks>
173         ''' <param name="r"></param>
174         ''' <param name = "a">Minimum</param>
175         ''' <param name = "b">Maximum</param>
176         ''' <param name = "c">Mode (most frequent value)</param>
177         ''' <returns></returns>
178         ''' 
179         <ExportAPI("NextTriangular")>
180         <Extension> Public Function NextTriangular(r As Random, a As Double, b As Double, c As DoubleAs Double
181             Dim u As Double = r.NextDouble()
182             Return If(u < (c - a) / (b - a), a + sys.Sqrt(u * (b - a) * (c - a)), b - sys.Sqrt((1 - u) * (b - a) * (b - c)))
183         End Function
184
185         ''' <summary>
186         ''' Equally likely to return true or false. Uses <see cref="Random.Next(Integer)"/>.
187         ''' </summary>
188         ''' <returns></returns>
189         ''' <remarks>
190         ''' ```vbnet
191         ''' 1 > 0 OR 0 > 0
192         ''' ```
193         ''' </remarks>
194         <ExportAPI("NextBoolean")>
195         <Extension> Public Function NextBoolean(r As Random) As Boolean
196             Return r.[Next](2) > 0 ' 1 > 0 OR 0 > 0
197         End Function
198
199         ''' <summary>
200         ''' Shuffles a list in O(n) time by using the Fisher-Yates/Knuth algorithm.
201         ''' </summary>
202         ''' <param name="r"></param>
203         ''' <param name = "list"></param>
204         <Extension> Public Sub Shuffle(Of T)(r As Random, ByRef list As List(Of T))
205             For i As Integer = 0 To list.Count - 1
206                 Dim j As Integer = r.[Next](0, i + 1)
207                 Dim temp As T = list(j)
208                 list(j) = list(i)
209                 list(i) = temp
210             Next
211         End Sub
212
213         ''' <summary>
214         ''' Shuffles a list in O(n) time by using the Fisher-Yates/Knuth algorithm.
215         ''' </summary>
216         ''' <param name="r"></param>
217         ''' <param name = "list"></param>
218         ''' 
219         <ExportAPI("Shuffle")>
220         Public Sub Shuffle(r As Random, ByRef list As IList)
221             For i As Integer = 0 To list.Count - 1
222                 Dim j As Integer = r.[Next](0, i + 1)
223                 Dim temp = list(j)
224                 list(j) = list(i)
225                 list(i) = temp
226             Next
227         End Sub
228
229         ''' <summary>
230         ''' Returns n unique random numbers in the range [1, n], inclusive. 
231         ''' This is equivalent to getting the first n numbers of some random permutation of the sequential numbers from 1 to max. 
232         ''' Runs in O(k^2) time.
233         ''' </summary>
234         ''' <param name="rand"></param>
235         ''' <param name="n">Maximum number possible.(最大值)</param>
236         ''' <param name="k">How many numbers to return.(返回的数据的数目)</param>
237         ''' <returns></returns>
238         ''' 
239         <ExportAPI("Permutation")>
240         <Extension> Public Function Permutation(rand As Random, n As Integer, k As IntegerAs Integer()
241             Dim result As New List(Of Integer)()
242             Dim sorted As New SortedSet(Of Integer)()
243
244             For i As Integer = 0 To k - 1
245                 Dim r = rand.[Next](1, n + 1 - i)
246
247                 For Each q As Integer In sorted
248                     If r >= q Then
249                         r += 1
250                     End If
251                 Next
252
253                 result.Add(r)
254                 sorted.Add(r)
255             Next
256
257             Return result.ToArray()
258         End Function
259     End Module
260 End Namespace