trosna-gisteresis
Гистерезис с выдержкой времени и периодом охлаждения — правило принятия решения о перераспределении ресурсов (например, оперативной памяти между виртуальными машинами) по индексу неравномерности. Подавляет дребезг решений вблизи порога, не реагирует на короткоживущие всплески и не повторяет бесполезные перераспределения, если дисбаланс не устраняется.
Постановка
Пусть I_t — индекс неравномерности в точке мониторинга t (размах, коэффициент вариации,
индекс Джини долей свободной памяти; для индекса Джейна берут 1 − J), Δt_t — интервал
между точками мониторинга. Параметры: верхний и нижний пороги θ⁺ > θ⁻, выдержка T_d,
период охлаждения T_c. Тогда
d_t = (d_{t−1} + Δt_t) · [I_t > θ⁺] (время непрерывного превышения θ⁺)
g_t = max{g_{t−1}, [I_t < θ⁻]} (флаг готовности)
δ_t = 1 ⇔ I_t > θ⁺ ∧ d_t ≥ T_d ∧ g_t = 1 ∧ t − τ ≥ T_c (решение)
где [·] равно 1 при истинном условии и 0 иначе, τ — момент последнего срабатывания.
После срабатывания τ = t, g_t = 0, d_t = 0: повторное решение возможно только после
снижения индекса ниже θ⁻ и не раньше, чем через T_c.
- Выдержка отсекает кратковременные выбросы: решение принимается, только если дисбаланс
держится не меньше
T_d. - Два порога не дают решению «дребезжать», пока индекс колеблется около одного порога.
- Флаг готовности не даёт повторять перераспределение, если ограничения не позволяют
устранить дисбаланс (индекс остаётся выше
θ⁺). - Период охлаждения ограничивает частоту перераспределений сверху.
Необязательное расширение rearm_after = T_r взводит правило и по истечении времени T_r
после срабатывания:
g_t = max{g_{t−1}, [I_t < θ⁻], [t − τ ≥ T_r]}
Без него правило блокируется, если перераспределение не опустило индекс ниже θ⁻
(например, решение было принято во время кратковременного выброса и после его окончания
распределение памяти оказалось перекошенным).
Время задаётся в секундах (или любых единицах, одинаковых для t, T_d, T_c), поэтому
правило корректно работает при переменном интервале мониторинга. Сложность — O(1) на точку.
Использование
import numpy as np
from trosna_gisteresis import Hysteresis, hysteresis
# Ряд целиком: индекс и отметки времени (здесь — мониторинг раз в 5 с).
t = np.arange(0.0, 600.0, 5.0)
index = np.where((t >= 100) & (t < 300), 0.5, 0.1)
trace = hysteresis(index, t, upper=0.35, lower=0.25, dwell=30.0, cooldown=120.0)
# Выдержка отсчитывается от последней точки ниже θ⁺ (t = 95), поэтому решение — в t = 125.
print(trace.fire_times) # [125.]
# Поток: по одной точке мониторинга.
rule = Hysteresis(upper=0.35, lower=0.25, dwell=30.0, cooldown=120.0)
for t_i, index_i in [(0, 0.5), (10, 0.5), (20, 0.5), (30, 0.5)]:
step = rule.step(index_i, t_i)
if step.fired:
print(f"перераспределить в t = {step.t}") # перераспределить в t = 30.0
# Состояние можно сохранить и продолжить после перезапуска управляющей системы.
saved = rule.state
rule = Hysteresis(rule.params, state=saved)
hysteresis возвращает Trace с массивами fired (δ_t), dwell (d_t), armed (g_t),
since_fired (t − τ) — значения, по которым проверялось условие решения, — и итоговым
состоянием state. Без t точки считаются идущими с шагом 1.
Параметры
| Параметр | Обозначение | Смысл |
|---|---|---|
upper |
θ⁺ |
порог значимого дисбаланса |
lower |
θ⁻ |
порог, ниже которого правило снова взводится, θ⁻ < θ⁺ |
dwell |
T_d |
выдержка, в единицах времени |
cooldown |
T_c |
период охлаждения, в единицах времени |
dwell_from |
"interval" (по умолчанию, как в формуле) — первая точка выше θ⁺ засчитывает весь интервал от предыдущей; "sample" — отсчёт от первой точки выше θ⁺ |
|
missing |
пропуск (NaN): "reset" (по умолчанию) — выдержка обнуляется; "hold" — продолжает идти |
|
armed |
g_0 |
начальное значение флага готовности, по умолчанию True |
rearm_after |
T_r |
взведение по времени после срабатывания; None (по умолчанию) — только по θ⁻ |
Подробное обоснование доопределений, которых нет в исходной формулировке (начальные условия,
отсчёт выдержки, пропуски, T_d = 0, округление времени), — в docs/design.md.
Разработка
uv sync # окружение
uv run pytest # тесты (детерминированные, ~1 мин)
uv run ruff check . && uv run ruff format --check .
uv run python examples/demo.py
Тесты сравнивают реализацию с буквальной записью формул в точной арифметике на случайных
рядах (hypothesis с фиксированным порядком генерации), проверяют инварианты правила
(разнесение срабатываний не меньше T_c, обязательное снижение ниже θ⁻ между
срабатываниями, непрерывность превышения на протяжении T_d, инвариантность к сдвигу и
масштабу времени), эквивалентность потоковой и пакетной обработки и сценарии с дребезгом,
короткоживущими процессами и переменным интервалом мониторинга.
Поддерживаются Python 3.11–3.14.
Metadata
Release files for trosna-gisteresis 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| trosna_gisteresis-0.1.0.tar.gz | 8.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| trosna_gisteresis-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.6 kB
Release files / trosna_gisteresis-0.1.0.tar.gz
| Download URL | trosna_gisteresis-0.1.0.tar.gz |
|---|---|
| Size | 8.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f28b14c0243c54eb7ad091b0d23badae74049feabec9ae48bba5c0c914107298
|
|
BLAKE2b-256 checksum How to use checksums |
048842b32d298bf3f06ad3e323e93093b056a5899a8204c02e885d285897e1ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / trosna_gisteresis-0.1.0-py3-none-any.whl
| Download URL | trosna_gisteresis-0.1.0-py3-none-any.whl |
|---|---|
| Size | 10.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c3ea7bdcf2274349374acf2f34c386205973de70c5d25e35e873d2fef1b158c0
|
|
BLAKE2b-256 checksum How to use checksums |
1f70f98c1a8b906788162996459bc8c742c7bfd5439cb56e6a4eb549d18400ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|