├── random ├── util.v ├── string.v ├── rand.v └── math.v ├── .gitignore ├── v.mod ├── examples ├── string.v ├── math.v └── rand.v ├── LICENSE ├── .github └── workflows │ └── ci.yml ├── tests └── rand_test.v └── README.md /random/util.v: -------------------------------------------------------------------------------- 1 | module random 2 | 3 | fn range(start, end int) []int { 4 | mut arr := []int{} 5 | for i := start; i < end; i++ { 6 | arr << i 7 | } 8 | return arr 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !*.* 4 | *.exe 5 | *.o 6 | *.so 7 | .*.c 8 | *.tmp.c 9 | *.obj 10 | *.exp 11 | *.ilk 12 | *.pdb 13 | *.dll 14 | *.lib 15 | *.bak 16 | a.out 17 | .noprefix.vrepl_temp 18 | -------------------------------------------------------------------------------- /v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'range' 3 | author: 'Swastik Baranwal' 4 | version: '0.0.2' 5 | repo_url: 'https://github.com/Delta456/random' 6 | vcs: 'git' 7 | tags: ['random', 'python', 'vlang', 'variate'] 8 | description: 'An all purpose random library written in V.' 9 | license: 'MIT' 10 | } 11 | -------------------------------------------------------------------------------- /examples/string.v: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import rand 4 | 5 | fn main() { 6 | rand.seed([u32(time.now().unix), 0]) 7 | for i := 0; i < 5; i++ { 8 | println('${i+1} iteration') 9 | println(random.string(10)) 10 | println(random.string_alpha(10)) 11 | println('\n') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/math.v: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import rand 4 | 5 | fn main() { 6 | rand.seed([u32(time.now().unix), 0]) 7 | 8 | for i := 0; i < 5; i++ { 9 | println('${i+1} iteration') 10 | println(random.normal_variate(34.0, 5.0)) 11 | println(random.weibull_variate(3.3, 0.3)) 12 | println(random.beta_variate(1, 1.3)) 13 | println(random.pareto_variate(3.3)) 14 | println(random.uniform(1.4, 2.56)) 15 | println(random.triangular(mut random.Triangular{mode:1})) 16 | println(random.vommeises_variate(0.0, 1.0)) 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /examples/rand.v: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import rand 4 | 5 | fn main() { 6 | rand.seed([u32(time.now().unix), 0]) 7 | for i := 0; i < 5; i++ { 8 | println('${i+1} iteration') 9 | println(random.bool()) 10 | println(random.choose([2, 4, 6, 8, 9, 7])) 11 | println(random.shuffle([2, 4, 6, 8, 9, 7])) 12 | println(random.sample([2, 4, 6, 7, 12, 8, 4 , 7, 5], 6, false)) 13 | println(random.numeric(5)) 14 | println(random.int_range(start: 5, stop: 15, step: 2)) 15 | println(random.float_range(start: 5.3, stop: 15.4, step: 2.0)) 16 | println('\n') 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /random/string.v: -------------------------------------------------------------------------------- 1 | module random 2 | 3 | import rand 4 | 5 | const ( 6 | captial_letters = 'ABCDEFGHIJLMNOPQURSTUVWXYZ' 7 | small_letters = 'abcdefghijklmnopqurstuwxyz' 8 | letters = 'ABCDEFGHIJLMNOPQURSTUVWXYZabcdefghijklmnopqurstuwxyz' 9 | digits = '0123456789' 10 | symbols = '!@#$%^&*()_+=|/' 11 | ) 12 | 13 | // string returns a random string of n length 14 | pub fn string(n int) string { 15 | mut str := []string{} 16 | letters_ := letters.split('') 17 | for _ in range(0, n) { 18 | str << letters_[rand.intn(letters_.len)] 19 | } 20 | return str.join('') 21 | } 22 | 23 | // string_alpha returns an alpha string of n length 24 | pub fn string_alpha(n int) string { 25 | mut str := []string{} 26 | letters_ := letters.split('') 27 | nums := digits.split('') 28 | for _ in range(0, n) { 29 | // TODO: do this in a better way 30 | str << nums[rand.intn(nums.len)] + letters_[rand.intn(letters_.len)] 31 | } 32 | str2 := str.join('') 33 | return if str2.len > n { str2[..n] } else { str2 } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Swastik Baranwal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | ubuntu: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout V 10 | uses: actions/checkout@v2 11 | with: 12 | repository: vlang/v 13 | - name: Checkout random 14 | uses: actions/checkout@v2 15 | with: 16 | path: vlib/random 17 | - name: Build V 18 | run: | 19 | make 20 | sudo ./v symlink 21 | - name: Build example 22 | run: | 23 | cd ./vlib/random/ 24 | v test tests/rand_test.v 25 | 26 | macos: 27 | runs-on: macos-latest 28 | steps: 29 | - name: Checkout V 30 | uses: actions/checkout@v2 31 | with: 32 | repository: vlang/v 33 | - name: Checkout random 34 | uses: actions/checkout@v2 35 | with: 36 | path: vlib/random 37 | - name: Build V 38 | run: | 39 | make 40 | ./v symlink 41 | - name: Build example 42 | run: | 43 | cd ./vlib/random/ 44 | v test tests/rand_test.v 45 | 46 | windows-msvc: 47 | runs-on: windows-latest 48 | env: 49 | VFLAGS: -cc msvc 50 | steps: 51 | - name: Checkout V 52 | uses: actions/checkout@v2 53 | with: 54 | repository: vlang/v 55 | - name: Checkout random 56 | uses: actions/checkout@v2 57 | with: 58 | path: vlib/random 59 | - name: Build V 60 | run: .\make.bat -msvc -skip-path 61 | # Don't move applying V directory to PATH, to other steps 62 | - name: Build example 63 | run: .\v.exe test .\vlib\random\tests\rand_test.v 64 | -------------------------------------------------------------------------------- /tests/rand_test.v: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import rand 4 | 5 | fn init() { 6 | rand.seed([u32(time.now().unix), 0]) 7 | } 8 | 9 | fn test_bool() { 10 | for i := 0; i < 10; i++ { 11 | b := random.bool() 12 | assert b == true || b == false 13 | } 14 | } 15 | 16 | fn test_numeric() { 17 | for i := 0; i < 10; i++ { 18 | b := random.numeric(5) 19 | //println(b.str().len) 20 | assert b.str().len == 5 || b.str().len == 6 || b.str().len == 4 21 | } 22 | } 23 | 24 | fn test_int_range() { 25 | for i := 0; i < 10; i++ { 26 | b := random.int_range(start: 5, stop: 15, step: 2) 27 | assert b >= 5 28 | assert b < 15 29 | } 30 | 31 | for i := 0; i < 10; i++ { 32 | b := random.int_range(start: 15, stop: 1, step:-1) 33 | assert b <= 15 34 | assert b > 1 35 | } 36 | } 37 | 38 | fn test_float_range() { 39 | for i := 0; i < 10; i++ { 40 | b := random.float_range(start: 5.3, stop: 15.4, step: 2.0) 41 | assert b >= f32(5.3) 42 | assert b < f32(15.4) 43 | } 44 | 45 | for i := 0; i < 10; i++ { 46 | b := random.float_range(start: 15.0, stop: 5.3, step: -1) 47 | assert b <= f32(15.0) 48 | assert b > f32(5.3) 49 | } 50 | } 51 | 52 | fn test_choose() { 53 | for i := 0; i < 10; i++ { 54 | arr_int := [2, 5, 7, 8, 9, 10, 13] 55 | arr_u64 := [u64(2), 37, 56, 79, 10] 56 | 57 | assert random.choose(arr_int) in arr_int 58 | assert random.choose(arr_u64) in arr_u64 59 | } 60 | } 61 | 62 | fn test_shuffle() { 63 | for i := 0; i < 10; i++ { 64 | arr_int := [2, 5, 7, 8, 9, 10, 13] 65 | arr_u64 := [u64(2), 37, 56, 79, 10] 66 | 67 | assert random.shuffle(arr_int).len == arr_int.len 68 | assert random.shuffle(arr_u64).len == arr_u64.len 69 | } 70 | } 71 | /* 72 | fn test_sample() { 73 | for i := 0; i < 10; i++ { 74 | arr_int := [2, 5, 7, 8, 9, 10, 13] 75 | arr_u64 := [u64(2), 37, 56, 79, 10] 76 | 77 | assert random.sample(arr_int, 5, false).len == 5 78 | assert random.sample(arr_u64, 6, true).len == 6 79 | } 80 | } 81 | */ 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS MODULE HAS BEEN DEPRECATED AND [V'S RAND MODULE](https://github.com/vlang/v/tree/master/vlib/rand) SHOULD BE USED INSTEAD! 2 | 3 | # random 4 | 5 | An all purpose random library written in V. 6 | 7 | ## Features 8 | 9 | - All variate functions possible. 10 | - Generate random `int` and `string` with ease. 11 | - range functions for `int` and `f32`. 12 | - Array functions like `shuffle`, `choose`, `sample` etc. 13 | - Makes life easier *sorta* 14 | - Many more features coming soon! 15 | 16 | ## Installation 17 | 18 | - Via `git clone` 19 | - `git clone https://github.com/Delta456/random` 20 | - Via `v install` 21 | - `v install random` 22 | - Via `vpkg` 23 | - `vpkg install random` 24 | 25 | ## Docs 26 | 27 | ```v 28 | // struct for `triangular()` 29 | struct Triangular { 30 | mut: 31 | low f32 = 1.0 32 | high f32 = 1.0 33 | mode int = 1 34 | } 35 | 36 | // struct for `int_range()` 37 | struct IntRange { 38 | start int 39 | stop int 40 | step int = 1 41 | } 42 | 43 | // struct for `float_range()` 44 | struct FloatRange { 45 | start f32 46 | stop f32 47 | step f32 = 1.0 48 | } 49 | 50 | // normal_variate is the normal distribution where mu is the 51 | // mean, and stigma is the standard deviation 52 | fn normal_variate(mu, stigma f32) f32 53 | 54 | 55 | // expo_variate is the expovariate distribution where lambda is // 1.0 divided by the desired mean. It should be nonzero. 56 | // return values range from 0 to positive infinity if lambda is // positive else negative 57 | fn expo_variate(lambda f32) f32 58 | 59 | 60 | // weibull distribution where alpha is the scale parameter and 61 | // beta is the shape parameter 62 | fn weibull_variate(alpha, beta f32) f32 63 | 64 | // lognorm_variate is the log nomral distribution If you take 65 | // the natural logarithm of this distribution, you'll get a 66 | // normal distribution with mean mu and standard deviation 67 | //sigma. mu can have any value, and sigma must be greater than 68 | // zero 69 | fn lognorm_variate(mu, stigma f32) f32 70 | 71 | // gamma_distribution is the gamma distribution conditions on the parameters are alpha > 0 and beta > 0. 72 | // conditions on the parameters are alpha > 0 and beta > 0. 73 | // The probability distribution function is: 74 | // math.pow(x, (alpha - 1)) * math.exp(-x / beta) 75 | // pdf(x) = -------------------------------------- 76 | // math.gamma(alpha) * math.pow(beta, alpha) 77 | fn gamma_variate(alpha, beta f32) f32 78 | 79 | 80 | // beta_variate is the beta distribution parameters alpha > 0 81 | // and beta > 0 return values range between 0 and 1 82 | fn beta_variate(alpha, beta f32) f32 83 | 84 | 85 | // pareto_variate is pareto distribution. alpha is the shape 86 | // paramter. 87 | fn pareto_variate(alpha f32) f32 88 | 89 | // vommeises_variate is the circular data distribution 90 | // where mu is the mean angle, expressed in radians between 0 and 2*pi, and 91 | // kappa is the concentration parameter, which must be greater than or 92 | // equal to zero. If kappa is equal to zero, this distribution reduces 93 | // to a uniform random angle over the range 0 to 2*pi 94 | // mu: mean angle (in radians between 0 and 2*pi) 95 | // kappa: concentration parameter kappa (>= 0) 96 | // if kappa == 0 then generate uniform random angle 97 | fn vommeises_variate(mu, kappa f32) f32 98 | 99 | // triangular is the triangular distribution. continuous 100 | // distribution bounded by given lower and upper limits, and 101 | // having a given mode value in-between 102 | fn triangular(mut tri Triangular) f32 103 | 104 | // uniform returns a random number between the range [a, b) or 105 | // [a, b] depending on rounding 106 | fn uniform(a, b f32) f32 107 | 108 | // int_range returns a random int between the specified range 109 | fn int_range(range IntRange) int 110 | 111 | // float_range returns a random float upon the given range 112 | fn float_range(range FloatRange) f32 113 | 114 | // numeric returns a number with n digits long 115 | fn numeric(n int) int 116 | 117 | // bool returns a random bool 118 | fn bool() bool 119 | 120 | // shuffle returns the new shuffled array 121 | fn shuffle(arr []T) []T 122 | 123 | // sample returns the new k-sized array 124 | // no_repetitions must be true when no repetitions are needed 125 | // else it must be false 126 | fn sample(arr []T, k int) []T 127 | 128 | // choose returns a random element from the array 129 | fn choose(arr []T) T 130 | 131 | // string returns a random string of n length 132 | fn string(n int) string 133 | 134 | // string_alpha returns an alpha string of n length 135 | fn string_alpha(n int) string 136 | ``` 137 | 138 | ## Usage 139 | 140 | See [math](examples/rand.v), [random](examples/rand.v) and [string](examples/string.v) for usage. 141 | 142 | ## Acknowledgments 143 | 144 | I thank [Python Software Foundation](https://www.python.org/psf/) for their work on [random](https://github.com/python/cpython/blob/master/Lib/random.py) library which helped me to port variate functions. 145 | 146 | ## License 147 | 148 | Licensed under [MIT](LICENSE) 149 | -------------------------------------------------------------------------------- /random/rand.v: -------------------------------------------------------------------------------- 1 | module random 2 | 3 | import rand 4 | import math 5 | 6 | // struct for `int_range()` 7 | pub struct IntRange { 8 | start int 9 | stop int 10 | step int = 1 11 | } 12 | 13 | // struct for `float_range()` 14 | pub struct FloatRange { 15 | start f32 16 | stop f32 17 | step f32 = 1.0 18 | } 19 | 20 | // uniform returns a random number between the range [a, b) or [a, b] depending on rounding 21 | pub fn uniform(a, b f32) f32 { 22 | return a + (b - a) * rand.f32() 23 | } 24 | 25 | // int_range returns a random int between the specified range 26 | pub fn int_range(range IntRange) int { 27 | if range.stop == 0 { 28 | if range.start > 1 { 29 | return rand.intn(range.start) 30 | } 31 | eprintln('random: empty range for int_range()') 32 | exit(1) 33 | } 34 | width := range.stop - range.start 35 | mut n := 0 36 | if range.step == 1 { 37 | if width > 0 { 38 | return range.start + rand.intn(width) 39 | } 40 | eprintln('random: empty range for int_range($range.start, $range.stop, $width)') 41 | exit(1) 42 | } 43 | if range.step > 0 { 44 | n = (width + range.step - 1) / range.step 45 | } else if range.step < 0 { 46 | n = (width + range.step + 1) / range.step 47 | } else { 48 | eprintln('random.int_range: empty range provided') 49 | exit(1) 50 | } 51 | return range.start + range.step * rand.intn(n) 52 | } 53 | 54 | // float_range returns a random float upon the given range 55 | pub fn float_range(range FloatRange) f32 { 56 | if range.stop == 0 { 57 | if range.start >= 1 { 58 | return rand.f32n(range.start) 59 | } 60 | eprintln('random: empty range for float_range()') 61 | exit(1) 62 | } 63 | width := range.stop - range.start 64 | mut n := f32(0) 65 | if range.step == 1 { 66 | if width > 0 { 67 | return range.start + rand.f32n(width) 68 | } 69 | eprintln('random: empty range for float_range($range.start, $range.stop, $width)') 70 | exit(1) 71 | } 72 | if range.step > 0 { 73 | n = (width + range.step - 1) / range.step 74 | } else if range.step < 0 { 75 | n = (width + range.step + 1) / range.step 76 | } else { 77 | eprintln('random.float_range: empty range provided') 78 | exit(1) 79 | } 80 | mut result := range.start + range.step * rand.f32n(n) 81 | // this happens in worst cases 82 | if result > range.stop && range.step > 0 { 83 | for result > range.stop { 84 | result = range.start + range.step * rand.f32n(n) 85 | } 86 | } 87 | return result 88 | } 89 | 90 | // numeric returns a number with n digits long 91 | pub fn numeric(n int) int { 92 | if n <= 0 { 93 | eprintln('random.numeric: number must be greater than one') 94 | exit(1) 95 | } 96 | num := rand.int() % int(math.pow(10, n)) 97 | return num 98 | } 99 | 100 | // bool returns a random bool 101 | pub fn bool() bool { 102 | b := [true, false] 103 | return b[rand.intn(b.len)] 104 | } 105 | 106 | // shuffle returns the new shuffled array. 107 | pub fn shuffle(arr []T) []T { 108 | mut clone := arr.clone() 109 | for i in range(0, arr.len).reverse() { 110 | j := rand.intn(i + 1) 111 | temp := clone[j] 112 | clone[j] = clone[i] 113 | clone[i] = temp 114 | } 115 | return clone 116 | } 117 | 118 | // sample returns the new k-sized array 119 | // no_repetitions must be true when no repetitions are needed 120 | // else it must be false 121 | pub fn sample(arr []T, k int, no_repetitions bool) []T { 122 | mut sub_array := []T{} 123 | if k <= 0 { 124 | eprintln('random.sample: number should be greater than 0') 125 | exit(1) 126 | } 127 | if k == arr.len { 128 | eprintln('random.sample: k and length of array must not be equal') 129 | exit(1) 130 | } 131 | for _ in range(0, k) { 132 | j := rand.intn(arr.len) 133 | if no_repetitions { 134 | if arr[j] !in sub_array { 135 | sub_array << arr[j] 136 | } 137 | } else { 138 | sub_array << arr[j] 139 | } 140 | } 141 | // this can happen in the worst cases 142 | if sub_array.len != k { 143 | for sub_array.len != k { 144 | len := rand.intn(arr.len) 145 | if no_repetitions { 146 | if arr[len] !in sub_array { 147 | sub_array << arr[len] 148 | } 149 | } 150 | } 151 | } 152 | return sub_array 153 | } 154 | 155 | // choose returns a random element from the array 156 | pub fn choose(arr []T) T { 157 | return arr[rand.intn(arr.len)] 158 | } 159 | -------------------------------------------------------------------------------- /random/math.v: -------------------------------------------------------------------------------- 1 | module random 2 | 3 | import math 4 | import rand 5 | 6 | const ( 7 | pi = 3.141592653589793 8 | e = 2.718281828459045 9 | twopi = 2 * pi 10 | nv_magic = f32(4) * math.exp(-0.5) / math.sqrt(2.0) 11 | log4 = math.log(4.0) 12 | sg_magic = 1.0 + math.log(4.5) 13 | ) 14 | 15 | // struct for `triangular()` 16 | pub struct Triangular { 17 | mut: 18 | low f32 = 1.0 19 | high f32 = 1.0 20 | mode int = 1 21 | } 22 | 23 | // normal_variate is the normal distribution 24 | // where mu is the mean, and stigma is the standard deviation 25 | pub fn normal_variate(mu, stigma f32) f32 { 26 | for { 27 | u1 := rand.f32() 28 | u2 := 1.0 - rand.f32() 29 | z := nv_magic * (u1 - 0.5) / u2 30 | zz := z * z / 4.0 31 | if zz <= -math.log(u2) { 32 | break 33 | } 34 | return f32(mu + z * stigma) 35 | } 36 | } 37 | 38 | // expo_variate is the expovariate distribution 39 | // where lambda is 1.0 divided by the desired mean. It should be nonzerp. 40 | // return values range from 0 to positive infinity if lambda is positive else negative/ 41 | pub fn expo_variate(lambda f32) f32 { 42 | return f32(-math.log(1.0 - rand.f32()) / lambda) 43 | } 44 | 45 | // weibull_variate is the weibull distribution 46 | // where alpha is the scale parameter and beta is the shape parameter 47 | pub fn weibull_variate(alpha, beta f32) f32 { 48 | u := 1.0 - rand.f32() 49 | return f32(alpha * math.pow((-math.log(u)), (1.0 / beta))) 50 | } 51 | 52 | // lognorm_variate is the log nomral distribution 53 | // If you take the natural logarithm of this distribution, you'll get a 54 | // normal distribution with mean mu and standard deviation sigma. 55 | // mu can have any value, and sigma must be greater than zero 56 | pub fn lognorm_variate(mu, stigma f32) f32 { 57 | return f32(math.exp(normal_variate(mu, stigma))) 58 | } 59 | 60 | // gamma_distribution is the gamma distribution 61 | // conditions on the parameters are alpha > 0 and beta > 0. 62 | // The probability distribution function is: 63 | // math.pow(x, (alpha - 1)) * math.exp(-x / beta) 64 | // pdf(x) = -------------------------------------- 65 | // math.gamma(alpha) * math.pow(beta, alpha) 66 | pub fn gamma_variate(alpha, beta f32) f32 { 67 | if alpha <= 0.0 && beta <= 0.0 { 68 | eprintln('random.gamma_variate: alpha and beta must be > 0.0') 69 | exit(1) 70 | } 71 | if alpha > 1.0 { 72 | ainv := math.sqrt(2.0 * alpha - 1.0) 73 | bbb := alpha - log4 74 | ccc := alpha + ainv 75 | for { 76 | u1 := rand.f32() 77 | if !(1e-7 < u1 && u1 < .9999999) { 78 | continue 79 | } 80 | u2 := 1.0 - rand.f32() 81 | v := math.log(u1 / (1.0 - u1)) / ainv 82 | x := alpha * math.exp(v) 83 | z := u1 * u1 * u2 84 | r := bbb + ccc * v - x 85 | if r + sg_magic - 4.5 * z >= 0.0 || r >= math.log(z) { 86 | return f32(x * beta) 87 | } 88 | } 89 | } else if alpha == 1.0 { 90 | return f32(-math.log(1.0 - rand.f32()) * beta) 91 | } else { 92 | mut x := 0.0 93 | for { 94 | u := rand.f32() 95 | b := (e + alpha) / e 96 | p := b * u 97 | if p <= 1.0 { 98 | x = math.pow(p, 1.0 / alpha) 99 | } else { 100 | x = -math.log(b - p) 101 | } 102 | u1 := rand.f32() 103 | if p > 1.0 { 104 | if u1 <= math.pow(x, alpha - 1.0) { 105 | break 106 | } 107 | } else if u1 <= math.exp(-x) { 108 | break 109 | } 110 | } 111 | return f32(x * beta) 112 | } 113 | return 0.0 // TODO: remove this when V knows about this 114 | } 115 | 116 | // beta_variate is the beta distribution 117 | // parameters alpha > 0 and beta > 0 118 | // return values range between 0 and 1 119 | pub fn beta_variate(alpha, beta f32) f32 { 120 | y := gamma_variate(alpha, 1.0) 121 | if y == 0 { 122 | return 0.0 123 | } 124 | return y / (y + gamma_variate(beta, 1.0)) 125 | } 126 | 127 | // pareto_variate is pareto distribution. alpha is the shape paramter 128 | pub fn pareto_variate(alpha f32) f32 { 129 | u := 1.0 - rand.f32() 130 | return f32(1.0 / math.pow(u, 1.0 / alpha)) 131 | } 132 | 133 | // vommeises_variate is the circular data distribution 134 | // where mu is the mean angle, expressed in radians between 0 and 2*pi, and 135 | // kappa is the concentration parameter, which must be greater than or 136 | // equal to zero. If kappa is equal to zero, this distribution reduces 137 | // to a uniform random angle over the range 0 to 2*pi 138 | // mu: mean angle (in radians between 0 and 2*pi) 139 | // kappa: concentration parameter kappa (>= 0) 140 | // if kappa == 0 then generate uniform random angle 141 | pub fn vommeises_variate(mu, kappa f32) f32 { 142 | if kappa <= 1e-6 { 143 | return twopi * rand.f32() 144 | } 145 | s := 0.5 / kappa 146 | r := s + math.sqrt(1.0 * s + s) 147 | mut z := math.cos(pi * rand.f32()) 148 | for { 149 | u1 := rand.f32() 150 | d := z / (r + z) 151 | z = math.cos(pi * u1) 152 | u2 := rand.f32() 153 | if u2 < 1.0 - d * d || u2 < 1.0 - d * math.exp(d) { 154 | break 155 | } 156 | } 157 | mut theta := 0.0 158 | q := 1.0 / r 159 | f := (q + z) / (1.0 + q * z) 160 | u3 := rand.f32() 161 | if u3 > 0.5 { 162 | theta = math.fmod((mu + math.acos(f)), twopi) 163 | } else { 164 | theta = math.fmod((mu - math.acos(f)), twopi) 165 | } 166 | return f32(theta) 167 | } 168 | 169 | // triangular is the triangular distribution. 170 | // continuous distribution bounded by given lower and upper limits, 171 | // and having a given mode value in-between 172 | pub fn triangular(mut tri Triangular) f32 { 173 | mut u := rand.f32() 174 | mut c := if tri.mode == 1 { 0.5 } else { (tri.mode - tri.low) / (tri.high - tri.low) } 175 | if c == 0 { 176 | return tri.low 177 | } 178 | if u > c { 179 | u -= 1.0 180 | c -= 1.0 181 | tri.low, tri.high = tri.high, tri.low 182 | } 183 | return f32(tri.low + (tri.high - tri.low) * math.sqrt(u * c)) 184 | } 185 | --------------------------------------------------------------------------------