Spec-Zone.ru › Julia 1.0

Случайные числа

Генерация случайных чисел в Julia использует библиотеку Mersenne Twister через объекты MersenneTwister. Julia имеет глобальный генератор случайных чисел (RNG), который используется по умолчанию. Другие типы RNG могут быть подключены, наследуя тип AbstractRNG; они могут затем использоваться для получения нескольких потоков случайных чисел. Помимо MersenneTwister, Julia также предоставляет тип RNG RandomDevice, который является оболочкой над энтропией, предоставляемой ОС.

Большинство функций, связанных с генерацией случайных чисел, принимают необязательный объект AbstractRNG в качестве первого аргумента, который по умолчанию равен глобальному, если не указан. Кроме того, некоторые из них принимают необязательные спецификации размерности dims... (которые могут быть заданы как кортеж) для генерации массивов случайных значений.

RNG типа MersenneTwister или RandomDevice может генерировать равномерно распределенные случайные числа следующих типов: Float16, Float32, Float64, BigFloat, Bool, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128, BigInt (или комплексные числа этих типов). Случайные числа с плавающей точкой генерируются равномерно в $[0, 1)$. Так как BigInt представляет неограниченные целые числа, интервал должен быть указан (например, rand(big.(1:6))).

Кроме того, нормальное и экспоненциальное распределения реализованы для некоторых типов AbstractFloat и Complex, см. randn и randexp для подробностей.

Функции генерации случайных чисел

Base.randФункция

rand([rng=GLOBAL_RNG], [S], [dims...])

Выбирает случайный элемент или массив случайных элементов из набора значений, указанных S; S может быть

  • индексируемой коллекцией (например, 1:n или ['x','y','z']),
  • объектом AbstractDict или AbstractSet,
  • строкой (рассматриваемой как коллекция символов), или
  • типом: набор значений для выбора тогда эквивалентен typemin(S):typemax(S) для целых чисел (это не применяется к BigInt), и к $[0, 1)$ для чисел с плавающей точкой;

S по умолчанию равен Float64 (за исключением случаев, когда dims является кортежем целых чисел, в этом случае S должен быть указан).

Примеры

julia> rand(Int, 2)
2-element Array{Int64,1}:
 1339893410598768192
 1575814717733606317

julia> rand(MersenneTwister(0), Dict(1=>2, 3=>4))
1=>2
Примечание

Сложность rand(rng, s::Union{AbstractDict,AbstractSet}) линейна относительно длины s, за исключением случаев, когда доступен оптимизированный метод с постоянной сложностью, что имеет место для Dict, Set и BitSet. Для более чем нескольких вызовов используйте rand(rng, collect(s)) вместо этого, или rand(rng, Dict(s)) или rand(rng, Set(s)) соответственно.

исходный код

Random.rand!Функция

rand!([rng=GLOBAL_RNG], A, [S=eltype(A)])

Заполняет массив A случайными значениями. Если S указано (S может быть типом или коллекцией, см. rand для подробностей), значения выбираются случайным образом из S. Это эквивалентно copyto!(A, rand(rng, S, size(A))), но без выделения нового массива.

Примеры

julia> rng = MersenneTwister(1234);

julia> rand!(rng, zeros(5))
5-element Array{Float64,1}:
 0.5908446386657102
 0.7667970365022592
 0.5662374165061859
 0.4600853424625171
 0.7940257103317943
исходный код

Random.bitrandФункция

bitrand([rng=GLOBAL_RNG], [dims...])

Генерирует массив BitArray случайных логических значений.

Примеры

julia> rng = MersenneTwister(1234);

julia> bitrand(rng, 10)
10-element BitArray{1}:
 false
  true
  true
  true
  true
 false
  true
 false
 false
  true
исходный код

Base.randnФункция

randn([rng=GLOBAL_RNG], [T=Float64], [dims...])

Генерирует нормально распределенное случайное число типа T со средним значением 0 и стандартным отклонением 1. Необязательно генерирует массив нормально распределенных случайных чисел. Модуль Base в настоящее время предоставляет реализацию для типов Float16, Float32 и Float64 (по умолчанию) и их комплексных аналогов Complex. Когда аргумент типа является комплексным, значения выбираются из круговой симметричной комплексной нормальной распределения.

Примеры

julia> rng = MersenneTwister(1234);

