- Зачем:
- спека отвечает «почему», а жанра «как пройти устройство по коду»
не было (#48); черновик в generator/README.md ждал выверки.
- Что:
- новый набор docs/architecture/generator/: индекс с целевой картиной
и mermaid-схемой плюс шесть поддокументов по темам тикета.
- демо-модуль и цель make demo: канонический D0, все стадии цепочки
на одном экране; тест-сторож проверяет стадии без прибитых чисел.
- раздел «Как это работает» в generator/README.md сжат до ссылки
на путеводитель, черновая врезка снята.
- Проверка:
- из generator/: make lint, make typecheck, make test (430 passed),
make demo; два слепых ревью и узкая перепроверка — находки закрыты.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
42 lines
2.8 KiB
Markdown
42 lines
2.8 KiB
Markdown
# Целочисленная случайность
|
||
|
||
Этот документ отвечает на вопрос, как читать целочисленный выбор по весам и
|
||
зачем генератору свой маленький `weights.py`.
|
||
|
||
За `PCG64` и целые броски `Generator.integers` отвечает NumPy.
|
||
Генератор стенда не пользуется готовым выбором по вещественным вероятностям и
|
||
плавающими распределениями: их алгоритмы и системная математика могут
|
||
различаться между версиями и архитектурами. Зависимости закреплены, а броски
|
||
остаются целыми — так выполняется побайтовое обещание, записанное в [спеке
|
||
генератора](../../specs/2026-08-01-generator.md), раздел 2.
|
||
|
||
## Одна таблица весов
|
||
|
||
[`weights.pick`](../../../generator/src/clickstream_generator/weights.py)
|
||
сначала получает накопленные веса. Для весов `2, 3, 1` это границы
|
||
`2, 5, 6`. Затем он бросает целое число из полуинтервала `[0, 6)` и находит
|
||
первую границу справа:
|
||
|
||
- броски `0–1` выбирают вариант 0;
|
||
- броски `2–4` выбирают вариант 1;
|
||
- бросок `5` выбирает вариант 2.
|
||
|
||
Размер участка и есть вес варианта. Нормировать веса до долей единицы не
|
||
нужно.
|
||
|
||
## Своя таблица для каждой строки
|
||
|
||
[`weights.pick_row`](../../../generator/src/clickstream_generator/weights.py)
|
||
работает так же, когда у каждого броска свой ряд весов. Ряды с одинаковой
|
||
суммой укладываются друг за другом. Номер ряда смещает бросок на его участок,
|
||
единый поиск находит ячейку, а обратное смещение возвращает номер варианта.
|
||
|
||
Конкретный проход виден в
|
||
[`day._hour_cumulative`](../../../generator/src/clickstream_generator/day.py)
|
||
и [`day._starts`](../../../generator/src/clickstream_generator/day.py): для
|
||
каждого города суточная волна повернута в свой ряд, но сумма весов от поворота
|
||
не меняется.
|
||
|
||
При чтении вызова `pick` полезно представлять ряд целочисленных участков:
|
||
бросок выбирает вариант, в чей участок он попал.
|