# Как работает приложение ## Запуск ```bash bundle install ruby app.rb # веб-интерфейс на http://localhost:4567 # или ruby main.rb # только CLI: загружает паттерны, обучает, выводит инфо ``` В Docker: собирается образ, `generate_excel.rb` генерирует `patterns.xlsx` при старте, Sinatra слушает на 4567. --- ## Данные Паттерны хранятся в `patterns.xlsx`. Каждый лист = один символ (T, H, E, X...). Ячейка `x` → `1`, остальное → `-1`. Размер: 8×8 = вектор из 64 значений. `loader.rb` читает Excel через гем `roo` и возвращает `{name => matrix_8x8}`. В вычислениях матрицы разворачиваются в векторы через `flatten`. Если хочешь добавить/изменить паттерны — правь `generate_excel.rb` и перезапусти. --- ## Веб-интерфейс Одна страница (`views/index.erb`), тёмная тема, 8×8 кликабельная сетка ввода. **Что можно сделать:** - Нарисовать паттерн кликами (или добавить шум кнопкой) - Нажать «Распознать» — сервер прогоняет через обе сети - Включить «Пошаговый режим» — видно, как Хопфилд сходится шаг за шагом - Включить «Показывать формулы» — рядом с анимацией появляются LaTeX-формулы вычислений --- ## Маршруты (`app.rb`) | Маршрут | Что делает | |---|---| | `GET /` | Загружает паттерны, отдаёт HTML | | `POST /recall` | Быстро: вектор → итоговый результат обеих сетей | | `POST /recall_steps` | То же + все промежуточные состояния для анимации | | `POST /recall_trace` | То же + net-значения, сколько нейронов изменилось на каждом шаге, трассировка MAXNET | Все POST принимают JSON `{vector: [...64 числа...]}`, возвращают JSON. --- ## Алгоритмы ### Хопфилд (`hopfield.rb`) **Обучение** — один раз при запуске: ``` W[i][j] += v[i] * v[j] для каждого паттерна v, i ≠ j ``` Матрица весов 64×64, кэшируется в `weights.cache`. **Recall** — итерации до сходимости: ``` new[i] = sign( Σ_j W[i][j] * x[j] ) # sign: ≥0 → 1, <0 → -1 ``` Все нейроны обновляются синхронно. Стоп: состояние не изменилось (EPS=0.01) или 200 итераций. ### Хэмминг (`hamming.rb`) **Шаг 1 — слой Хэмминга** (один раз): ``` output[k] = (dot(pattern_k, input) + 64) / 2 ``` Результат: число от 0 до 64 — сколько бит совпало с k-м эталоном. **Шаг 2 — MAXNET** (итерации до одного победителя): ``` new[i] = max(output[i] - eps * Σ_{j≠i} output[j], 0) # eps = 0.9 / кол-во паттернов ``` Нейроны конкурируют: слабые гаснут, остаётся один. Его индекс = ближайший паттерн.