julia> randn(rng, ComplexF64)
0.6133070881429037 - 0.6376291670853887im

julia> randn(rng, ComplexF32, (2, 3))
2×3 Array{Complex{Float32},2}:
 -0.349649-0.638457im  0.376756-0.192146im  -0.396334-0.0136413im
  0.611224+1.56403im   0.355204-0.365563im  0.0905552+1.31012im
исходный код

Random.randn!Функция

randn!([rng=GLOBAL_RNG], A::AbstractArray) -> A

Заполняет массив A нормально распределёнными (среднее 0, стандартное отклонение 1) случайными числами. Также см. функцию rand.

Примеры

julia> rng = MersenneTwister(1234);

julia> randn!(rng, zeros(5))
5-element Array{Float64,1}:
  0.8673472019512456
 -0.9017438158568171
 -0.4944787535042339
 -0.9029142938652416
  0.8644013132535154
исходный код

Random.randexpФункция

randexp([rng=GLOBAL_RNG], [T=Float64], [dims...])

Генерирует случайное число типа T согласно экспоненциальному распределению со масштабом 1. Необязательно генерирует массив таких случайных чисел. Модуль Base в настоящее время предоставляет реализацию для типов Float16, Float32 и Float64 (по умолчанию).

Примеры

julia> rng = MersenneTwister(1234);

julia> randexp(rng, Float32)
2.4835055f0

julia> randexp(rng, 3, 3)
3×3 Array{Float64,2}:
 1.5167    1.30652   0.344435
 0.604436  2.78029   0.418516
 0.695867  0.693292  0.643644
исходный код

Random.randexp!Функция

randexp!([rng=GLOBAL_RNG], A::AbstractArray) -> A

Заполняет массив A случайными числами, следующими экспоненциальному распределению (со масштабом 1).

Примеры

julia> rng = MersenneTwister(1234);

julia> randexp!(rng, zeros(5))
5-element Array{Float64,1}:
 2.4835053723904896
 1.516703605376473
 0.6044364871025417
 0.6958665886385867
 1.3065196315496677
исходный код

Random.randstringФункция

randstring([rng=GLOBAL_RNG], [chars], [len=8])

Создаёт случайную строку длиной len, состоящую из символов из chars, которая по умолчанию является набором прописных и строчных букв и цифр от 0 до 9. Необязательный аргумент rng задаёт генератор случайных чисел, см. Случайные числа.

Примеры

julia> Random.seed!(0); randstring()
"0IPrGg0J"

julia> randstring(MersenneTwister(0), 'a':'z', 6)
"aszvqk"

julia> randstring("ACGT")
"TATCGGTC"
Примечание

chars может быть любой коллекцией символов, типа Char или UInt8 (более эффективно), при условии, что rand может случайным образом выбирать символы из неё.

исходный код

Подпоследовательности, перестановки и перемешивание

Random.randsubseqФункция

randsubseq([rng=GLOBAL_RNG,] A, p) -> Vector

Возвращает вектор, состоящий из случайной подпоследовательности заданного массива A, где каждый элемент A включается (в порядке) с независимой вероятностью p. (Сложность линейна относительно p*length(A), поэтому эта функция эффективна даже если p мал, а A велик.) В техническом плане этот процесс известен как «выборка Бернулли» из A.

Примеры

julia> rng = MersenneTwister(1234);

julia> randsubseq(rng, collect(1:8), 0.3)
2-element Array{Int64,1}:
 7
 8
исходный код

Random.randsubseq!Функция

randsubseq!([rng=GLOBAL_RNG,] S, A, p)

Аналогично randsubseq, но результаты сохраняются в S (размер которого изменяется по мере необходимости).

Примеры

julia> rng = MersenneTwister(1234);

julia> S = Int64[];

julia> randsubseq!(rng, S, collect(1:8), 0.3);

julia> S
2-element Array{Int64,1}:
 7
 8
исходный код

Random.randpermФункция

randperm([rng=GLOBAL_RNG,] n::Integer)

Создаёт случайную перестановку длины n. Необязательный аргумент rng задаёт генератор случайных чисел (см. Случайные числа). Для случайного перемешивания произвольного вектора см. shuffle или shuffle!.

Примеры

julia> randperm(MersenneTwister(1234), 4)
4-element Array{Int64,1}:
 2
 1
 4
 3
исходный код

Random.randperm!Функция

