For Development HEAD DRAFTSearch (procedure/syntax/module):

12.20 data.random - ランダムデータの生成

Module: data.random

このモジュールは、特定のデータ型や、特定の値の分布を持つランダムなデータを 生成するジェネレータ、およびそういったジェネレータを作り出すジェネレータ構築器を 提供します。

このモジュールの一部の機能はSRFI-194になりましたが、 同SRFIでは他のSRFIとの一貫性から異なる名前/APIを採用しています (srfi.194 - ランダムデータジェネレータ (SRFI)参照)。

名前付けの規則:パラメータを受け取り、それにそったジェネレータを返す 手続きにはサフィックス$がついています (例: integer$)。 それ自体がジェネレータである手続きにはサフィックスがつきません (例: fixnums)。 コンビネータ、つまり複数のジェネレータを取ってジェネレータを返す手続きの名前は、 通常前置詞で終わります (例: list-of)。

乱数源

Parameter: random-data-random-source

{data.random} このパラメータの値はSRFI-27の乱数発生源でなければなりません (srfi.27 - ランダムビットのソース参照)。初期値はSRFI-27の default-random-sourceです。

このモジュールのユーティリティでジェネレータを作った場合、その作成時の パラメータの動的な値が捕獲され、ジェネレータはそれを使って乱数を生成します。 ジェネレータの作成後にこのパラメータの値を変えてもジェネレータの動作には影響しません。

註: 0.9.13まで、このモジュールで作られるジェネレータは乱数生成の度に現在の乱数源を 参照していました。これにより、一度構築した乱数生成のネットワークのふるまいを、 現在の乱数源をいじることで変えられますが、乱数発生の度に若干のオーバヘッドも生じます。 一般に、異なる乱数源を使いたければそれを現在の乱数源として新にジェネレータを 作成した方が安価でしょう。それに、現在のふるまいはSRFI-194と一貫性があります。

以下のふたつの手続きは現在の乱数源を置き換えるために提供されていましたが、 今では効果がありません。

random-data-seed          with-random-data-seed

プリミティブデータ型のジェネレータ

以下のジェネレータは特に断りが無い限り、一様分布するデータを生成します。

例の中では、生成された値を具体的に示すために gauche.generatorモジュールのgenerator->listを 使っています。ジェネレータを扱うユーティリティについては gauche.generator - ジェネレータを参照してください。

Function: integers$ size :optional (start 0)
Function: integers-between$ lower-bound upper-bound

{data.random} 正確な整数のジェネレータを作成します。 integer$が返すジェネレータは、 start 以上 start + size 未満の整数を一様に発生させます。 integers-between$はが返すジェネレータは、lower-bound以上、 upper-bound以下の整数を一様に発生させます。

;; サイコロ
(define dice (integers$ 6 1))

;; サイコロを10回振ってみる
(generator->list dice 10)
 ⇒ (6 6 2 4 2 5 5 1 2 2)
Function: fixnums$
Function: int8s$
Function: uint8s$
Function: int16s$
Function: uint16s$
Function: int32s$
Function: uint32s$
Function: int64s$
Function: uint64s$

{data.random} 固定範囲の一様整数ジェネレータを作って返します。 作られたジェネレータはそれぞれ、 fixnumおよび8/16/32/64ビットの符号つき/符号無し整数を生成します。

(generator->list (int8s$) 10)
 ⇒ (20 -101 50 -99 -111 -28 -19 -61 39 110)
Function: booleans$

