random-number-generator.scm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. (library (random-number-generator)
  2. (export make-random-integer-generator
  3. make-random-floats-generator
  4. generate-n-unique-integers
  5. generate-random-list
  6. generate-n-integers
  7. generate-n-floats)
  8. (import (except (rnrs base) error map)
  9. (only (guile)
  10. lambda* λ
  11. ;; output
  12. simple-format
  13. ;; error "handling"
  14. error
  15. ;; control flow
  16. when
  17. unless)
  18. ;; SRFI 1: list procedures
  19. (srfi srfi-1)
  20. ;; SRFI-27 for random number utilities
  21. (srfi srfi-27)
  22. ;; SRFI 43: vectors
  23. (srfi srfi-43)
  24. ;; SRFI 69: hash tables
  25. (srfi srfi-69)
  26. (ice-9 pretty-print)
  27. (ice-9 match)
  28. ;; purely functional data structures
  29. (pfds sets)
  30. ;; for fisher-yates-shuffle
  31. (only (shuffling) fisher-yates-shuffle))
  32. (define make-random-integer-generator
  33. (lambda* (#:key (seed #f))
  34. "Get a procedure for generating uniformly distributed
  35. random integers from 0 up to a not included bound, which is
  36. seeded by the keyword argument seed, which must be a
  37. positive integer."
  38. (cond
  39. [seed
  40. (let ([rand-src (make-random-source)])
  41. ;; Set the given seed to guarantee same results for
  42. ;; same invokations.
  43. (random-source-pseudo-randomize! rand-src 0 seed)
  44. ;; Obtain a procedure, which gives uniformly
  45. ;; distributed integers.
  46. (random-source-make-integers rand-src))]
  47. [else
  48. (let ([rand-src (make-random-source)])
  49. ;; Try to make the random source truly random. How
  50. ;; this works depends on the specific implementation
  51. ;; of SRFI-27.
  52. (random-source-randomize! rand-src)
  53. (random-source-make-integers rand-src))])))
  54. (define make-random-floats-generator
  55. (lambda* (#:key (seed #f))
  56. "Get a procedure for generating uniformly distributed
  57. random floats from 0 up to a not included bound, which is
  58. seeded by the keyword argument seed, which must be a
  59. positive integer."
  60. (cond
  61. [seed
  62. (let ([rand-src (make-random-source)])
  63. ;; Set the given seed to guarantee same results for
  64. ;; same invokations.
  65. (random-source-pseudo-randomize! rand-src 0 seed)
  66. ;; Obtain a procedure, which gives uniformly
  67. ;; distributed integers.
  68. (random-source-make-reals rand-src))]
  69. [else
  70. (let ([rand-src (make-random-source)])
  71. ;; Try to make the random source truly random. How
  72. ;; this works depends on the specific implementation
  73. ;; of SRFI-27.
  74. (random-source-randomize! rand-src)
  75. (random-source-make-reals rand-src))])))
  76. (define generate-n-unique-integers
  77. (lambda* (n
  78. minimum
  79. maximum
  80. #:key (rng (make-random-integer-generator #:seed 12345)))
  81. (when (> n (- maximum minimum))
  82. (error
  83. (simple-format
  84. #f "range from ~a to ~a is too small for generating ~a unique integers"
  85. minimum maximum n)))
  86. (let ([gen-range (- maximum minimum)])
  87. ;; Need to shuffle, because set->list gives same result for
  88. ;; all sets which have the same entries, no matter in which
  89. ;; order the keys were added.
  90. (fisher-yates-shuffle
  91. (set->list
  92. (let iter ([gen-count° 0] [numbers° (make-set <)])
  93. (cond
  94. [(>= gen-count° n) numbers°]
  95. [else
  96. (let ([generated-num (rng gen-range)])
  97. (cond
  98. [(set-member? numbers° generated-num)
  99. (iter gen-count°
  100. numbers°)]
  101. [else
  102. (iter (+ gen-count° 1)
  103. (set-insert numbers° generated-num))]))])))
  104. #:rng rng))))
  105. (define generate-n-integers
  106. (lambda* (n
  107. minimum
  108. maximum
  109. #:key (rng (make-random-integer-generator #:seed 12345)))
  110. (let ([gen-range (- maximum minimum)])
  111. (let iter ([gen-count° 0] [numbers° '()])
  112. (cond
  113. [(>= gen-count° n) numbers°]
  114. [else
  115. (let ([generated-num (+ (rng gen-range) minimum)])
  116. (iter (+ gen-count° 1)
  117. (cons generated-num numbers°)))])))))
  118. (define scale-float
  119. (λ (num mininum maximum)
  120. (let ([scaling-factor (- maximum mininum)])
  121. (+ (* num scaling-factor) mininum))))
  122. (define generate-n-floats
  123. (lambda* (n
  124. minimum
  125. maximum
  126. #:key (rng (make-random-floats-generator #:seed 12345)))
  127. (let iter ([gen-count° 0] [numbers° '()])
  128. (cond
  129. [(>= gen-count° n) numbers°]
  130. [else
  131. (let ([generated-num (scale-float (rng) minimum maximum)])
  132. (iter (+ gen-count° 1)
  133. (cons generated-num numbers°)))]))))
  134. (define generate-random-list
  135. (lambda* (length
  136. event-limit-table
  137. #:key
  138. (rng (make-random-integer-generator #:seed 12345)))
  139. "Create a list of length LENGTH of randomly selected events
  140. from the given hash table EVENT-COUNTS."
  141. (when (> length (apply + (hash-table-values event-limit-table)))
  142. (error "invalid arguments: length too high"))
  143. (let* ([result-vector (make-vector length)]
  144. [count-events (hash-table-fold event-limit-table
  145. (λ (key val previous)
  146. (+ previous val))
  147. 0)]
  148. [random-indices (generate-n-unique-integers count-events
  149. 0
  150. count-events
  151. #:rng rng)])
  152. ;; Fill result vector for all events
  153. (let iter ([random-indices° random-indices]
  154. [event-limit-alist° (hash-table->alist event-limit-table)])
  155. (cond
  156. [(null? event-limit-alist°)
  157. (vector->list result-vector)]
  158. [else
  159. (let* ([event (car (first event-limit-alist°))]
  160. [count (cdr (first event-limit-alist°))])
  161. ;; (simple-format #t "filling result vector with event ~a count ~a\n" event count)
  162. ;; Fill result vector for a specific event.
  163. (let iter-single-event ([indices° (take random-indices° count)])
  164. ;; (simple-format #t "setting event ~a at indices ~a\n" event indices°)
  165. (unless (null? indices°)
  166. (vector-set! result-vector
  167. (first indices°)
  168. event)
  169. (iter-single-event (drop indices° 1))))
  170. (iter (drop random-indices° count)
  171. (drop event-limit-alist° 1)))])))))
  172. #;(define make-random-uniform-sum-distribution-generator
  173. (λ (#:key (seed 12345))
  174. "Uniform sum distribution, also known as Irwin–Hall distribution."
  175. (let ([rng (make-random-integer-generator #:seed seed)])
  176. (λ ()
  177. ))))
  178. #;(define make-random-normal-distribution-generator
  179. (λ (#:key seed)
  180. ...
  181. ))
  182. )