randperm!([rng=GLOBAL_RNG,] A::Array{<:Integer})

Создаёт в A случайную перестановку длины length(A). Необязательный аргумент rng задаёт генератор случайных чисел (см. Случайные числа). Для случайной перестановки произвольного вектора, см. shuffle или shuffle!.

Примеры

julia> randperm!(MersenneTwister(1234), Vector{Int}(undef, 4))
4-element Array{Int64,1}:
 2
 1
 4
 3
исходный код

Random.randcycleФункция

randcycle([rng=GLOBAL_RNG,] n::Integer)

Создаёт случайную циклическую перестановку длины n. Необязательный аргумент rng задаёт генератор случайных чисел, см. Случайные числа.

Примеры

julia> randcycle(MersenneTwister(1234), 6)
6-element Array{Int64,1}:
 3
 5
 4
 6
 1
 2
исходный код

Random.randcycle!Функция

randcycle!([rng=GLOBAL_RNG,] A::Array{<:Integer})

Создаёт в A случайную циклическую перестановку длины length(A). Необязательный аргумент rng задаёт генератор случайных чисел, см. Случайные числа.

Примеры

julia> randcycle!(MersenneTwister(1234), Vector{Int}(undef, 6))
6-element Array{Int64,1}:
 3
 5
 4
 6
 1
 2
исходный код

Random.shuffleФункция

shuffle([rng=GLOBAL_RNG,] v::AbstractArray)

Возвращает случайную перестановку копии v. Необязательный аргумент rng задаёт генератор случайных чисел (см. Случайные числа). Для перестановки v на месте, см. shuffle!. Для получения случайной перестановки индексов, см. randperm.

Примеры

julia> rng = MersenneTwister(1234);

julia> shuffle(rng, Vector(1:10))
10-element Array{Int64,1}:
  6
  1
 10
  2
  3
  9
  5
  7
  4
  8
исходный код

Random.shuffle!Функция

shuffle!([rng=GLOBAL_RNG,] v::AbstractArray)

Функция shuffle для перестановки на месте: случайная перестановка v на месте, необязательно с генератором случайных чисел rng.

Примеры

julia> rng = MersenneTwister(1234);

julia> shuffle!(rng, Vector(1:16))
16-element Array{Int64,1}:
  2
 15
  5
 14
  1
  9
 10
  6
 11
  3
 16
  7
  4
 12
  8
 13
исходный код

Генераторы (создание и инициализация)

Random.seed!Функция

seed!([rng=GLOBAL_RNG], seed) -> rng
seed!([rng=GLOBAL_RNG]) -> rng

Переинициализировать генератор случайных чисел: rng даст воспроизводимую последовательность чисел только в том случае, если предоставлен seed. Некоторые генераторы случайных чисел не принимают seed, как RandomDevice. После вызова seed!, rng эквивалентен только что созданному объекту, инициализированному с тем же seed.

Примеры

julia> Random.seed!(1234);

julia> x1 = rand(2)
2-element Array{Float64,1}:
 0.590845
 0.766797

julia> Random.seed!(1234);

julia> x2 = rand(2)
2-element Array{Float64,1}:
 0.590845
 0.766797

julia> x1 == x2
true

julia> rng = MersenneTwister(1234); rand(rng, 2) == x1
true

julia> MersenneTwister(1) == Random.seed!(rng, 1)
true

julia> rand(Random.seed!(rng), Bool) # not reproducible
true

julia> rand(Random.seed!(rng), Bool)
false

julia> rand(MersenneTwister(), Bool) # not reproducible either
true
исходный код

Random.MersenneTwisterТип

MersenneTwister(seed)
MersenneTwister()

Создать объект генератора случайных чисел MersenneTwister. Разные объекты генераторов могут иметь свои собственные семена, что может быть полезно для генерации различных потоков случайных чисел. seed может быть целым неотрицательным числом или вектором целых чисел UInt32. Если seed не предоставлен, создаётся случайный (используя энтропию из системы). См. функцию seed! для переинициализации уже существующего объекта MersenneTwister.

Примеры

julia> rng = MersenneTwister(1234);

julia> x1 = rand(rng, 2)
2-element Array{Float64,1}:
 0.5908446386657102
 0.7667970365022592

julia> rng = MersenneTwister(1234);

julia> x2 = rand(rng, 2)
2-element Array{Float64,1}:
 0.5908446386657102
 0.7667970365022592