{data.random} 真偽値(#f#t)を等確率で生成するジェネレータを作って返します。

(generator->list (booleans$) 10)
 ⇒ (#f #f #t #f #f #t #f #f #f #f)
Function: fixnums
Function: int8s
Function: uint8s
Function: int16s
Function: uint16s
Function: int32s
Function: uint32s
Function: int64s
Function: uint64s
Function: booleans

{data.random} これらはfixnum$などを使ってあらかじめ作られたジェネレータです。 簡便のために提供されています。ただ、乱数発生源はdefault-random-source に固定であることに注意してください。

Function: chars$ :optional char-set

{data.random} char-setにある文字を一様分布で生成するジェネレータを作ります。 char-setが省略された場合は#[A-Za-z0-9]が使われます。

(define alphanumeric-chars (chars$))

(generator->list alphanumeric-chars 10)
 ⇒ (#\f #\m #\3 #\S #\z #\m #\x #\S #\l #\y)
Function: reals$ :optional size start
Function: reals-between$ lower-bound upper-bound

{data.random} 与えられた範囲の実数値を一様に生成するジェネレータを返します。 reals$の返すジェネレータは、 start 以上 start + size 以下の実数値を生成します。 sizeのデフォルト値は1.0startのデフォルト値は0.0です。 reals-between$の返すジェネレータは、 lower-bound以上upper-bound以下の実数値を生成します。

(define uniform-100 (reals$ 100))

(generator->list uniform-100 10)
 ⇒ (81.67965004942268 81.84927577572596 53.02443813660833)

reals$の返すジェネレータは、integer$と違って 上限の値を生成し得ることに注意してください。限界値を除外したい場合は、 gfilter等を使ってその値を棄却します。

(define generate-from-0-below-1
  (gfilter (^r (not (= r 1.0))) (reals$ 1.0 0.0)))

また、浮動小数点数は与えられた実数範囲の中で一様に分布していないことに注意してください。 ある実数範囲から一様にサンプリングした場合、得られるほとんどの実数の指数部は、 範囲の上下限の指数と同じかそれに近いものになります。それが必要なものでしたら良いのですが、 有効な浮動小数点数から一様にサンプリングしたい場合は、下のfinite-flonums$ を見てください。

Function: finite-flonums$

可能な全ての有限の浮動小数点数から一様にサンプリングする浮動小数点数ジェネレータ を返します。これは実数を一様にサンプリングするのとは異なります。 浮動小数点数は実数空間で一様に分布していないからです。 これは、テスト用途でランダムな浮動小数点数を使いたい場合に便利です。 実数範囲で一様サンプリングすると、得られる数値の指数部は非常に偏ったものになるからです。

Function: complexes-rectangular$ re-lb re-ub im-lb im-ub
Function: complexes-polar$ [origin] mag-lb mag-ub :optional ang-lb ang-ub

複素数を一様に生成する新たなジェネレータを作って返します。 全ての*-lbおよび*-ub引数は実数でなければならず、*-ub*-lb以上でなければなりません。originは複素数です。

complexes-rectangular$が返すジェネレータは、 実部がre-lbre-ubの間にあり、 虚部がim-lbim-ubの間にある矩形領域中の複素数を生成します。 境界は含まれます。

complexes-rectangular$が返すジェネレータは、 originを中心とし、半径がmag-lbmag-ub、 切り取り角がang-lbang-ubの間にある部分環状領域の中にある 複素数を生成します。境界は含まれます。 originang-lbang-ubが 省略された場合は、それぞれ0+0i, 0, 2πが使われます。

Function: samples$ collection

{data.random} コレクションcollectionから毎回ランダムにひとつ要素を選んで返すジェネレータを 作成します。

下で説明するsamples-fromと混同しないようにしてください。samples-from は複数のジェネレータを組み合わせてサンプリングするものです。

(define coin-toss (samples$ '(head tail)))

(generator->list coin-toss 5)
 ⇒ (head tail tail head tail)
Function: regular-string$ regexp

{data.random} 与えられたregexpにマッチするランダムな文字列を生成し続けるジェネレータを 作って返します。regexpには条件付きパターン、lookahead/lookbehindアサーションを 含めないでください。

註: 生成される文字列の分布をどうすべきかというのは難しい問題です。 現在の実装は単純に、内部で正規表現からNFAを生成し、複数の選択肢がある場合は 等しい重みでランダムに選択していますが、それが目的(例えばテストデータの生成)に ふさわしいかどうかはまだわかりません。 現在の実装は暫定的なものと考えてください。

非一様分布

Function: reals-normal$ :optional mean deviation

{data.random} 期待値mean、標準偏差deviationの正規分布に従って実数値を生成する ジェネレータを作ります。省略時はmeanが0.0、deviationが 1.0になります。

Function: reals-exponential$ mean

{data.random} 期待値meanの指数分布に従って実数値を生成するジェネレータを作ります。

註: 確率密度関数 p(x) は(* (/ mean) (exp (- (/ x mean)))) です。 指数分布の定義では、期待値のかわりに、減衰パラメータ λ を使って確率密度関数を (* λ (exp (- (* x λ))))とする流儀もあります。 この場合、λ = 1/meanです。

Function: reals-power-law$ xmin power

{data.random} 冪乗則に従った確率で有限の正実数を生成するジェネレータを作って返します。 確率密度関数p(x)は(α-1)/xmin (x/xmin)^{-α}と表せます。ここでx ≧ xmin、α > 1 です。 power引数がαを指定します。

xminは正の実数、powerは1より大きい実数でなければなりません。

Function: integers-geometric$ p

{data.random} 成功確率p (0 ≦ p ≦ 1) である幾何分布に従って 非負整数値を生成するジェネレータを作ります。 期待値は1/p、分散は(1-p)/p^2になります。

Function: integers-poisson$ L

{data.random} 期待値Lのポアソン分布に従う非負整数値を生成するジェネレータを作ります。 分散もLになります。

複合データ型のジェネレータ

Function: samples-from generators

{data.random} ジェネレータの有限シーケンス (ここではgauche.sequenceがシーケンスとして 扱うもの) を取り、新たなジェネレータを返します。 返されたジェネレータは、値を必要とする度に、 入力となるジェネレータのどれかを等確率で選んで、その入力ジェネレータから値を取ります。

返されるジェネレータは、全ての入力ジェネレータが終端に達した時に終わりとなります。

(define g (samples-from (list uint8s (chars$ #[a-z]))))

(generator->list g 10)
 ⇒ (207 107 #\m #\f 199 #\o #\b 57 #\j #\e)

註: 固定した要素の集まりからサンプルするジェネレータを作るには、 上の方で説明したsamples$を使ってください。

Function: weighted-samples-from weight&gens

{data.random} 引数は、非負の実数値とジェネレータのペアのリストです。 実数値が「重み」、すなわちペアとなっているジェネレータが選ばれる相対確率を決定します。 重みの総和が1.0である必要はありません。

次の例では、uint8ジェネレータは文字ジェネレータより4倍頻繁に使われます。

(define g (weighted-samples-from
           `((4.0 . ,uint8s)
             (1.0 . ,(chars$)))))

(generator->list g 10)
 ⇒ (195 97 #\j #\W #\5 72 49 143 19 164)
Function: pairs-of car-gen cdr-gen

{data.random} ペアを生成するジェネレータを作ります。 各ペアのcarはジェネレータcar-gen、 cdrはジェネレータcdr-genによって生成されます。

(define g (pairs-of int8s booleans))

(generator->list g 10)
 ⇒ ((113 . #t) (101 . #f) (12 . #t) (68 . #f) (-55 . #f))
Function: tuples-of gen …

{data.random} リストを生成するジェネレータを作ります。 各リストのi番目の要素はi番目の引数のジェネレータによって生成されます。

(define g (tuples-of int8s booleans (char$)))

(generator->list g 3)
 ⇒ ((-43 #f #\8) (53 #f #\1) (-114 #f #\i))
Function: permutations-of seq

{data.random} シーケンスseqの要素をランダムに並べ替えたシーケンスを生成する ジェネレータを作ります。

seqの型は、ビルダーを持つシーケンスである必要があります (gauche.sequence - シーケンスフレームワーク参照)。生成されるオブジェクトは seqと同じ型になります。

(generator->list (permutations-of '(1 2 3)) 3)
 ⇒ ((1 2 3) (2 3 1) (3 2 1))

(generator->list (permutations-of "abc") 3)
 ⇒ ("cba" "cba" "cab")
Function: combinations-of size seq

{data.random} シーケンスseqからランダムにsize個の要素を取り出して 並べたシーケンスを生成するジェネレータを作ります。

seqの型は、ビルダーを持つシーケンスである必要があります (gauche.sequence - シーケンスフレームワーク参照)。生成されるオブジェクトは seqと同じ型になります。

(generator->list (combinations-of 2 '(a b c)) 5)
 ⇒ ((a c) (a b) (a c) (b a) (a c))

(generator->list (combinations-of 2 '#(a b c)) 5)
 ⇒ (#(a c) #(b c) #(c b) #(b a) #(b c))

以下の手続きは、省略可能なsizer引数を取ります。 sizer引数は非負整数か、非負整数を生成するジェネレータで、 その値(もしくは生成された値)が、最終的に生成されるデータの長さを決定します。

Gaucheの他のほとんどの手続きと違って、sizer引数は省略されない時は 最後の引数よりも前に来ます。これは統一性を損ないますが、 (lists-of 3 booleans) のように書ける、という誘惑に勝てませんでした。

sizer引数が省略された場合、パラメータdefault-sizerの値が 使われます。default-sizerのデフォルトは (integers-poisson$ 4)で作られるジェネレータです。

Function: lists-of item-gen
Function: lists-of sizer item-gen
Function: vectors-of item-gen
Function: vectors-of sizer item-gen
Function: strings-of
Function: strings-of item-gen
Function: strings-of sizer item-gen

{data.random} それぞれ、リスト、ベクタ、文字列を生成するジェネレータを作ります。 作られるデータの各要素はジェネレータitem-genから取られます。 各データの長さはsizerにより決定されます。

strings-ofの場合はitem-genも省略することができます。 その場合は、(chars$)で作られるジェネレータが使われます。

(generator->list (lists-of 3 uint8s) 4)
 ⇒ ((254 46 0) (77 158 46) (1 134 156) (74 5 110))

;; デフォルトのsizerを使う
(generator->list (lists-of uint8s) 4)
 ⇒ ((93 249) (131 97) (98 206 144 247 241) (126 156 31))

;; sizerにジェネレータを使う
(generator->list (strings-of (integers$ 8) (chars$)) 5)
 ⇒ ("dTJYVhu" "F" "PXkC" "w" "")
Function: sequences-of class item-gen
Function: sequences-of class sizer item-gen

{data.random} クラスclassのインスタンスであるシーケンスを生成するジェネレータを作ります。 シーケンスの要素はitem-genにより生成されます。 各シーケンスの長さはsizer引数 (省略時はdefault-sizerの値) によって決められます。sizerは非負整数か、非負整数を生成するジェネレータです。

class<sequence>のサブクラスであり、 ビルダーインタフェースを実装していなければなりません。

(generator->list (sequences-of <u8vector> 4 uint8s) 3)
 ⇒ (#u8(95 203 243 46) #u8(187 199 153 152) #u8(39 114 39 25))
Parameter: default-sizer

{data.random} lists-ofvectors-ofstrings-ofsizer引数が省略された場合に使われるsizerです。

値は、非負整数か、非負整数を生成するジェネレータでなければなりません。 デフォルトの値は(integers-poisson$ 4)です。



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT