Dmtlant commited on
Commit
411f3df
·
verified ·
1 Parent(s): c00d034

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -101
app.py CHANGED
@@ -1,136 +1,127 @@
1
  import numpy as np
2
  import matplotlib.pyplot as plt
3
- import random
4
- from scipy.stats import entropy as scipy_entropy
5
  import streamlit as st
6
 
7
- # --- НАСТРОЙКИ ---
8
- seqlen = st.slider("Длина последовательности", 10, 100, 60)
9
- steps = st.slider("Количество шагов", 10, 200, 120)
10
- min_run, max_run = st.slider("Длина машин", 1, 10, 1), st.slider("Максимальная длина машин", 2, 10, 2)
11
- ANGLE_MAP = {'A': 60.0, 'C': 180.0, 'G': -60.0, 'T': -180.0, 'N': 0.0}
12
- bases = ['A', 'C', 'G', 'T']
13
-
14
- def find_local_min_runs(profile, min_run=1, max_run=2):
15
- result = []
16
- N = len(profile)
17
- i = 0
18
- while i < N:
19
- run_val = profile[i]
20
- run_length = 1
21
- while i + run_length < N and profile[i + run_length] == run_val:
22
- run_length += 1
23
- if min_run <= run_length <= max_run:
24
- result.append((i, i + run_length - 1, run_val))
25
- i += run_length
26
- return result
27
-
28
- # --- Более биологичные мутации ---
29
- def bio_mutate(seq):
30
- r = random.random()
31
- if r < 0.70:
32
- idx = random.randint(0, len(seq)-1)
33
- orig = seq[idx]
34
- prob = random.random()
35
- if orig in 'AG':
36
- newbase = 'C' if prob < 0.65 else random.choice(['T', 'C'])
37
- elif orig in 'CT':
38
- newbase = 'G' if prob < 0.65 else random.choice(['A', 'G'])
39
- else:
40
- newbase = random.choice([b for b in bases if b != orig])
41
- seq = seq[:idx] + newbase + seq[idx+1:]
42
- elif r < 0.80:
43
- idx = random.randint(0, len(seq)-1)
44
- ins = ''.join(random.choices(bases, k=random.randint(1, 3)))
45
- seq = seq[:idx] + ins + seq[idx:]
46
- if len(seq) > seqlen:
47
- seq = seq[:seqlen]
48
- elif r < 0.90:
49
- if len(seq) > 4:
50
- idx = random.randint(0, len(seq)-2)
51
- dell = random.randint(1, min(3, len(seq)-idx))
52
- seq = seq[:idx] + seq[idx+dell:]
53
- else:
54
- if len(seq) > 10:
55
- start = random.randint(0, len(seq)-6)
56
- end = start + random.randint(3,6)
57
- subseq = seq[start:end]
58
- subseq = subseq[::-1]
59
- seq = seq[:start] + subseq + seq[end:]
60
- while len(seq) < seqlen:
61
- seq += random.choice(bases)
62
- if len(seq) > seqlen:
63
- seq = seq[:seqlen]
64
- return seq
65
 
66
  def compute_autocorr(profile):
 
67
  profile = profile - np.mean(profile)
68
  result = np.correlate(profile, profile, mode='full')