julia> x1 == x2
true
исходный код

Random.RandomDeviceТип

RandomDevice()

Создать объект генератора случайных чисел RandomDevice. Два таких объекта всегда будут генерировать разные потоки случайных чисел. Энтропия извлекается из операционной системы.

исходный код

Встраивание в API Random

Есть два основных ортогональных способа расширить функциональность Random:

  1. генерация случайных значений пользовательских типов
  2. создание новых генераторов

API для 1) довольно функциональный, но относительно новый, поэтому он может ещё развиваться в последующих выпусках модуля Random. Например, обычно достаточно реализовать один метод rand, чтобы все остальные обычные методы работали автоматически.

API для 2) всё ещё примитивный и может потребовать больше работы от разработчика, чем строго необходимо, чтобы поддерживать обычные типы генерируемых значений.

Генерация случайных значений пользовательских типов

Есть две категории: генерация значений из типа (например, rand(Int)) или из коллекции (например, rand(1:3)). Простые случаи объясняются вначале, а более продвинутое использование представлено позже. Мы предполагаем здесь, что выбор алгоритма не зависит от RNG, поэтому мы используем AbstractRNG в наших сигнатурах.

Генерация значений из типа

Учитывая тип T, в настоящее время предполагается, что если rand(T) определён, будет создан объект типа T. Для определения случайной генерации значений типа T, можно определить следующий метод: rand(rng::AbstractRNG, ::Random.SamplerType{T}) (он должен возвращать то, что rand(rng, T) ожидается вернуть).

Давайте рассмотрим следующий пример: мы реализуем тип Die, с переменным числом n сторон, пронумерованных от 1 до n Мы хотим, чтобы rand(Die) генерировало кость с случайным числом сторон до 20 (и не менее 4):

struct Die
    nsides::Int # number of sides
end

Random.rand(rng::AbstractRNG, ::Random.SamplerType{Die}) = Die(rand(rng, 4:20))

# output

Скалярные и массивовые методы для Die теперь работают как ожидается:

julia> rand(Die)
Die(18)

julia> rand(MersenneTwister(0), Die)
Die(4)

julia> rand(Die, 3)
3-element Array{Die,1}:
 Die(6)
 Die(11)
 Die(5)

julia> a = Vector{Die}(undef, 3); rand!(a)
3-element Array{Die,1}:
 Die(18)
 Die(6)
 Die(8)

Генерация значений из коллекции

Учитывая тип коллекции S, в настоящее время предполагается, что если rand(::S) определён, будет создан объект типа eltype(S) Для определения случайной генерации из объектов типа S, можно определить следующий метод: rand(rng::AbstractRNG, sp::Random.SamplerTrivial{S}). Здесь, sp просто оборачивает объект типа S, к которому можно получить доступ через sp[]. Продолжая пример Die, мы хотим теперь определить rand(d::Die) для создания Int, соответствующего одной из сторон d:

julia> Random.rand(rng::AbstractRNG, d::Random.SamplerTrivial{Die}) = rand(rng, 1:d[].nsides);

julia> rand(Die(4))
3

julia> rand(Die(4), 3)
3-element Array{Any,1}:
 3
 4
 2

В последнем примере был получен Vector{Any}, потому что eltype(Die) == Any. Лечение заключается в определении Base.eltype(::Type{Die}) = Int.

Генерация значений для типа AbstractFloat

Типы AbstractFloat являются специальным случаем, потому что по умолчанию случайные значения не генерируются во всем диапазоне типа, а скорее в [0,1). Следующий метод должен быть реализован для T <: AbstractFloat: Random.rand(::AbstractRNG, ::Random.SamplerTrivial{Random.CloseOpen01{T}})

Оптимизация генерации с кэшированием вычислений между вызовами

При многократной генерации случайных значений (с теми же параметрами rand для некоторых типов происходит так, что результат вычисления используется для каждого вызова. В этом случае вычисление можно отделить от фактической генерации значений. Например, это происходит в реализации по умолчанию для AbstractArray. Предположим, что rand(rng, 1:20) должен вызываться многократно в цикле: способ воспользоваться этим разделением такой:

rng = MersenneTwister()
sp = Random.Sampler(rng, 1:20) # or Random.Sampler(MersenneTwister,1:20)
for x in X
    n = rand(rng, sp) # similar to n = rand(rng, 1:20)
    # use n
end

Этот механизм, конечно, используется в реализации по умолчанию для генерации случайных массивов (как в rand(1:20, 10)). Для реализации этого разделения для пользовательского типа можно использовать вспомогательный тип. Вернёмся к нашему примеру Die: rand(::Die) использует генерацию случайных значений из диапазона, поэтому есть возможность этой оптимизации:

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)

Теперь можно получить саплер с sp = Sampler(rng, die), и использовать sp вместо die в любом вызове rand , включающем rng. В упрощённом примере выше, die не нужно хранить в SamplerDie, но это часто встречается на практике.

Этот шаблон настолько частый, что существует вспомогательный тип под названием Random.SamplerSimple, экономящий нам определение SamplerDie: мы могли бы реализовать наше разделение с:

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)

Здесь, sp.data относится ко второму параметру в вызове конструктора SamplerSimple (в этом случае равно Sampler(rng, 1:die.nsides, r)), в то время как объект Die можно получить через sp[].

Другой вспомогательный тип в настоящее время доступен для других случаев, Random.SamplerTag, но считается внутренним API и может сломаться в любое время без надлежащего исключения.

Использование различных алгоритмов для генерации скаляров или массивов

В некоторых случаях выбор алгоритма зависит от того, нужно ли сгенерировать небольшое или большое количество значений. Это обрабатывается с помощью третьего параметра конструктора Sampler. Предположим, мы определили два вспомогательных типа для Die, скажем, SamplerDie1, который следует использовать для генерации небольшого числа случайных значений, и SamplerDieMany для генерации многих значений. Мы можем использовать эти типы следующим образом:

Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{1}) = SamplerDie1(...)
Sampler(RNG::Type{<:AbstractRNG}, die::Die, ::Val{Inf}) = SamplerDieMany(...)

Конечно, rand также должен быть определен для этих типов (т.е. rand(::AbstractRNG, ::SamplerDie1) и rand(::AbstractRNG, ::SamplerDieMany)).

Примечание: Sampler(rng, x) — это просто сокращение для Sampler(rng, x, Val(Inf)), а Random.Repetition — псевдоним для Union{Val{1}, Val{Inf}}.

Создание новых генераторов

API пока не определен четко, но в качестве правила:

  1. любой метод rand , производящий «базовые» типы (типы целых и с плавающей запятой isbitstype в Base ), должен быть определен для этого конкретного генератора случайных чисел, если они необходимы;
  2. другие документированные методы rand , принимающие AbstractRNG , должны работать прямо из коробки (при условии, что реализованы методы из п. 1), но, конечно, могут быть специализированы для этого генератора, если есть возможность оптимизации.

Что касается п. 1), метод rand может работать автоматически, но это не поддерживается официально и может сломаться без предупреждений в последующем релизе.

Для определения нового метода rand для гипотетического генератора MyRNG и спецификации значения s (например, s == Int, или s == 1:10 ) типа S==typeof(s) или S==Type{s} , если s это тип, должны быть определены те же два метода, что и раньше:

  1. Sampler(::Type{MyRNG}, ::S, ::Repetition), который возвращает объект типа, скажем, SamplerS
  2. rand(rng::MyRNG, sp::SamplerS)

Может случиться, что Sampler(rng::AbstractRNG, ::S, ::Repetition) уже определен в модуле Random. Тогда можно пропустить шаг 1) на практике (если требуется специализация генерации для этого типа генератора случайных чисел), но соответствующий тип SamplerS считается внутренней деталью и может быть изменен без предупреждения.

Специализация генерации массивов

В некоторых случаях для данного типа генератора случайных чисел генерация массива случайных значений может быть более эффективной с помощью специализированного метода, чем с использованием описанной ранее техники декомпозиции. Например, это относится к MersenneTwister, который напрямую записывает случайные значения в массив.

Чтобы реализовать эту специализацию для MyRNG и для спецификации s, производящей элементы типа S, можно определить следующий метод: rand!(rng::MyRNG, a::AbstractArray{S}, ::SamplerS), где SamplerS — тип возвращаемого выборщика Sampler(MyRNG, s, Val(Inf)). Вместо AbstractArray, можно реализовать функциональность только для подтипа, например, Array{S}. Неизменяющий метод массива rand автоматически вызовет эту специализацию внутри.

© 2009–2019 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.0.4/stdlib/Random/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API