Алгоритм «Зиккурат» (англ. Ziggurat Algorithm, Ziggurat Method) — это алгоритм выборки псевдослучайных чисел. Будучи представителем класса алгоритмов выборки с отклонением, он в работе своей опирается на источник равномерно распределенных случайных чисел — обыкновенно это генератор псевдослучайных чисел, либо же предварительно вычисленная таблица. Алгоритм используется для генерации значений на основе монотонно убывающего вероятностного распределения. Также может быть применен по отношению к симметричному унимодальному распределению, такому как нормальное, с помощью выбора значений из одной его половины, а затем, при необходимости, перехода к симметричному значению с помощью операции арифметического отрицания. Одним из авторов алгоритма, разработанного в 1960-е, является Джордж Марсалья.
В простейшем случае для вычисления значения, возвращаемого алгоритмом, требуется только генерация одного числа с плавающей точкой и одного случайного табличного индекса, за которой следует один табличный поиск, одна операция умножения и одно сравнение. Иногда (в гораздо меньшем количестве случаев) требуются более сложные вычисления. Тем не менее, данный алгоритм гораздо быстрее с вычислительной точки зрения, чем два наиболее часто используемых метода генерации нормально распределенных случайных чисел: полярного метода Марсальи и преобразования Бокса — Мюллера, где требуется вычисление по меньшей мере одного логарифма и одного квадратного корня для каждой пары генерируемых значений. Однако, так как алгоритм «Зиккурат» более сложен в реализации, наиболее часто он используется в случаях, где требуется большое количество случайных чисел.
Сам термин «алгоритм „Зиккурат“» (Ziggurat Algorithm) фигурирует в совместной работе Марсальи и Ваи Ван Тсанга 2000 года и назван так потому, что концептуально основан на покрытии распределения вероятностей прямоугольными сегментами, сложенными друг на друге в порядке уменьшения размера (если рассматривать снизу вверх), что приводит к появлению фигуры, напоминающей зиккурат.
Алгоритм «Зиккурат» — это алгоритм выборки с отклонением. Он случайным образом генерирует точку, незначительно отклоненную от нужного распределения, а затем проверяет попала ли сгенерированная точка точно внутрь такового. Если нет, алгоритм пробует заново. Если точка лежит под кривой вероятностной функции плотности, то ее x-координата и будет искомым случайным числом с нужным распределением.
Распределение, из которого алгоритм производит выборку, состоит из областей равной площади; прямоугольник покрывает основную часть нужного распределения и располагается «пирамидкой» на не-прямоугольном основании, которое включает в себя остаточную часть или «хвост» распределения.
У заданной монотонно убывающей вероятностной функции плотности , определенной для всех , основание зиккурата определяется как все точки внутри распределения и ниже некоторого . Оно состоит из прямоугольной части от до , и (обычно бесконечного) остатка (хвоста) распределения, где (и ).
Этот уровень (назовем его уровень 0) имеет площадь . Добавим на его вершину новый прямоугольный уровень ширины и высоты , так что у него тоже площадь будет равна . Вершина этого уровня находится на высоте , и пересекает функцию плотности в точке , где . Этот уровень включает в себя все точки функции плотности между и , но (в отличие от базового уровня) также включает прочие точки, такие, как , которые не принадлежат нужному распределению.
Все последующие уровни накладываются друг на друга аналогичным образом. Для использования предварительно вычисленной таблицы размера ( используется очень часто), следует выбрать так, что , таким образом верхний прямоугольный уровень с номером достигнет пика распределения в точности в точке .
Уровень с номером в высоту занимает место от до , и по ширине может быть разделен на две области: часть от до (обыкновенно бо́льшую), которая целиком содержится внутри заданного распределения, и часть от до (меньшую), которая содержится внутри лишь частично.
Забывая ненадолго о вопросе особого случая с уровнем 0, и имея равномерно распределенные числа и , алгоритм может быть описан следующим образом:
Шаг 1 является случайной выборкой уровня. Шаг 3 проверяет, лежит ли координата чётко внутри заданной функции плотности даже без какой-либо информации о координате . Если не лежит, шаг 4 производит вычисление координаты , и шаг 5 производит проверку на попадание внутрь нужной области.
Если число уровней достаточно велико и они имеют малую высоту, то та самая «зона риска», проверка которой производится после шага 3, очень мала, и алгоритм останавливается на шаге 3 существенную часть времени. Стоит обратить внимание на то, что верхний уровень , однако, этот тест всегда проваливает, так как .
Уровень 0 также может быть разделен на центральную и граничную области, но граничная будет содержать бесконечный остаток функции. Для использования того же алгоритма для проверки принадлежности точки центральной области, стоит сгенерировать фиктивную . Точки с координатой будут обрабатываться просто, а для того редкого случая, когда был выбран уровень 0 и , придется использовать особый резервный алгоритм для случайной выборки точки из «хвоста» функции. Поскольку такой запасной алгоритм будет задействован чрезвычайно редко (редкость относительна и зависит от разбиения на уровни), то его скорость не окажет существенного влияния на производительность в целом.
Таким образом, полный алгоритм «Зиккурат» для несимметричного распределения выглядит следующим образом:
Для симметричного распределения результат, конечно же, может просто становиться противоположного знака в 50 % случаев. Часто может быть удобно сгенерировать и на шаге 3 проверить .
Так как алгоритм «Зиккурат» очень быстро генерирует только лишь большую часть значений и требует наличия запасного алгоритма в случаях , дела обстоят сложнее непосредственной реализации из 6 шагов. Запасной алгоритм зависит от заданного распределения.
В случае показательного распределения, хвостовая часть имеет вид тела распределения. Один из способов — вернуться к самому элементарному алгоритму и положить . Другой способ состоит в рекурсивном вызове алгоритма «Зиккурат» и прибавлении к результату.
В случае нормального распределения, Марсалья предлагает компактный алгоритм:
Так как для таблиц более-менее типичных размеров, тест на шаге 3 почти всегда успешен.
Алгоритм может быть выполнен эффективно с использованием заранее вычисленных таблиц и , но есть несколько модификаций, чтобы ускорить его еще больше:
Возможно или хранить таблицу с заранее вычисленными и целиком, или всего лишь включить значения , , , и реализацию в исходный код, и вычислить оставшиеся значения при инициализации генератора случайных чисел (зависит от того, что нам дороже: вычислительное время или память).
Можно находить и . Повторить для всех уровней зиккурата. В конце должно получиться .
При итоговом заполнении таблицы нужно положить и , приняв небольшие несостыковки (если они и правда вышли небольшими) как ошибки округления.
Если имеется начальное значение (вычисленное если и не точно, то приближенно), останется лишь вычислить площадь хвостовой части функции, для которой выполнено . Вычислить можно методами численного интегрирования.
Далее, из можно найти , из площади хвостовой части найдется площадь базового уровня: .
Затем вычисляется серия и как показано выше. Если для любых , тогда начальное значение было слишком малым, что привело к большой площади . Если , тогда начальное значение было слишком большим.
Учитывая сказанное, можно использовать численное решение уравнений (например, метод бисекции) для нахождения значения , при котором значение так близко к как только возможно. В качестве альтернативы можно рассматривать и находить значения площади верхнего уровня, , настолько близкие к нужному значению как только возможно.
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .