1 #Region "Microsoft.VisualBasic::33776f60c24dae9f2254b706bc01cec0, 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             Randomize()
93             seeds = (Rnd() * SecurityString.ToLong(SecurityString.GetMd5Hash(Now.ToString))) / seeds
94             Return CInt(seeds)
95         End Function
96
97         Const RandfMultiply# = 10000
98
99         ''' <summary>
100         ''' 返回<paramref name="min"/>到<paramref name="max"/>区间之内的一个和实数
101         ''' </summary>
102         ''' <param name="min"></param>
103         ''' <param name="max"></param>
104         ''' <returns></returns>
105         Public Function randf(min As Double, max As DoubleAs Double
106             Dim minInteger& = CLng(sys.Truncate(min * RandfMultiply))
107             Dim maxInteger& = CLng(sys.Truncate(max * RandfMultiply))
108             Dim randInteger& = CLng(RandomNumbers.rand()) * CLng(RandomNumbers.rand())
109             Dim diffInteger& = maxInteger - minInteger
110             Dim resultInteger& = randInteger Mod diffInteger + minInteger
111
112             Return resultInteger / RandfMultiply
113         End Function
114
115         ReadOnly seeds As New Random(Rnd() * 10000)
116
117         <MethodImpl(MethodImplOptions.AggressiveInlining)>
118         Public Function RandomSingle() As Single
119             Return seeds.NextDouble()
120         End Function
121
122         <Extension>
123         Public Function GetRandomValue(rng As DoubleRange) As Double
124             SyncLock seeds
125                 Return seeds.NextDouble(range:=rng)
126             End SyncLock
127         End Function
128
129         ''' <summary>
130         ''' Returns a random floating-point number that is greater than or equal to min of the range,
131         ''' and less than the max of the range.
132         ''' </summary>
133         ''' <param name="rnd"></param>
134         ''' <param name="range"></param>
135         ''' <returns></returns>
136         <Extension>
137         Public Function NextDouble(rnd As Random, range As DoubleRange) As Double
138             Return range.Length * rnd.NextDouble + range.Min
139         End Function
140
141         <Extension>
142         Public Function NextDouble(rand As Random, min#, max#) As Double
143             Return (max - min) * rand.NextDouble + min
144         End Function
145
146         <Extension>
147         Public Function GetRandomValue(rng As IntRange) As Integer
148             Return rng.Length * seeds.NextDouble + rng.Min
149         End Function
150
151         ''' <summary>
152         ''' 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.
153         ''' </summary>
154         ''' <param name="r"></param>
155         ''' <param name = "mu">Mean of the distribution</param>
156         ''' <param name = "sigma">Standard deviation</param>
157         ''' <returns></returns>
158         ''' 
159         <ExportAPI("NextGaussian")>
160         <Extension> Public Function NextGaussian(r As Random, Optional mu As Double = 0, Optional sigma As Double = 1) As Double
161             Dim u1 As Double = r.NextDouble()
162             Dim u2 As Double = r.NextDouble()
163
164             Dim rand_std_normal = sys.Sqrt(-2.0 * sys.Log(u1)) * sys.Sin(2.0 * sys.PI * u2)
165             Dim rand_normal = mu + sigma * rand_std_normal
166
167             Return rand_normal
168         End Function
169
170         ''' <summary>
171         ''' Generates values from a triangular distribution.
172         ''' </summary>
173         ''' <remarks>
174         ''' See http://en.wikipedia.org/wiki/Triangular_distribution for a description of the triangular probability distribution and the algorithm for generating one.
175         ''' </remarks>
176         ''' <param name="r"></param>
177         ''' <param name = "a">Minimum</param>
178         ''' <param name = "b">Maximum</param>
179         ''' <param name = "c">Mode (most frequent value)</param>
180         ''' <returns></returns>
181         ''' 
182         <ExportAPI("NextTriangular")>
183         <Extension> Public Function NextTriangular(r As Random, a As Double, b As Double, c As DoubleAs Double
184             Dim u As Double = r.NextDouble()
185             Return If(u < (c - a) / (b - a), a + sys.Sqrt(u * (b - a) * (c - a)), b - sys.Sqrt((1 - u) * (b - a) * (b - c)))
186         End Function
187
188         ''' <summary>
189         ''' Equally likely to return true or false. Uses <see cref="Random.Next(Integer)"/>.
190         ''' </summary>
191         ''' <returns></returns>
192         ''' <remarks>
193         ''' ```vbnet
194         ''' 1 > 0 OR 0 > 0
195         ''' ```
196         ''' </remarks>
197         <ExportAPI("NextBoolean")>
198         <Extension> Public Function NextBoolean(r As Random) As Boolean
199             Return r.[Next](2) > 0 ' 1 > 0 OR 0 > 0
200         End Function
201
202         ''' <summary>
203         ''' Shuffles a list in O(n) time by using the Fisher-Yates/Knuth algorithm.
204         ''' </summary>
205         ''' <param name="r"></param>
206         ''' <param name = "list"></param>
207         <Extension> Public Sub Shuffle(Of T)(r As Random, ByRef list As List(Of T))
208             For i As Integer = 0 To list.Count - 1
209                 Dim j As Integer = r.[Next](0, i + 1)
210                 Dim temp As T = list(j)
211                 list(j) = list(i)
212                 list(i) = temp
213             Next
214         End Sub
215
216         ''' <summary>
217         ''' Shuffles a list in O(n) time by using the Fisher-Yates/Knuth algorithm.
218         ''' </summary>
219         ''' <param name="r"></param>
220         ''' <param name = "list"></param>
221         ''' 
222         <ExportAPI("Shuffle")>
223         Public Sub Shuffle(r As Random, ByRef list As IList)
224             For i As Integer = 0 To list.Count - 1
225                 Dim j As Integer = r.[Next](0, i + 1)
226                 Dim temp = list(j)
227                 list(j) = list(i)
228                 list(i) = temp
229             Next
230         End Sub
231
232         ''' <summary>
233         ''' Returns n unique random numbers in the range [1, n], inclusive. 
234         ''' This is equivalent to getting the first n numbers of some random permutation of the sequential numbers from 1 to max. 
235         ''' Runs in O(k^2) time.
236         ''' </summary>
237         ''' <param name="rand"></param>
238         ''' <param name="n">Maximum number possible.(最大值)</param>
239         ''' <param name="k">How many numbers to return.(返回的数据的数目)</param>
240         ''' <returns></returns>
241         ''' 
242         <ExportAPI("Permutation")>
243         <Extension> Public Function Permutation(rand As Random, n As Integer, k As IntegerAs Integer()
244             Dim result As New List(Of Integer)()
245             Dim sorted As New SortedSet(Of Integer)()
246
247             For i As Integer = 0 To k - 1
248                 Dim r = rand.[Next](1, n + 1 - i)
249
250                 For Each q As Integer In sorted
251                     If r >= q Then
252                         r += 1
253                     End If
254                 Next
255
256                 result.Add(r)
257                 sorted.Add(r)
258             Next
259
260             Return result.ToArray()
261         End Function
262     End Module
263 End Namespace