Random Numbers
Julia'da rastgele sayı üretimi varsayılan olarak Xoshiro256++ algoritmasını kullanır ve her Task
için bir durum içerir. Diğer RNG türleri, AbstractRNG
türünden miras alarak entegre edilebilir; bu türler daha sonra birden fazla rastgele sayı akışı elde etmek için kullanılabilir.
Random
paketinden dışa aktarılan PRNG'ler (sahte rastgele sayı üreteçleri) şunlardır:
TaskLocalRNG
: şu anda aktif olan Görev-eşel (Task-local) akışının kullanımını temsil eden bir token, ana görevden belirleyici bir şekilde tohumlanmış veya program başlangıcındaRandomDevice
(sistem rastgeleliği ile) tarafından tohumlanmıştır.Xoshiro
: Xoshiro256++ algoritmasını kullanarak küçük bir durum vektörü ile yüksek performanslı ve yüksek kaliteli rastgele sayı akışları üretir.RandomDevice
: OS tarafından sağlanan entropi için. Bu, kriptografik olarak güvenli rastgele sayılar (CS(P)RNG) için kullanılabilir.MersenneTwister
: eski Julia sürümlerinde varsayılan olan, alternatif bir yüksek kaliteli PRNG'dir ve oldukça hızlıdır, ancak durum vektörünü depolamak ve rastgele bir dizi oluşturmak için çok daha fazla alan gerektirir.
Çoğu rastgele üretimle ilgili fonksiyon, ilk argüman olarak isteğe bağlı bir AbstractRNG
nesnesi alır. Bazıları ayrıca rastgele değerler dizileri oluşturmak için boyut spesifikasyonları dims...
(bir demet olarak da verilebilir) alır. Çok iş parçacıklı bir programda, genellikle iş parçacıkları veya görevler için farklı RNG nesneleri kullanmalısınız, böylece iş parçacığı güvenliğini sağlarsınız. Ancak, varsayılan RNG, Julia 1.3 itibarıyla iş parçacığı güvenlidir (1.6 sürümüne kadar iş parçacığı başına RNG kullanarak ve sonrasında görev başına RNG kullanarak).
Verilen RNG'ler aşağıdaki türlerde uniform rastgele sayılar üretebilir: Float16
, Float32
, Float64
, BigFloat
, Bool
, Int8
, UInt8
, Int16
, UInt16
, Int32
, UInt32
, Int64
, UInt64
, Int128
, UInt128
, BigInt
(veya bu türlerin karmaşık sayıları). Rastgele kayan nokta sayıları $[0, 1)$ aralığında uniform olarak üretilir. BigInt
sınırsız tam sayıları temsil ettiğinden, aralığın belirtilmesi gerekir (örneğin rand(big.(1:6))
).
Ayrıca, bazı AbstractFloat
ve Complex
türleri için normal ve üstel dağılımlar uygulanmıştır, ayrıntılar için randn
ve randexp
'ya bakın.
Rastgele sayılar üretmek için diğer dağılımlardan, Distributions.jl paketine bakın.
Rastgele sayıların üretilme şekli bir uygulama detayı olarak kabul edildiğinden, hata düzeltmeleri ve hız iyileştirmeleri, bir sürüm değişikliğinden sonra üretilen sayı akışını değiştirebilir. Birim testleri sırasında belirli bir tohum veya üretilen sayı akışına güvenmek bu nedenle önerilmez - bunun yerine söz konusu yöntemlerin özelliklerini test etmeyi düşünün.
Random numbers module
Random.Random
— ModuleRastgele
Rastgele sayılar üretme desteği. rand
, randn
, AbstractRNG
, MersenneTwister
ve RandomDevice
sağlar.
Random generation functions
Base.rand
— Functionrand([rng=default_rng()], [S], [dims...])
S
tarafından belirtilen değerler kümesinden rastgele bir öğe veya rastgele öğeler dizisi seçin; S
şunlar olabilir:
indekslenebilir bir koleksiyon (örneğin
1:9
veya('x', "y", :z)
)bir
AbstractDict
veyaAbstractSet
nesnesibir dize (karakterler koleksiyonu olarak kabul edilir), veya
aşağıdaki listeden bir tür, belirtilen değerler kümesine karşılık gelir
- somut tam sayı türleri
typemin(S):typemax(S)
aralığından örnek alır (desteklenmeyenBigInt
hariç) - somut kayan nokta türleri
[0, 1)
aralığından örnek alır Complex{T}
türündeki somut karmaşık türler,T
örneklenebilir bir türse,T
'ye karşılık gelen değerler kümesinden bağımsız olarak gerçek ve hayali bileşenlerini alır, ancakT
örneklenebilir değilse desteklenmez.- tüm
<:AbstractChar
türleri geçerli Unicode skalarları kümesinden örnek alır - kullanıcı tanımlı bir tür ve değerler kümesi; uygulama rehberi için lütfen Random API'ye Bağlanma bölümüne bakın
- bilinen boyutta bir demet türü ve
S
'nin her parametresi kendisi örneklenebilir bir türse;S
türünde bir değer döndürün.Tuple{Vararg{T}}
(bilinmeyen boyut) veTuple{1:2}
(bir değerle parametrelenmiş) gibi demet türlerinin desteklenmediğini unutmayın. Pair
türü, örneğinPair{X, Y}
böylecerand
içinX
veY
tanımlıysa, rastgele çiftler üretilir.
- somut tam sayı türleri
S
varsayılan olarak Float64
olarak ayarlanmıştır. Opsiyonel rng
dışında yalnızca bir argüman geçirildiğinde ve bu bir Tuple
olduğunda, değerler koleksiyonu (S
) olarak yorumlanır ve dims
olarak değil.
Normal dağılımlı sayılar için randn
ve yerinde eşdeğerleri için rand!
ve randn!
bölümlerine de bakın.
S
'nin bir demet olarak desteklenmesi en az Julia 1.1 gerektirir.
S
'nin bir Tuple
türü olarak desteklenmesi en az Julia 1.11 gerektirir.
Örnekler
julia> rand(Int, 2)
2-element Array{Int64,1}:
1339893410598768192
1575814717733606317
julia> using Random
julia> rand(Xoshiro(0), Dict(1=>2, 3=>4))
3 => 4
julia> rand((2, 3))
3
julia> rand(Float64, (2, 3))
2×3 Array{Float64,2}:
0.999717 0.0143835 0.540787
0.696556 0.783855 0.938235
rand(rng, s::Union{AbstractDict,AbstractSet})
'nin karmaşıklığı s
'nin uzunluğuna bağlı olarak lineerdir, eğer sabit karmaşıklıkta optimize edilmiş bir yöntem mevcut değilse, bu durum Dict
, Set
ve yoğun BitSet
'ler için geçerlidir. Birkaç çağrıdan fazlası için, bunun yerine rand(rng, collect(s))
kullanın veya uygun olduğunda rand(rng, Dict(s))
veya rand(rng, Set(s))
kullanın.
Random.rand!
— Functionrand!([rng=default_rng()], A, [S=eltype(A)])
Diziyi A
'yı rastgele değerlerle doldurur. Eğer S
belirtilmişse (S
bir tür veya bir koleksiyon olabilir, ayrıntılar için bkz. rand
), değerler S
'den rastgele seçilir. Bu, copyto!(A, rand(rng, S, size(A)))
ile eşdeğerdir, ancak yeni bir dizi ayırmadan.
Örnekler
julia> rand!(Xoshiro(123), zeros(5))
5-element Vector{Float64}:
0.521213795535383
0.5868067574533484
0.8908786980927811
0.19090669902576285
0.5256623915420473
Random.bitrand
— Functionbitrand([rng=default_rng()], [dims...])
Rastgele boolean değerlerden oluşan bir BitArray
oluşturur.
Örnekler
julia> bitrand(Xoshiro(123), 10)
10-element BitVector:
0
1
0
1
0
1
0
0
1
1
Base.randn
— Functionrandn([rng=default_rng()], [T=Float64], [dims...])
0 ortalama ve 1 standart sapmaya sahip T
türünde normal dağılımlı rastgele bir sayı üretir. Opsiyonel dims
argüman(lar)ı verildiğinde, bu türden sayıların dims
boyutunda bir dizisini üretir. Julia'nın standart kütüphanesi, rand
uygulayan herhangi bir kayan nokta türü için randn
'ı destekler; örneğin, Base
türleri Float16
, Float32
, Float64
(varsayılan) ve BigFloat
ile birlikte bunların Complex
karşıtları.
(T
karmaşık olduğunda, değerler, varyansı 1 olan dairesel simetrik karmaşık normal dağılımdan çekilir; bu, reel ve sanal kısımların sıfır ortalama ve 1/2
varyansa sahip bağımsız normal dağılıma sahip olduğu anlamına gelir).
Yerinde işlem yapmak için randn!
ile de bakabilirsiniz.
Örnekler
Tek bir rastgele sayı üretme (varsayılan Float64
türü ile):
julia> randn()
-0.942481877315864
Normal rastgele sayıların bir matrisini üretme (varsayılan Float64
türü ile):
julia> randn(2,3)
2×3 Matrix{Float64}:
1.18786 -0.678616 1.49463
-0.342792 -0.134299 -1.45005
Kullanıcı tanımlı bir tohum ile rastgele sayı üreteci rng
'yi ayarlama (tekrarlanabilir sayılar için) ve bunu kullanarak rastgele bir Float32
sayısı veya ComplexF32
rastgele sayılardan oluşan bir matris üretme:
julia> using Random
julia> rng = Xoshiro(123);
julia> randn(rng, Float32)
-0.6457307f0
julia> randn(rng, ComplexF32, (2, 3))
2×3 Matrix{ComplexF32}:
-1.03467-1.14806im 0.693657+0.056538im 0.291442+0.419454im
-0.153912+0.34807im 1.0954-0.948661im -0.543347-0.0538589im
Random.randn!
— Functionrandn!([rng=default_rng()], A::AbstractArray) -> A
Diziyi A
'yı normal dağılıma sahip (ortalama 0, standart sapma 1) rastgele sayılarla doldurur. Ayrıca rand
fonksiyonuna da bakın.
Örnekler
julia> randn!(Xoshiro(123), zeros(5))
5-element Vector{Float64}:
-0.6457306721039767
-1.4632513788889214
-1.6236037455860806
-0.21766510678354617
0.4922456865251828
Random.randexp
— Functionrandexp([rng=default_rng()], [T=Float64], [dims...])
1 ölçekli üstel dağılıma göre T
türünde rastgele bir sayı üretir. İsteğe bağlı olarak, bu türde rastgele sayıların bir dizisini de üretebilir. Base
modülü şu türler için bir uygulama sağlar: Float16
, Float32
ve Float64
(varsayılan).
Örnekler
julia> rng = Xoshiro(123);
julia> randexp(rng, Float32)
1.1757717f0
julia> randexp(rng, 3, 3)
3×3 Matrix{Float64}:
1.37766 0.456653 0.236418
3.40007 0.229917 0.0684921
0.48096 0.577481 0.71835
Random.randexp!
— Functionrandexp!([rng=default_rng()], A::AbstractArray) -> A
Diziyi A
'yı üstel dağılıma (ölçek 1 ile) göre rastgele sayılarla doldurun.
Örnekler
julia> randexp!(Xoshiro(123), zeros(5))
5-element Vector{Float64}:
1.1757716836348473
1.758884569451514
1.0083623637301151
0.3510644315565272
0.6348266443720407
Random.randstring
— Functionrandstring([rng=default_rng()], [chars], [len=8])
len
uzunluğunda, varsayılan olarak büyük ve küçük harfler ile 0-9 rakamlarından oluşan chars
karakter setinden oluşan rastgele bir dize oluşturur. İsteğe bağlı rng
argümanı, bir rastgele sayı üreteci belirtir, bkz. Rastgele Sayılar.
Örnekler
julia> Random.seed!(3); randstring()
"Lxz5hUwn"
julia> randstring(Xoshiro(3), 'a':'z', 6)
"iyzcsm"
julia> randstring("ACGT")
"TGCTCCTC"
chars
, rand
karakterleri rastgele seçebiliyorsa, Char
veya UInt8
türünde herhangi bir karakter koleksiyonu olabilir (daha verimli).
Subsequences, permutations and shuffling
Random.randsubseq
— Functionrandsubseq([rng=default_rng(),] A, p) -> Vector
Verilen dizi A
'nın rastgele bir alt dizisini içeren bir vektör döndürür; burada A
'nın her bir elemanı bağımsız olasılık p
ile (sırasıyla) dahil edilir. (Karmaşıklık p*length(A)
cinsindendir, bu nedenle bu fonksiyon p
küçük ve A
büyük olsa bile etkilidir.) Teknik olarak, bu süreç A
'nın "Bernoulli örneklemesi" olarak bilinir.
Örnekler
julia> randsubseq(Xoshiro(123), 1:8, 0.3)
2-element Vector{Int64}:
4
7
Random.randsubseq!
— Functionrandsubseq!([rng=default_rng(),] S, A, p)
randsubseq
gibi, ancak sonuçlar S
içinde saklanır (gerekirse boyutu değiştirilir).
Örnekler
julia> S = Int64[];
julia> randsubseq!(Xoshiro(123), S, 1:8, 0.3)
2-element Vector{Int64}:
4
7
julia> S
2-element Vector{Int64}:
4
7
Random.randperm
— Functionrandperm([rng=default_rng(),] n::Integer)
n
uzunluğunda rastgele bir permütasyon oluşturur. İsteğe bağlı rng
argümanı bir rastgele sayı üreteci belirtir (bkz. Rastgele Sayılar). Sonucun eleman tipi, n
'nin tipiyle aynıdır.
Rastgele bir vektörü permüte etmek için shuffle
veya shuffle!
fonksiyonlarına bakın.
Julia 1.1'de randperm
, eltype(v) == typeof(n)
olan bir vektör v
dönerken, Julia 1.0'da eltype(v) == Int
döner.
Örnekler
julia> randperm(Xoshiro(123), 4)
4-element Vector{Int64}:
1
4
2
3
Random.randperm!
— Functionrandperm!([rng=default_rng(),] A::Array{<:Integer})
A
içinde length(A)
uzunluğunda rastgele bir permütasyon oluşturur. İsteğe bağlı rng
argümanı, bir rastgele sayı üreteci belirtir (bkz. Rastgele Sayılar). Rastgele bir vektörü permüte etmek için shuffle
veya shuffle!
fonksiyonlarına bakın.
Örnekler
julia> randperm!(Xoshiro(123), Vector{Int}(undef, 4))
4-element Vector{Int64}:
1
4
2
3
Random.randcycle
— Functionrandcycle([rng=default_rng(),] n::Integer)
n
uzunluğunda rastgele bir döngüsel permütasyon oluşturur. İsteğe bağlı rng
argümanı, Rastgele Sayılar bölümünde belirtilen bir rastgele sayı üreteciyi tanımlar. Sonucun eleman tipi, n
'nin tipiyle aynıdır.
Burada "döngüsel permütasyon", tüm elemanların tek bir döngü içinde yer aldığı anlamına gelir. Eğer n > 0
ise, $(n-1)!$ olası döngüsel permütasyon vardır ve bunlar eşit olarak örneklenir. Eğer n == 0
ise, randcycle
boş bir vektör döner.
randcycle!
bu işlevin yerinde bir varyantıdır.
Julia 1.1 ve üzeri sürümlerde, randcycle
eltype(v) == typeof(n)
olan bir vektör v
dönerken, Julia 1.0'da eltype(v) == Int
'dir.
Örnekler
julia> randcycle(Xoshiro(123), 6)
6-element Vector{Int64}:
5
4
2
6
3
1
Random.randcycle!
— Functionrandcycle!([rng=default_rng(),] A::Array{<:Integer})
A
içinde uzunluğu n = length(A)
olan rastgele bir döngüsel permütasyon oluşturur. İsteğe bağlı rng
argümanı, Rastgele Sayılar bölümünde belirtilen bir rastgele sayı üreteciyi tanımlar.
Burada "döngüsel permütasyon", tüm elemanların tek bir döngü içinde yer aldığı anlamına gelir. Eğer A
boş değilse (n > 0
), $(n-1)!$ olası döngüsel permütasyon vardır ve bunlar eşit olarak örneklenir. Eğer A
boşsa, randcycle!
onu değiştirmeden bırakır.
randcycle
bu işlevin yeni bir vektör ayıran bir varyantıdır.
Örnekler
julia> randcycle!(Xoshiro(123), Vector{Int}(undef, 6))
6-element Vector{Int64}:
5
4
2
6
3
1
Random.shuffle
— Functionshuffle([rng=default_rng(),] v::AbstractArray)
v
'nin rastgele bir şekilde permütasyona uğramış bir kopyasını döndürür. İsteğe bağlı rng
argümanı, bir rastgele sayı üreteci belirtir (bkz. Rastgele Sayılar). v
'yi yerinde permütasyona uğratmak için shuffle!
fonksiyonuna bakın. Rastgele permütasyona uğramış indeksler elde etmek için randperm
fonksiyonuna bakın.
Örnekler
julia> shuffle(Xoshiro(123), Vector(1:10))
10-element Vector{Int64}:
5
4
2
3
6
10
8
1
9
7
Random.shuffle!
— Functionshuffle!([rng=default_rng(),] v::AbstractArray)
Yerinde versiyonu shuffle
: v
'yi yerinde rastgele permüte eder, isteğe bağlı olarak rastgele sayı üreteci rng
sağlanabilir.
Örnekler
julia> shuffle!(Xoshiro(123), Vector(1:10))
10-element Vector{Int64}:
5
4
2
3
6
10
8
1
9
7
Generators (creation and seeding)
Random.default_rng
— FunctionRandom.default_rng() -> rng
Varsayılan küresel rastgele sayı üreteci (RNG) döndürülür; bu, açık bir RNG sağlanmadığında rand
ile ilgili işlevler tarafından kullanılır.
Random
modülü yüklendiğinde, varsayılan RNG rastgele bir şekilde tohumlanır; bu, her yeni julia oturumu başlatıldığında, rand()
'ın ilk çağrısının farklı bir sonuç üretmesi anlamına gelir, aksi takdirde seed!(seed)
çağrılmadıkça.
Thread güvenlidir: farklı thread'ler, default_rng()
üzerinde rand
ile ilgili işlevleri güvenli bir şekilde eşzamanlı olarak çağırabilir, örneğin rand(default_rng())
.
Varsayılan RNG'nin türü bir uygulama ayrıntısıdır. Farklı Julia sürümleri arasında, varsayılan RNG'nin her zaman aynı türde olmasını veya belirli bir tohum için aynı rastgele sayı akışını üretmesini beklememelisiniz.
Bu işlev Julia 1.3'te tanıtılmıştır.
Random.seed!
— Functionseed!([rng=default_rng()], seed) -> rng
seed!([rng=default_rng()]) -> rng
Rastgele sayı üreteciyi yeniden tohumlayın: rng
, yalnızca bir seed
sağlandığında yeniden üretilebilir bir sayı dizisi verecektir. Bazı RNG'ler, RandomDevice
gibi, bir tohum kabul etmez. seed!
çağrısından sonra, rng
, aynı tohumla başlatılmış yeni bir nesne ile eşdeğerdir. Kabul edilen tohumların türleri rng
türüne bağlıdır, ancak genel olarak, tam sayı tohumları çalışmalıdır.
Eğer rng
belirtilmemişse, paylaşılan görev yerel üretecin durumunu tohumlamayı varsayılan olarak alır.
Örnekler
julia> Random.seed!(1234);
julia> x1 = rand(2)
2-element Vector{Float64}:
0.32597672886359486
0.5490511363155669
julia> Random.seed!(1234);
julia> x2 = rand(2)
2-element Vector{Float64}:
0.32597672886359486
0.5490511363155669
julia> x1 == x2
true
julia> rng = Xoshiro(1234); rand(rng, 2) == x1
true
julia> Xoshiro(1) == Random.seed!(rng, 1)
true
julia> rand(Random.seed!(rng), Bool) # yeniden üretilebilir değil
true
julia> rand(Random.seed!(rng), Bool) # yeniden üretilebilir değil
false
julia> rand(Xoshiro(), Bool) # yeniden üretilebilir değil
true
Random.AbstractRNG
— TypeAbstractRNG
MersenneTwister
ve RandomDevice
gibi rastgele sayı üreteçleri için süpertip.
Random.TaskLocalRNG
— TypeTaskLocalRNG
TaskLocalRNG
, görevi için yerel olan bir duruma sahiptir, ipliği için değil. Görev oluşturulurken, ana görevin durumundan tohumlanır, ancak ana görevin RNG'sinin durumunu ilerletmeden.
Bir avantaj olarak, TaskLocalRNG
oldukça hızlıdır ve yarış koşulları hariç, zamanlayıcı kararlarından bağımsız olarak yeniden üretilebilir çok iş parçacıklı simülasyonlara izin verir. Görev oluşturma kararlarında iş parçacığı sayısı kullanılmadığı sürece, simülasyon sonuçları mevcut iş parçacığı / CPU sayısından da bağımsızdır. Rastgele akış, donanım ayrıntılarına bağlı olmamalıdır, sonlandırma ve muhtemelen kelime boyutu hariç.
current_task()
tarafından döndürülen görevden başka bir görevin RNG'sini kullanmak veya tohumlamak tanımsız bir davranıştır: çoğu zaman çalışır ve bazen sessizce başarısız olabilir.
TaskLocalRNG()
'yi seed!
ile tohumlarken, geçirilen tohum, varsa, herhangi bir tam sayı olabilir.
Negatif bir tam sayı tohumu ile TaskLocalRNG()
'yi tohumlamak en az Julia 1.11 gerektirir.
Görev oluşturma, Julia 1.10 itibarıyla ana görevin RNG durumunu ilerletmez.
Random.Xoshiro
— TypeXoshiro(seed::Union{Integer, AbstractString})
Xoshiro()
Xoshiro256++ hızlı bir sahte rastgele sayı üreteci olup, David Blackman ve Sebastiano Vigna tarafından "Scrambled Linear Pseudorandom Number Generators", ACM Trans. Math. Softw., 2021'de tanımlanmıştır. Referans uygulaması https://prng.di.unimi.it adresinde mevcuttur.
Yüksek hızın yanı sıra, Xoshiro'nun küçük bir bellek ayak izi vardır, bu da onu birçok farklı rastgele durumun uzun süre tutulması gereken uygulamalar için uygun hale getirir.
Julia'nın Xoshiro uygulaması, ana kaynaktan yeni sanal PRNG'ler tohumlayan bir toplu üretim moduna sahiptir ve SIMD kullanarak paralel olarak üretim yapar (yani, toplu akış birden fazla iç içe geçmiş xoshiro örneğinden oluşur). Sanal PRNG'ler, toplu isteğin karşılandığı anda atılır (ve yığın tahsisatına neden olmamalıdır).
Eğer bir tohum sağlanmazsa, rastgele üretilmiş bir tohum oluşturulur (sistemden entropi kullanılarak). Zaten mevcut bir Xoshiro
nesnesini yeniden tohumlamak için seed!
fonksiyonuna bakın.
Negatif bir tamsayı tohumunun geçmesi en az Julia 1.11 gerektirir.
Örnekler
julia> using Random
julia> rng = Xoshiro(1234);
julia> x1 = rand(rng, 2)
2-element Vector{Float64}:
0.32597672886359486
0.5490511363155669
julia> rng = Xoshiro(1234);
julia> x2 = rand(rng, 2)
2-element Vector{Float64}:
0.32597672886359486
0.5490511363155669
julia> x1 == x2
true
Random.MersenneTwister
— TypeMersenneTwister(seed)
MersenneTwister()
Bir MersenneTwister
RNG nesnesi oluşturun. Farklı RNG nesneleri kendi tohumlarına sahip olabilir, bu da farklı rastgele sayı akışları oluşturmak için yararlı olabilir. seed
bir tamsayı, bir dize veya UInt32
tamsayılarının bir vektörü olabilir. Hiçbir tohum sağlanmazsa, rastgele üretilmiş bir tohum oluşturulur (sistemden entropi kullanılarak). Zaten mevcut bir MersenneTwister
nesnesinin yeniden tohumlanması için seed!
fonksiyonuna bakın.
Negatif bir tamsayı tohumunun geçmesi en az Julia 1.11 gerektirir.
Örnekler
julia> rng = MersenneTwister(123);
julia> x1 = rand(rng, 2)
2-element Vector{Float64}:
0.37453777969575874
0.8735343642013971
julia> x2 = rand(MersenneTwister(123), 2)
2-element Vector{Float64}:
0.37453777969575874
0.8735343642013971
julia> x1 == x2
true
Random.RandomDevice
— TypeRandomDevice()
Bir RandomDevice
RNG nesnesi oluşturur. İki böyle nesne her zaman farklı rastgele sayı akışları üretecektir. Entropi işletim sisteminden elde edilir.
Hooking into the Random
API
Random
işlevselliğini genişletmenin iki çoğunlukla ortogonal yolu vardır:
- özel türlerin rastgele değerlerini oluşturma
- yeni jeneratörler oluşturma
The API for 1) is quite functional, but is relatively recent so it may still have to evolve in subsequent releases of the Random
module. For example, it's typically sufficient to implement one rand
method in order to have all other usual methods work automatically.
The API for 2) is still rudimentary, and may require more work than strictly necessary from the implementor, in order to support usual types of generated values.
Generating random values of custom types
Rastgele değerler üretmek bazı dağılımlar için çeşitli ticaret dengeleri içerebilir. Önceden hesaplanmış değerler, örneğin, ayrık dağılımlar için bir alias table veya tek değişkenli dağılımlar için “squeezing” functions gibi değerler, örnekleme hızını önemli ölçüde artırabilir. Önceden ne kadar bilginin hesaplanması gerektiği, bir dağılımdan çekmeyi planladığımız değerlerin sayısına bağlı olabilir. Ayrıca, bazı rastgele sayı üreteçleri, çeşitli algoritmaların faydalanmak isteyebileceği belirli özelliklere sahip olabilir.
Random
modülü, bu sorunları ele alabilecek rastgele değerler elde etmek için özelleştirilebilir bir çerçeve tanımlar. rand
'in her çağrısı, yukarıdaki ticaret dengeleri göz önünde bulundurularak özelleştirilebilen bir örnekleyici oluşturur; bu, Sampler
'a yöntemler ekleyerek yapılır ve bu yöntemler, rastgele sayı üreteci, dağılımı tanımlayan nesne ve tekrar sayısı için bir öneri üzerinde dağıtım yapabilir. Şu anda, sonuncusu için Val{1}
(tek bir örnek için) ve Val{Inf}
(keyfi bir sayı için) kullanılmakta olup, Random.Repetition
her ikisi için de bir takma addır.
Sampler
tarafından döndürülen nesne, rastgele değerleri üretmek için kullanılır. Örnekleme yapılabilen bir değer X
için rastgele üretim arayüzünü uygularken, uygulayıcı aşağıdaki yöntemi tanımlamalıdır.
rand(rng, sampler)
Sampler(rng, X, repetition)
tarafından döndürülen belirli sampler
için.
Samplerlere rand(rng, sampler)
uygulayan rastgele değerler olarak tanımlanabilir, ancak çoğu uygulama için aşağıdaki önceden tanımlanmış samplerlere yeterli olabilir:
SamplerType{T}()
türündenT
'den örnekler çizen örnekleyiciler uygulamak için kullanılabilir (örneğin,rand(Int)
). Bu, türler içinSampler
tarafından döndürülen varsayılan değerdir.SamplerTrivial(self)
basit bir sarmalayıcıdır ve[]
ile erişilebilir. Önceden hesaplanmış bilgiye ihtiyaç duyulmadığında (örneğin,rand(1:3)
) önerilen örnekleyicidir ve değerler içinSampler
tarafından döndürülen varsayılandır.SamplerSimple(self, data)
ayrıca,Sampler
'ın özel bir yönteminde hesaplanması gereken rastgele önceden hesaplanmış değerleri depolamak için kullanılabilecek ekdata
alanını içerir.
Herhangi birinin örneklerini sağlıyoruz. Burada algoritma seçimimizin RNG'den bağımsız olduğunu varsayıyoruz, bu nedenle imzalarımızda AbstractRNG
kullanıyoruz.
Random.Sampler
— TypeSampler(rng, x, repetition = Val(Inf))
rng
için x
'den rastgele değerler üretmek için kullanılabilecek bir örnekleyici nesnesi döndürür.
sp = Sampler(rng, x, repetition)
olduğunda, rastgele değerler çekmek için rand(rng, sp)
kullanılacak ve buna göre tanımlanmalıdır.
repetition
Val(1)
veya Val(Inf)
olabilir ve uygulanabilir olduğunda ön hesaplama miktarını belirlemek için bir öneri olarak kullanılmalıdır.
Random.SamplerType
ve Random.SamplerTrivial
varsayılan geri dönüşlerdir tipler ve değerler için, sırasıyla. Random.SamplerSimple
yalnızca bu amaç için ekstra türler tanımlamadan önceden hesaplanmış değerleri saklamak için kullanılabilir.
Random.SamplerType
— TypeSamplerType{T}()
Türler için bir örnekleyici, başka hiçbir bilgi içermiyor. Türlerle çağrıldığında Sampler
için varsayılan geri dönüş.
Random.SamplerTrivial
— TypeSamplerTrivial(x)
Verilen x
değerini saran bir örnekleyici oluşturur. Bu, değerler için varsayılan geri dönüş yoludur. Bu örnekleyicinin eltype
'ı eltype(x)
ile eşittir.
Tavsiye edilen kullanım durumu, önceden hesaplanmış veriler olmadan değerlerden örneklemektir.
Random.SamplerSimple
— TypeSamplerSimple(x, data)
Verilen değer x
ve data
ile sarmalayan bir örnekleyici oluşturun. Bu örnekleyicinin eltype
'ı eltype(x)
ile eşittir.
Tavsiye edilen kullanım durumu, önceden hesaplanmış verilerle değerlerden örneklemektir.
Önceden hesaplamayı değerleri gerçekten üretmekten ayırmak, API'nin bir parçasıdır ve kullanıcıya da açıktır. Örneğin, rand(rng, 1:20)
'nin bir döngüde tekrar tekrar çağrılması gerektiğini varsayalım: bu ayrımın avantajlarından yararlanmanın yolu aşağıdaki gibidir:
rng = Xoshiro()
sp = Random.Sampler(rng, 1:20) # or Random.Sampler(Xoshiro, 1:20)
for x in X
n = rand(rng, sp) # similar to n = rand(rng, 1:20)
# use n
end
Bu, standart kütüphanede de kullanılan mekanizmadır; örneğin, rastgele dizi oluşturmanın varsayılan uygulaması (örneğin rand(1:20, 10)
gibi).
Generating values from a type
Verilen bir T
türü için, rand(T)
tanımlıysa, T
türünde bir nesne üretileceği varsayılmaktadır. SamplerType
, türler için varsayılan örnekleyicidir. T
türündeki değerlerin rastgele üretilmesini tanımlamak için, rand(rng::AbstractRNG, ::Random.SamplerType{T})
yöntemi tanımlanmalı ve rand(rng, T)
'nin beklediği değerleri döndürmelidir.
Aşağıdaki örneği ele alalım: 1
ile n
arasında numaralandırılmış, n
sayıda kenarı olan bir Die
türü uyguluyoruz. rand(Die)
'nin en az 4 ve en fazla 20 kenara sahip rastgele bir Die
üretmesini istiyoruz.
struct Die
nsides::Int # number of sides
end
Random.rand(rng::AbstractRNG, ::Random.SamplerType{Die}) = Die(rand(rng, 4:20))
# output
Die
için skalar ve dizi yöntemleri artık beklenildiği gibi çalışıyor:
julia> rand(Die)
Die(5)
julia> rand(Xoshiro(0), Die)
Die(10)
julia> rand(Die, 3)
3-element Vector{Die}:
Die(9)
Die(15)
Die(14)
julia> a = Vector{Die}(undef, 3); rand!(a)
3-element Vector{Die}:
Die(19)
Die(7)
Die(17)
A simple sampler without pre-computed data
Burada bir koleksiyon için bir örnekleyici tanımlıyoruz. Önceden hesaplanmış verilere ihtiyaç yoksa, aslında değerler için varsayılan geri dönüş olan SamplerTrivial
örnekleyicisi ile uygulanabilir.
Rastgele nesne üretimini S
türündeki nesnelerden tanımlamak için aşağıdaki yöntem tanımlanmalıdır: rand(rng::AbstractRNG, sp::Random.SamplerTrivial{S})
. Burada, sp
basitçe S
türündeki bir nesneyi sarmalar ve bu nesneye sp[]
ile erişilebilir. Die
örneğini devam ettirerek, şimdi rand(d::Die)
tanımlamak istiyoruz; bu, d
'nin bir yüzüne karşılık gelen bir Int
üretmelidir:
julia> Random.rand(rng::AbstractRNG, d::Random.SamplerTrivial{Die}) = rand(rng, 1:d[].nsides);
julia> rand(Die(4))
1
julia> rand(Die(4), 3)
3-element Vector{Any}:
2
3
3
Verilen bir koleksiyon türü S
için, rand(::S)
tanımlıysa, eltype(S)
türünde bir nesne üretileceği varsayılmaktadır. Son örnekte, bir Vector{Any}
üretilmiştir; bunun nedeni eltype(Die) == Any
olmasıdır. Çözüm, Base.eltype(::Type{Die}) = Int
tanımlamaktır.
Generating values for an AbstractFloat
type
AbstractFloat
türleri özel durumlar olarak ele alınır, çünkü varsayılan olarak rastgele değerler tüm tür alanında üretilmez, bunun yerine [0,1)
aralığında üretilir. Aşağıdaki yöntem T <: AbstractFloat
için uygulanmalıdır: Random.rand(::AbstractRNG, ::Random.SamplerTrivial{Random.CloseOpen01{T}})
An optimized sampler with pre-computed data
Bir ayrık dağılımı düşünün; burada 1:n
sayıları, toplamı bir olan belirli olasılıklarla çekilir. Bu dağılımdan birçok değer gerektiğinde, en hızlı yöntem alias table kullanmaktır. Böyle bir tablo oluşturma algoritmasını burada sağlamıyoruz, ancak bunun yerine make_alias_table(probabilities)
fonksiyonunun mevcut olduğunu varsayalım ve draw_number(rng, alias_table)
fonksiyonu kullanılarak ondan rastgele bir sayı çekilebilir.
Dağılımın şu şekilde tanımlandığını varsayalım:
struct DiscreteDistribution{V <: AbstractVector}
probabilities::V
end
ve ve her zaman bir takma ad tablosu oluşturmak istediğimizi, gereken değer sayısından bağımsız olarak (bunu aşağıda özelleştirmeyi öğreniyoruz). Yöntemler
Random.eltype(::Type{<:DiscreteDistribution}) = Int
function Random.Sampler(::Type{<:AbstractRNG}, distribution::DiscreteDistribution, ::Repetition)
SamplerSimple(distribution, make_alias_table(distribution.probabilities))
end
önceden hesaplanmış verilerle bir örnekleyici döndürmek için tanımlanmalıdır, o zaman
function rand(rng::AbstractRNG, sp::SamplerSimple{<:DiscreteDistribution})
draw_number(rng, sp.data)
end
değerleri çizmek için kullanılacaktır.
Custom sampler types
SamplerSimple
türü, önceden hesaplanmış verilerle çoğu kullanım durumu için yeterlidir. Ancak, özel örnekleyici türlerini nasıl kullanacağınızı göstermek için burada SamplerSimple
'a benzer bir şey uyguluyoruz.
Die
örneğimize geri dönersek: rand(::Die)
bir aralıktan rastgele üretim kullanır, bu nedenle bu optimizasyon için bir fırsat vardır. Özel örnekleyicimize SamplerDie
adını veriyoruz.
import Random: Sampler, rand
struct SamplerDie <: Sampler{Int} # generates values of type Int
die::Die
sp::Sampler{Int} # this is an abstract type, so this could be improved
end
Sampler(RNG::Type{<:AbstractRNG}, die::Die, r::Random.Repetition) =
SamplerDie(die, Sampler(RNG, 1:die.nsides, r))
# the `r` parameter will be explained later on
rand(rng::AbstractRNG, sp::SamplerDie) = rand(rng, sp.sp)
Artık sp = Sampler(rng, die)
ile bir örnekleyici almak ve rng
ile ilgili herhangi bir rand
çağrısında die
yerine sp
kullanmak mümkün. Yukarıdaki basit örnekte, die
'nin SamplerDie
içinde saklanmasına gerek yoktur, ancak pratikte bu genellikle böyle olur.
Tabii ki, bu desen o kadar sık ki, yukarıda kullanılan yardımcı tür, yani Random.SamplerSimple
, mevcut ve SamplerDie
tanımını yapmamıza gerek kalmıyor: ayrıştırmamızı şu şekilde uygulayabilirdik:
Sampler(RNG::Type{<:AbstractRNG}, die::Die, r::Random.Repetition) =
SamplerSimple(die, Sampler(RNG, 1:die.nsides, r))
rand(rng::AbstractRNG, sp::SamplerSimple{Die}) = rand(rng, sp.data)
Burada, sp.data
, SamplerSimple
yapıcısına yapılan çağrıda ikinci parametreyi ifade eder (bu durumda Sampler(rng, 1:die.nsides, r)
ile eşittir), Die
nesnesine ise sp[]
aracılığıyla erişilebilir.
SamplerDie
gibi, herhangi bir özel örnekleyici Sampler{T}
alt türü olmalıdır; burada T
, üretilen değerlerin türüdür. SamplerSimple(x, data) isa Sampler{eltype(x)}
olduğu için, bu SamplerSimple
'a ilk argümanın ne olabileceğini kısıtlar (ilk argüman olarak SamplerSimple
'ı kullanmanız önerilir; burada x
, bir Sampler
yöntemi tanımlarken basitçe iletilir). Benzer şekilde, SamplerTrivial(x) isa Sampler{eltype(x)}
.
Başka bir yardımcı tür, Random.SamplerTag
, diğer durumlar için mevcut, ancak dahili API olarak kabul edilir ve uygun bir deprekasyon olmadan herhangi bir zamanda bozulabilir.
Using distinct algorithms for scalar or array generation
Bazı durumlarda, yalnızca birkaç değer üretmek isteyip istemediğiniz veya büyük sayıda değer üretmek isteyip istemediğiniz, algoritma seçiminde etkili olacaktır. Bu, Sampler
yapıcısının üçüncü parametresi ile ele alınır. İki yardımcı tür tanımladığımızı varsayalım, Die
için, SamplerDie1
yalnızca birkaç rastgele değer üretmek için kullanılacak ve SamplerDieMany
ise birçok değer için kullanılacak. Bu türleri aşağıdaki gibi kullanabiliriz:
Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{1}) = SamplerDie1(...)
Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{Inf}) = SamplerDieMany(...)
Elbette, rand
bu türler üzerinde de tanımlanmalıdır (yani rand(::AbstractRNG, ::SamplerDie1)
ve rand(::AbstractRNG, ::SamplerDieMany)
). Her zamanki gibi, özel türler gerekli değilse SamplerTrivial
ve SamplerSimple
kullanılabilir.
Not: Sampler(rng, x)
sadece Sampler(rng, x, Val(Inf))
için bir kısayoldur ve Random.Repetition
Union{Val{1}, Val{Inf}}
için bir takma addır.
Creating new generators
API henüz net bir şekilde tanımlanmamış, ancak genel bir kural olarak:
- herhangi bir
rand
yöntemi "temel" türler (isbitstype
tam sayılar veBase
içindeki kayan nokta türleri) üretiyorsa, bunlar bu özel RNG için tanımlanmalıdır, eğer gerekiyorsa; - diğer belgelenmiş
rand
yöntemleri birAbstractRNG
kabul ediyorsa kutudan çıktığı gibi çalışmalıdır, (1) numaralı maddeden hangi yöntemlerin kullanıldığı uygulanmışsa), ancak elbette bu RNG için optimizasyon alanı varsa özelleştirilebilir; copy
için pseudo-RNG'ler, çağrıldığında aynı şekilde orijinal ile aynı rastgele diziyi üreten bağımsız bir kopya döndürmelidir. Bu mümkün olmadığında (örneğin, donanım tabanlı RNG'ler),copy
uygulanmamalıdır.
Concerning 1), a rand
method may happen to work automatically, but it's not officially supported and may break without warnings in a subsequent release.
Yeni bir rand
metodunu varsayımsal bir MyRNG
jeneratörü için tanımlamak ve bir değer spesifikasyonu s
(örneğin s == Int
veya s == 1:10
) tanımlamak için, S==typeof(s)
veya S==Type{s}
ise s
bir türse, daha önce gördüğümüz aynı iki metod tanımlanmalıdır:
Sampler(::Type{MyRNG}, ::S, ::Repetition)
, buSamplerS
türünde bir nesne döndürür.rand(rng::MyRNG, sp::SamplerS)
Sampler(rng::AbstractRNG, ::S, ::Repetition)
zaten Random
modülünde tanımlı olabilir. Bu durumda, pratikte adım 1)'i atlamak mümkün olacaktır (eğer bu belirli RNG türü için üretimi özelleştirmek isteniyorsa), ancak ilgili SamplerS
türü içsel bir detay olarak kabul edilir ve uyarı olmaksızın değiştirilebilir.
Specializing array generation
Bazı durumlarda, belirli bir RNG türü için, rastgele değerler dizisi oluşturmak, daha önce açıklanan ayrıştırma tekniğini kullanmaktan daha verimli olabilir. Bu, örneğin, rastgele değerleri bir diziye yerel olarak yazan MersenneTwister
için geçerlidir.
MyRNG
için bu özel durumu ve s
spesifikasyonunu uygulamak için, S
türünde elemanlar üreten aşağıdaki yöntem tanımlanabilir: rand!(rng::MyRNG, a::AbstractArray{S}, ::SamplerS)
, burada SamplerS
, Sampler(MyRNG, s, Val(Inf))
tarafından döndürülen örnekleyicinin türüdür. AbstractArray
yerine, işlevselliği yalnızca bir alt tür için uygulamak mümkündür, örneğin Array{S}
. rand
'ın değiştirici olmayan dizi yöntemi, bu özel durumu otomatik olarak dahili olarak çağıracaktır.
Reproducibility
RNG parametreleri belirli bir tohum ile başlatıldığında, programınızı birden fazla kez çalıştırdığınızda aynı sahte rastgele sayı dizisini yeniden üretebilirsiniz. Ancak, Julia'nın küçük bir sürümü (örneğin 1.3'ten 1.4'e) belirli bir tohumdan üretilen sahte rastgele sayı dizisini değiştirebilir, özellikle MersenneTwister
kullanılıyorsa. (Düşük seviyeli bir fonksiyonun ürettiği dizinin değişmemesi durumunda bile, rand
gibi, daha yüksek seviyeli fonksiyonların çıktısı randsubseq
algoritma güncellemeleri nedeniyle değişebilir.) Gerekçe: sahte rastgele akışların asla değişmeyeceğini garanti etmek, birçok algoritmik iyileştirmeyi engeller.
Eğer rastgele verilerin tam yeniden üretilebilirliğini garanti etmek istiyorsanız, verileri kaydetmek (örneğin, bir bilimsel yayında ek bir ek olarak) tavsiye edilir. (Ayrıca, özellikle bit yeniden üretilebilirliğine ihtiyaç duyuyorsanız, belirli bir Julia sürümünü ve paket manifestosunu da belirtebilirsiniz.)
Yazılım testleri, belirli "rastgele" verilere dayanıyorsa, genellikle verileri kaydetmeli, test koduna gömmeli veya StableRNGs.jl gibi üçüncü taraf paketler kullanmalıdır. Öte yandan, çoğu rastgele veri için geçmesi gereken testler (örneğin, rastgele bir matris A = randn(n,n)
için A \ (A*x) ≈ x
test etme) çok olasılıksız veriler nedeniyle testin birçok kez çalıştırılmasının başarısızlıkla karşılaşmamasını sağlamak için sabit bir tohum ile bir RNG kullanabilir.
İstatistiksel dağılım, rastgele örneklerin alındığı aynı minor Julia sürümleri arasında garanti edilmektedir.