|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
import streamlit as st |
|
|
|
|
|
SEQ_LEN = 100 |
|
HISTORY_LEN = 200 |
|
JUMP = 10 |
|
ENTROPY_BINS = 36 |
|
|
|
|
|
if "seq" not in st.session_state: |
|
st.session_state.seq = np.random.randint(-180, 180, size=SEQ_LEN) |
|
st.session_state.history = [] |
|
st.session_state.bist_counts = [] |
|
st.session_state.entropy = [] |
|
st.session_state.autocorr = [] |
|
st.session_state.step = 0 |
|
|
|
|
|
def find_local_min_runs(profile, threshold=10): |
|
"""Находит устойчивые участки ("машины"), где значения углов почти не меняются.""" |
|
runs = [] |
|
start = 0 |
|
for i in range(1, len(profile)): |
|
if abs(profile[i] - profile[i - 1]) > threshold: |
|
if i - start > 2: |
|
runs.append((start, i - 1)) |
|
start = i |
|
if len(profile) - start > 2: |
|
runs.append((start, len(profile) - 1)) |
|
return runs |
|
|
|
def compute_autocorr(profile): |
|
"""Автокорреляция – структурность, насколько повторяется рисунок""" |
|
profile = profile - np.mean(profile) |
|
result = np.correlate(profile, profile, mode='full') |
|
mid = len(result) // 2 |
|
return result[mid + 1] / result[mid] |
|
|
|
def compute_entropy(profile): |
|
"""Энтропия – мера хаотичности, насколько случайна структура""" |
|
hist, _ = np.histogram(profile, bins=ENTROPY_BINS, range=(-180, 180), density=True) |
|
hist = hist[hist > 0] |
|
return -np.sum(hist * np.log2(hist)) |
|
|
|
|
|
def draw_world(seq, axs, step, stat_bist_counts, stat_entropy, stat_autocorr): |
|
axs[0].cla() |
|
axs[1].cla() |
|
axs[2].cla() |
|
axs[3].cla() |
|
|
|
|
|
axs[0].plot(seq, label=f"Шаг {step}", color='skyblue') |
|
axs[0].set_title("Торсионный профиль (углы)") |
|
axs[0].set_ylim(-180, 180) |
|
|
|
|
|
stable_zones = find_local_min_runs(seq) |
|
for start, end in stable_zones: |
|
axs[0].axvspan(start, end, color='yellow', alpha=0.3) |
|
axs[0].text((start + end) // 2, 160, f'▲{end - start}', ha='center', va='center', fontsize=8, color='darkgreen') |
|
|
|
|
|
axs[1].plot(stat_bist_counts, color='orchid') |
|
axs[1].set_title("Кол-во устойчивых машин (стромбистов)") |
|
|
|
|
|
axs[2].plot(stat_entropy, color='crimson') |
|
axs[2].set_title("Энтропия торсионного поля") |
|
|
|
|
|
axs[3].plot(stat_autocorr, color='seagreen') |
|
axs[3].set_title("Автокорреляция (память)") |
|
|
|
for ax in axs: |
|
ax.legend() |
|
|
|
|
|
def update_step(): |
|
seq = st.session_state.seq |
|
history = st.session_state.history |
|
stat_bist_counts = st.session_state.bist_counts |
|
stat_entropy = st.session_state.entropy |
|
stat_autocorr = st.session_state.autocorr |
|
step = st.session_state.step |
|
|
|
|
|
i = np.random.randint(0, len(seq)) |
|
delta = np.random.randint(-JUMP, JUMP + 1) |
|
seq[i] = (seq[i] + delta + 180) % 360 - 180 |
|
|
|
history.append(seq.copy()) |
|
if len(history) > HISTORY_LEN: |
|
history.pop(0) |
|
|
|
stable_regions = find_local_min_runs(seq) |
|
stat_bist_counts.append(len(stable_regions)) |
|
stat_entropy.append(compute_entropy(seq)) |
|
stat_autocorr.append(compute_autocorr(seq)) |
|
st.session_state.step += 1 |
|
|
|
|
|
st.set_page_config(layout="wide") |
|
st.title("🧬 Стромбистный анализ торсионного поля") |
|
col1, col2 = st.columns([1, 2]) |
|
|
|
with col1: |
|
if st.button("🔁 Следующий шаг"): |
|
update_step() |
|
st.markdown(f"**Текущий шаг**: {st.session_state.step}") |
|
st.markdown("**Стромбисты** — устойчивые участки структуры, подобные памяти или машинам.") |
|
st.markdown("**Автокорреляция** — отражает повторяемость паттерна.") |
|
st.markdown("**Энтропия** — мера хаоса.") |
|
|
|
with col2: |
|
fig, axs = plt.subplots(4, 1, figsize=(10, 10), sharex=True) |
|
draw_world( |
|
st.session_state.seq, |
|
axs, |
|
st.session_state.step, |
|
st.session_state.bist_counts, |
|
st.session_state.entropy, |
|
st.session_state.autocorr |
|
) |
|
st.pyplot(fig) |
|
|