69
- result = result[result.size // 2:]
70
- norm = np.max(result) if np.max(result)!=0 else 1
71
- return result[:10]/norm # только лаги 0..9
72
 
73
  def compute_entropy(profile):
74
- vals, counts = np.unique(profile, return_counts=True)
75
- p = counts / counts.sum()
76
- return scipy_entropy(p, base=2)
77
-
78
- # --- Начальная цепь ---
79
- seq = ''.join(random.choices(bases, k=seqlen))
80
- stat_bist_counts = []
81
- stat_entropy = []
82
- stat_autocorr = []
83
-
84
- fig, axs = plt.subplots(3, 1, figsize=(10, 8))
85
- plt.subplots_adjust(hspace=0.45)
86
- lags_shown = 6
87
 
 
88
  def draw_world(seq, axs, step, stat_bist_counts, stat_entropy, stat_autocorr):
89
  axs[0].cla()
90
  axs[1].cla()
91
  axs[2].cla()
92
  axs[3].cla()
93
 
94
- # Отображение торсионного профиля
95
- axs[0].plot(seq, label=f"Step {step}", color='skyblue')
96
  axs[0].set_title("Торсионный профиль (углы)")
97
  axs[0].set_ylim(-180, 180)
98
-
99
- # Выделение устойчивых машин
100
  stable_zones = find_local_min_runs(seq)
101
  for start, end in stable_zones:
102
  axs[0].axvspan(start, end, color='yellow', alpha=0.3)
103
- axs[0].text((start + end) // 2, 160, f'▲ {end - start}', ha='center', va='center', fontsize=8, color='darkgreen')
104
 
105
- # Количество "машин"
106
- axs[1].plot(stat_bist_counts, label='Machines', color='orchid')
107
  axs[1].set_title("Кол-во устойчивых машин (стромбистов)")
108
 
109
  # Энтропия
110
- axs[2].plot(stat_entropy, label='Entropy', color='crimson')
111
  axs[2].set_title("Энтропия торсионного поля")
112
 
113
  # Автокорреляция
114
- axs[3].plot(stat_autocorr, label='Autocorr', color='seagreen')
115
  axs[3].set_title("Автокорреляция (память)")
116
 
117
  for ax in axs:
118
  ax.legend()
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- # --- Запуск анимации в Streamlit ---
122
- if st.button("Начать анимацию"):
123
- chart_placeholder = st.empty() # создаем пустое место для графиков
124
- for step in range(steps):
125
- seq = bio_mutate(seq)
126
- torsion_profile = np.array([ANGLE_MAP.get(nt, 0.0) for nt in seq])
127
- runs = find_local_min_runs(torsion_profile, min_run, max_run)
128
- stat_bist_counts.append(len(runs))
129
- ent = compute_entropy(torsion_profile)
130
- stat_entropy.append(ent)
131
- acorr = compute_autocorr(torsion_profile)
132
- stat_autocorr.append(acorr)
133
- draw_world(seq, axs, step, stat_bist_counts, stat_entropy, stat_autocorr)
134
-
135
- chart_placeholder.pyplot(fig) # обновляем график
136
- # После каждого шага Streamlit перерисует график
 
1
  import numpy as np
2
  import matplotlib.pyplot as plt
 
 
3
  import streamlit as st
4
 
5
+ # === Параметры модели ===
6
+ SEQ_LEN = 100 # длина последовательности
7
+ HISTORY_LEN = 200 # сколько шагов хранить в статистике
8
+ JUMP = 10 # максимальный шаг изменения угла
9
+ ENTROPY_BINS = 36 # шаг 10 градусов
10
+
11
+ # === Инициализация состояния ===
12
+ if "seq" not in st.session_state:
13
+ st.session_state.seq = np.random.randint(-180, 180, size=SEQ_LEN)
14
+ st.session_state.history = []
15
+ st.session_state.bist_counts = []
16
+ st.session_state.entropy = []
17
+ st.session_state.autocorr = []
18
+ st.session_state.step = 0
19
+
20
+ # === Функции анализа ===
21
+ def find_local_min_runs(profile, threshold=10):
22
+ """Находит устойчивые участки ("машины"), где значения углов почти не меняются."""
23
+ runs = []
24
+ start = 0
25
+ for i in range(1, len(profile)):
26
+ if abs(profile[i] - profile[i - 1]) > threshold:
27
+ if i - start > 2:
28
+ runs.append((start, i - 1))
29
+ start = i
30
+ if len(profile) - start > 2:
31
+ runs.append((start, len(profile) - 1))
32
+ return runs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  def compute_autocorr(profile):
35
+ """Автокорреляция – структурность, насколько повторяется рисунок"""
36
  profile = profile - np.mean(profile)
37
  result = np.correlate(profile, profile, mode='full')
38
+ mid = len(result) // 2
39
+ return result[mid + 1] / result[mid]
 
40
 
41
  def compute_entropy(profile):
42
+ """Энтропия мера хаотичности, насколько случайна структура"""
43
+ hist, _ = np.histogram(profile, bins=ENTROPY_BINS, range=(-180, 180), density=True)
44
+ hist = hist[hist > 0]
45
+ return -np.sum(hist * np.log2(hist))
 
 
 
 
 
 
 
 
 
46
 
47
+ # === Функция отрисовки ===
48
  def draw_world(seq, axs, step, stat_bist_counts, stat_entropy, stat_autocorr):
49
  axs[0].cla()
50
  axs[1].cla()
51
  axs[2].cla()
52
  axs[3].cla()
53
 
54
+ # Отображение профиля
55
+ axs[0].plot(seq, label=f"Шаг {step}", color='skyblue')
56
  axs[0].set_title("Торсионный профиль (углы)")
57
  axs[0].set_ylim(-180, 180)
58
+
59
+ # Визуальное выделение устойчивых "машин"
60
  stable_zones = find_local_min_runs(seq)
61
  for start, end in stable_zones:
62
  axs[0].axvspan(start, end, color='yellow', alpha=0.3)
63
+ axs[0].text((start + end) // 2, 160, f'▲{end - start}', ha='center', va='center', fontsize=8, color='darkgreen')
64
 
65
+ # График количества "стромбистов"
66
+ axs[1].plot(stat_bist_counts, color='orchid')
67
  axs[1].set_title("Кол-во устойчивых машин (стромбистов)")
68
 
69
  # Энтропия
70
+ axs[2].plot(stat_entropy, color='crimson')
71
  axs[2].set_title("Энтропия торсионного поля")
72
 
73
  # Автокорреляция
74
+ axs[3].plot(stat_autocorr, color='seagreen')
75
  axs[3].set_title("Автокорреляция (память)")
76
 
77
  for ax in axs:
78
  ax.legend()
79
 
80
+ # === Функция обновления ===
81
+ def update_step():
82
+ seq = st.session_state.seq
83
+ history = st.session_state.history
84
+ stat_bist_counts = st.session_state.bist_counts
85
+ stat_entropy = st.session_state.entropy
86
+ stat_autocorr = st.session_state.autocorr
87
+ step = st.session_state.step
88
+
89
+ # Случайная мутация
90
+ i = np.random.randint(0, len(seq))
91
+ delta = np.random.randint(-JUMP, JUMP + 1)
92
+ seq[i] = (seq[i] + delta + 180) % 360 - 180
93
+
94
+ history.append(seq.copy())
95
+ if len(history) > HISTORY_LEN:
96
+ history.pop(0)
97
+
98
+ stable_regions = find_local_min_runs(seq)
99
+ stat_bist_counts.append(len(stable_regions))
100
+ stat_entropy.append(compute_entropy(seq))
101
+ stat_autocorr.append(compute_autocorr(seq))
102
+ st.session_state.step += 1
103
+
104
+ # === Интерфейс Streamlit ===
105
+ st.set_page_config(layout="wide")
106
+ st.title("🧬 Стромбистный анализ торсионного поля")
107
+ col1, col2 = st.columns([1, 2])
108
+
109
+ with col1:
110
+ if st.button("🔁 Следующий шаг"):
111
+ update_step()
112
+ st.markdown(f"**Текущий шаг**: {st.session_state.step}")
113
+ st.markdown("**Стромбисты** — устойчивые участки структуры, подобные памяти или машинам.")
114
+ st.markdown("**Автокорреляция** — отражает повторяемость паттерна.")
115
+ st.markdown("**Энтропия** — мера хаоса.")
116
 
117
+ with col2:
118
+ fig, axs = plt.subplots(4, 1, figsize=(10, 10), sharex=True)
119
+ draw_world(
120
+ st.session_state.seq,
121
+ axs,
122
+ st.session_state.step,
123
+ st.session_state.bist_counts,
124
+ st.session_state.entropy,
125
+ st.session_state.autocorr
126
+ )
127
+ st.pyplot(fig)