calculate_activation_probability()

Домен: SIMULATION | Контур: Стохастическая активация и диспетчеризация

WarningОграничение публичной документации

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

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

1. Бизнес-спецификация метода

  • Идентификатор метода: BPDS-SIM-M02
  • Системное имя: calculate_activation_probability()
  • Микросервис: simulation-core-engine
  • Домен: SIMULATION
  • Класс / Компонент: simulation.engine.scheduler.ActivationDispatcher

1.1. Описание логики работы

Этот метод работает внутри Диспетчера. Он решает, совершит ли конкретный пользователь какое-либо действие в текущем виртуальном часе симуляции. Симулятор не перебирает пользователей вглухую, а использует стохастический фильтр:

  1. Сначала метод моментально проверяет оперативную память (RAM) — если пользователь критически голоден, он признается активным автоматически. Физиологическая потребность перебивает социальные привычки.
  2. Если голод не критичен, симулятор оценивает его характер и привычки: сопоставляет хронотип из базы данных с текущим часом суток Алматы (например, любители вечерних закупок в пятницу) и умножает на его личную спонтанность.
  3. На выходе получается итоговый шанс активности. Симулятор бросает виртуальный кубик (случайное число), и если оно укладывается в этот шанс, пользователь «просыпается» для совершения шага.

1.2. Пошаговое выполнение

  1. Запрос голода: Метод запрашивает из оперативной памяти (ConcurrentHashMap) текущий показатель голода пользователя.
  2. Физиологический перехват: Если голод равен или выше 0.9000 (критическая стадия), метод сразу возвращает вероятность 1.0000, минуя проверку характера.
  3. Оценка привычек: Если голод в норме, метод берет хронотип и спонтанность пользователя из базы данных и рассчитывает социальный шанс активности с учетом часа и дня.
  4. Свертка Бернулли: Итоговая вероятность берется как максимальное значение между текущим голодом и рассчитанным социальным шансом.
  5. Бросок кубика: Генерируется случайное число от 0.0 до 1.0. Если число меньше или равно итоговой вероятности — управление передается следующему методу (evaluate_next_step) для запуска транзакции.

2. Диаграмма последовательности метода (Вход и Выход флоу)

Диаграмма наглядно показывает, как Диспетчер принимает временной контекст от Часов (Метод 1), параллельно вычитывает профили из базы данных, сверяет оперативную память и передает управление Методу 3.

sequenceDiagram
    autonumber
    participant Ticker as Метод 1 (SimulationTicker)
    participant Disp as ActivationDispatcher
    participant DB as База Данных Симулятора
    participant RAM as RAM Реестр (TickRegistry)
    participant Core as Метод 3 (CoreSimulationEngine)

    %% ВХОД МЕТОДА И ВЫЧИТКА ПОПУЛЯЦИИ
    Ticker->>Disp: Вызов processActivation(AlmatyTimeContext)
    activate Disp
    Note over Disp: Вход метода: Текущий такт, час и день недели Алматы
    
    Disp->>DB: SELECT twin_id, chronotype, spontaneity_rate FROM twin_profiles
    activate DB
    DB-->>Disp: Возврат: Список всех пользователей популяции (20k строк)
    deactivate DB

    Note over Disp: Инициализация пула виртуальных потоков Java 21+<br/>Каждый пользователь обрабатывается в своем потоке параллельно

    %% ВНУТРЕННИЙ СТОХАСТИЧЕСКИЙ ФИЛЬТР
    loop Параллельно для каждого пользователя
        Disp->>RAM: Запрос уровня голода hunger_x0 (volatile)
        activate RAM
        RAM-->>Disp: Возврат: Текущий голод (Пример: 0.4500)
        deactivate RAM
        
        Note over Disp: Расчет вероятности P_active на основе характера и времени Алматы
        Note over Disp: Бросок кубика Бернулли: random_float = Math.random()
        
        alt Ситуация 1: random_float <= P_active (Пользователь АКТИВЕН)
            Note over Disp: Выход метода: Генерация X-Request-ID для сессии твина
            
            %% ПЕРЕДАЧА УПРАВЛЕНИЯ СЛЕДУЮЩЕМУ МЕТОДУ
            Disp->>Core: Вызов evaluate_next_step(twin_id, tick, requestId)
            activate Core
            Note over Core: Управление передано в Метод 3 (Инициация транзакции шага)
            deactivate Core
        else Ситуация 2: random_float > P_active (Пользователь ПАССИВЕН)
            Note over Disp: Поток пользователя изолированно завершает работу
        end
    end
    deactivate Disp


