123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- (library (random-number-generator)
- (export make-random-integer-generator
- make-random-floats-generator
- generate-n-unique-integers
- generate-random-list
- generate-n-integers
- generate-n-floats)
- (import (except (rnrs base) error map)
- (only (guile)
- lambda* λ
- ;; output
- simple-format
- ;; error "handling"
- error
- ;; control flow
- when
- unless)
- ;; SRFI 1: list procedures
- (srfi srfi-1)
- ;; SRFI-27 for random number utilities
- (srfi srfi-27)
- ;; SRFI 43: vectors
- (srfi srfi-43)
- ;; SRFI 69: hash tables
- (srfi srfi-69)
- (ice-9 pretty-print)
- (ice-9 match)
- ;; purely functional data structures
- (pfds sets)
- ;; for fisher-yates-shuffle
- (only (shuffling) fisher-yates-shuffle))
- (define make-random-integer-generator
- (lambda* (#:key (seed #f))
- "Get a procedure for generating uniformly distributed
- random integers from 0 up to a not included bound, which is
- seeded by the keyword argument seed, which must be a
- positive integer."
- (cond
- [seed
- (let ([rand-src (make-random-source)])
- ;; Set the given seed to guarantee same results for
- ;; same invokations.
- (random-source-pseudo-randomize! rand-src 0 seed)
- ;; Obtain a procedure, which gives uniformly
- ;; distributed integers.
- (random-source-make-integers rand-src))]
- [else
- (let ([rand-src (make-random-source)])
- ;; Try to make the random source truly random. How
- ;; this works depends on the specific implementation
- ;; of SRFI-27.
- (random-source-randomize! rand-src)
- (random-source-make-integers rand-src))])))
- (define make-random-floats-generator
- (lambda* (#:key (seed #f))
- "Get a procedure for generating uniformly distributed
- random floats from 0 up to a not included bound, which is
- seeded by the keyword argument seed, which must be a
- positive integer."
- (cond
- [seed
- (let ([rand-src (make-random-source)])
- ;; Set the given seed to guarantee same results for
- ;; same invokations.
- (random-source-pseudo-randomize! rand-src 0 seed)
- ;; Obtain a procedure, which gives uniformly
- ;; distributed integers.
- (random-source-make-reals rand-src))]
- [else
- (let ([rand-src (make-random-source)])
- ;; Try to make the random source truly random. How
- ;; this works depends on the specific implementation
- ;; of SRFI-27.
- (random-source-randomize! rand-src)
- (random-source-make-reals rand-src))])))
- (define generate-n-unique-integers
- (lambda* (n
- minimum
- maximum
- #:key (rng (make-random-integer-generator #:seed 12345)))
- (when (> n (- maximum minimum))
- (error
- (simple-format
- #f "range from ~a to ~a is too small for generating ~a unique integers"
- minimum maximum n)))
- (let ([gen-range (- maximum minimum)])
- ;; Need to shuffle, because set->list gives same result for
- ;; all sets which have the same entries, no matter in which
- ;; order the keys were added.
- (fisher-yates-shuffle
- (set->list
- (let iter ([gen-count° 0] [numbers° (make-set <)])
- (cond
- [(>= gen-count° n) numbers°]
- [else
- (let ([generated-num (rng gen-range)])
- (cond
- [(set-member? numbers° generated-num)
- (iter gen-count°
- numbers°)]
- [else
- (iter (+ gen-count° 1)
- (set-insert numbers° generated-num))]))])))
- #:rng rng))))
- (define generate-n-integers
- (lambda* (n
- minimum
- maximum
- #:key (rng (make-random-integer-generator #:seed 12345)))
- (let ([gen-range (- maximum minimum)])
- (let iter ([gen-count° 0] [numbers° '()])
- (cond
- [(>= gen-count° n) numbers°]
- [else
- (let ([generated-num (+ (rng gen-range) minimum)])
- (iter (+ gen-count° 1)
- (cons generated-num numbers°)))])))))
- (define scale-float
- (λ (num mininum maximum)
- (let ([scaling-factor (- maximum mininum)])
- (+ (* num scaling-factor) mininum))))
- (define generate-n-floats
- (lambda* (n
- minimum
- maximum
- #:key (rng (make-random-floats-generator #:seed 12345)))
- (let iter ([gen-count° 0] [numbers° '()])
- (cond
- [(>= gen-count° n) numbers°]
- [else
- (let ([generated-num (scale-float (rng) minimum maximum)])
- (iter (+ gen-count° 1)
- (cons generated-num numbers°)))]))))
- (define generate-random-list
- (lambda* (length
- event-limit-table
- #:key
- (rng (make-random-integer-generator #:seed 12345)))
- "Create a list of length LENGTH of randomly selected events
- from the given hash table EVENT-COUNTS."
- (when (> length (apply + (hash-table-values event-limit-table)))
- (error "invalid arguments: length too high"))
- (let* ([result-vector (make-vector length)]
- [count-events (hash-table-fold event-limit-table
- (λ (key val previous)
- (+ previous val))
- 0)]
- [random-indices (generate-n-unique-integers count-events
- 0
- count-events
- #:rng rng)])
- ;; Fill result vector for all events
- (let iter ([random-indices° random-indices]
- [event-limit-alist° (hash-table->alist event-limit-table)])
- (cond
- [(null? event-limit-alist°)
- (vector->list result-vector)]
- [else
- (let* ([event (car (first event-limit-alist°))]
- [count (cdr (first event-limit-alist°))])
- ;; (simple-format #t "filling result vector with event ~a count ~a\n" event count)
- ;; Fill result vector for a specific event.
- (let iter-single-event ([indices° (take random-indices° count)])
- ;; (simple-format #t "setting event ~a at indices ~a\n" event indices°)
- (unless (null? indices°)
- (vector-set! result-vector
- (first indices°)
- event)
- (iter-single-event (drop indices° 1))))
- (iter (drop random-indices° count)
- (drop event-limit-alist° 1)))])))))
- #;(define make-random-uniform-sum-distribution-generator
- (λ (#:key (seed 12345))
- "Uniform sum distribution, also known as Irwin–Hall distribution."
- (let ([rng (make-random-integer-generator #:seed seed)])
- (λ ()
- ))))
- #;(define make-random-normal-distribution-generator
- (λ (#:key seed)
- ...
- ))
- )
|