3. Схемы данных и SQL-взаимодействие

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

3.1. Структура таблицы профилей

CREATE TABLE simulation.twin_profiles (
    twin_id UUID PRIMARY KEY,
    chronotype VARCHAR(32) NOT NULL,          -- Временное окно ("FRIDAY_EVENING", "DAILY_LUNCH")
    laziness_coefficient NUMERIC(5, 4) NOT NULL, -- Коэффициент лени (будет нужен на шаге 7)
    spontaneity_rate NUMERIC(5, 4) NOT NULL,     -- Спонтанность (влияет на импульсивные действия)
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

3.2. Чтение популяции планировщиком (Запрос на получение данных)

На каждом часовом такте симулятор выгружает параметры для фильтрации:

SELECT twin_id, chronotype, spontaneity_rate FROM simulation.twin_profiles;

4. Спецификация обмена данными (Вход / Выход)

Поскольку метод выполняется параллельно внутри оперативной памяти сервера на виртуальных потоках воркеров, у него нет внешних сетевых HTTP-эндпоинтов. Контракты специфицируются в виде структур данных в памяти.

4.1. Структура входящего контекста времени (Входные параметры от Метода 1)

{
  "global_tick": 105,
  "hour_of_day": 19,
  "day_of_week": "FRIDAY"
}

4.2. Структура выходного сигнала запуска (Входные параметры для Метода 3)

Передается только для тех пользователей, которые успешно прошли проверку «кубика» активности.

{
  "active_twin_id": "d3b07384-d113-4956-bf8a-e421cd7bf777",
  "current_tick": 105,
  "x_request_id": "req-t105-active-d3b07384"
}

5. ЗАДАЧА ДЛЯ РАЗРАБОТЧИКА: BACKEND

Заголовок: Реализация Диспетчера стохастической активации пользователей calculate_activation_probability на виртуальных потоках

5.1. Что нужно сделать

  1. Написать Java-класс ActivationDispatcher в пакете simulation.engine.scheduler.
  2. Подключить вызов метода к получению данных от SimulationTicker (Метод 1).
  3. При наступлении такта выгружать список всех пользователей через репозиторий TwinProfileRepository.
  4. Использовать пул виртуальных потоков Java 21+ (Executors.newVirtualThreadPerTaskExecutor()), чтобы каждый пользователь обрабатывался параллельно и не блокировал общие потоки процессора.
  5. Внутри потока запрашивать голод из TickRegistry, рассчитывать вероятность по формуле Math.max(hungerX0, Math.min(1.0, 0.05 * modifier * spontaneity)) и бросать случайное число Math.random().
  6. Для прошедших фильтр пользователей генерировать уникальную строку X-Request-ID и вызывать метод Ядра coreEngine.evaluateNextStep().

6. ЗАДАЧА ДЛЯ РАЗРАБОТЧИКА: МИГРАЦИЯ

Заголовок: Индексация таблицы twin_profiles для ускорения массовой выгрузки Диспетчером

6.1. Что нужно сделать

  1. Создать SQL-скрипт миграции СУБД для создания покрывающего индекса B-Tree.
  2. Индекс должен включать поля twin_id, chronotype и spontaneity_rate, чтобы база данных Postgres могла мгновенно отдавать эти данные планировщику без построчного сканирования всего диска.
CREATE INDEX IF NOT EXISTS idx_twin_profiles_scheduler_cover 
ON simulation.twin_profiles (twin_id, chronotype, spontaneity_rate);