From 8f85c0adbc1117ea7f02395538106104273a6a5d Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 17 May 2026 17:21:58 +0300 Subject: [PATCH] Fix port configuration and update Hamming network logic; enhance index view formulas and add deployment workflow --- .gitea/workflows/deploy.yml | 21 ++++++++++++++++++++ app.rb | 6 +++--- hamming.rb | 2 +- loader.rb | 2 ++ views/index.erb | 38 +++++++++++++++++++++---------------- 5 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 .gitea/workflows/deploy.yml diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..5256d23 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,21 @@ +name: Build and Push + +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Login to registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | \ + docker login git.ada-dev.ru -u ${{ secrets.REGISTRY_USER }} --password-stdin + + - name: Build and push + run: | + docker build -t git.ada-dev.ru/ada/${{ gitea.repository }}:latest . + docker push git.ada-dev.ru/ada/${{ gitea.repository }}:latest \ No newline at end of file diff --git a/app.rb b/app.rb index db494cd..107af7e 100644 --- a/app.rb +++ b/app.rb @@ -9,7 +9,7 @@ require_relative 'trace' EPS = 0.01 set :bind, '0.0.0.0' -set :port, 4568 +set :port, 4567 set :server, 'webrick' disable :protection set :host_authorization, { allow_if: ->(_env) { true } } @@ -51,7 +51,7 @@ post '/recall_steps' do MAX_MAXNET_ITER.times do nxt = maxnet_step(outputs, eps) hamming_steps << nxt.map { |v| v.round(2) } - break if nxt.count { |v| v > 0 } <= 1 + break if nxt.count { |v| v > 1e-9 } <= 1 outputs = nxt end @@ -88,7 +88,7 @@ post '/recall_trace' do MAX_MAXNET_ITER.times do nxt = maxnet_step(outputs, eps_val) hamming_steps << nxt.map { |v| v.round(2) } - break if nxt.count { |v| v > 0 } <= 1 + break if nxt.count { |v| v > 1e-9 } <= 1 outputs = nxt end winner_idx = outputs.each_with_index.max_by { |v, _| v }[1] diff --git a/hamming.rb b/hamming.rb index 12a6976..1545e3d 100644 --- a/hamming.rb +++ b/hamming.rb @@ -21,7 +21,7 @@ def recall_hamming(pattern_vectors, input_vec) outputs = hamming_layer(pattern_vectors, input_vec) MAX_MAXNET_ITER.times do next_out = maxnet_step(outputs, eps) - return next_out.each_with_index.max_by { |v, _| v }[1] if next_out.count { |v| v > 0 } <= 1 + return next_out.each_with_index.max_by { |v, _| v }[1] if next_out.count { |v| v > 1e-9 } <= 1 outputs = next_out end diff --git a/loader.rb b/loader.rb index 045e88e..da71b29 100644 --- a/loader.rb +++ b/loader.rb @@ -1,4 +1,6 @@ require 'roo' +require 'zip' +Zip.warn_invalid_date = false def load_patterns(file) xlsx = Roo::Spreadsheet.open(file) diff --git a/views/index.erb b/views/index.erb index 3fee0e1..f1e0311 100644 --- a/views/index.erb +++ b/views/index.erb @@ -401,20 +401,23 @@ const names = data.pattern_names; const t = data.hamming_trace; - hfFormula(String.raw`\operatorname{net}_i = \sum_{j} W_{ij} \cdot x_j \qquad x_i = \operatorname{sgn}(\operatorname{net}_i)`); + hfFormula(String.raw`s_j(p{+}1) = \sum_{i=0}^{n-1} w_{ij}\,y_i(p)`); + hfFormula(String.raw`y_j(p{+}1) = f\!\left[s_j(p{+}1)\right], \quad f(s)=\begin{cases}1&s\geq0\\-1&s<0\end{cases}`); data.hopfield_nets.forEach((nd, i) => { const mark = nd.changed === 0 ? ' ← сошлось' : ''; - hfLine(`шаг ${i + 1}: изменено ${nd.changed}/64${mark}`); + hfLine(`p=${i + 1}: изменено ${nd.changed}/64${mark}`); }); - hmFormula(String.raw`y_k = \frac{\mathbf{x} \cdot \mathbf{p}_k + n}{2}`); + hmFormula(String.raw`w_{ik} = \tfrac{x_i^k}{2}, \quad T_k = \tfrac{n}{2}`); + hmFormula(String.raw`y_j^{(1)} = \sum_{i=0}^{n-1} w_{ij}\,x_i + T_j`); const layer = names.map((n, i) => `${n}\\!=\\!${t.initial_outputs[i]}`).join(',\\;'); - hmFormula(String.raw`\text{слой: }\;` + layer); - hmFormula(String.raw`\varepsilon = \tfrac{0.9}{K} = \tfrac{0.9}{${t.k}} = ${t.eps}`); - hmFormula(String.raw`y_i(t{+}1) = \max\!\left(0,\; y_i(t) - \varepsilon\!\sum_{j \neq i} y_j(t)\right)`); + hmFormula(String.raw`y_j^{(2)}(0) = y_j^{(1)}:\;` + layer); + hmFormula(String.raw`0 < \varepsilon < \tfrac{1}{m},\quad \varepsilon = \tfrac{0.9}{${t.k}} = ${t.eps}`); + hmFormula(String.raw`s_j^{(2)}(p{+}1) = y_j^{(2)}(p) - \varepsilon\!\sum_{k \neq j} y_k^{(2)}(p)`); + hmFormula(String.raw`y_j^{(2)}(p{+}1) = f\!\left[s_j^{(2)}(p{+}1)\right]`); data.hamming_steps.slice(1).forEach((step, i) => { const vals = names.map((n, j) => `${n}\\!=\\!${step[j]}`).join(',\\;'); - hmFormula(`\\text{iter ${i + 1}: }\\;` + vals); + hmFormula(`p=${i + 1}:\\; y^{(2)} = [\\;` + vals + `\\;]`); }); hmFormula(String.raw`\Rightarrow \text{победитель: } \mathbf{` + data.hamming_winner + `}`); } @@ -496,7 +499,8 @@ if (showTrace) { clearTrace(); document.getElementById('trace-panels').style.display = 'flex'; - hfFormula(String.raw`\operatorname{net}_i = \sum_{j} W_{ij} \cdot x_j \qquad x_i = \operatorname{sgn}(\operatorname{net}_i)`); + hfFormula(String.raw`s_j(p{+}1) = \sum_{i=0}^{n-1} w_{ij}\,y_i(p)`); + hfFormula(String.raw`y_j(p{+}1) = f\!\left[s_j(p{+}1)\right], \quad f(s)=\begin{cases}1&s\geq0\\-1&s<0\end{cases}`); } renderBars(names, data.hamming_steps[0]); @@ -513,7 +517,7 @@ if (showTrace && i > 0 && data.hopfield_nets[i - 1]) { const nd = data.hopfield_nets[i - 1]; const mark = nd.changed === 0 ? ' ← сошлось' : ''; - hfLine(`шаг ${i}: изменено ${nd.changed}/64${mark}`); + hfLine(`p=${i}: изменено ${nd.changed}/64${mark}`); } } if (i < hmSteps.length) { @@ -523,14 +527,16 @@ if (showTrace) { const t = data.hamming_trace; if (i === 0) { - hmFormula(String.raw`y_k = \frac{\mathbf{x} \cdot \mathbf{p}_k + n}{2}`); + hmFormula(String.raw`w_{ik} = \tfrac{x_i^k}{2}, \quad T_k = \tfrac{n}{2}`); + hmFormula(String.raw`y_j^{(1)} = \sum_{i=0}^{n-1} w_{ij}\,x_i + T_j`); const layer = names.map((n, j) => `${n}\\!=\\!${t.initial_outputs[j]}`).join(',\\;'); - hmFormula(String.raw`\text{слой: }\;` + layer); - hmFormula(String.raw`\varepsilon = \tfrac{0.9}{${t.k}} = ${t.eps}`); - hmFormula(String.raw`y_i(t{+}1) = \max\!\left(0,\; y_i(t) - \varepsilon\!\sum_{j \neq i} y_j(t)\right)`); + hmFormula(String.raw`y_j^{(2)}(0) = y_j^{(1)}:\;` + layer); + hmFormula(String.raw`0 < \varepsilon < \tfrac{1}{m},\quad \varepsilon = \tfrac{0.9}{${t.k}} = ${t.eps}`); + hmFormula(String.raw`s_j^{(2)}(p{+}1) = y_j^{(2)}(p) - \varepsilon\!\sum_{k \neq j} y_k^{(2)}(p)`); + hmFormula(String.raw`y_j^{(2)}(p{+}1) = f\!\left[s_j^{(2)}(p{+}1)\right]`); } else { const vals = names.map((n, j) => `${n}\\!=\\!${hmSteps[i][j]}`).join(',\\;'); - hmFormula(`\\text{iter ${i}: }\\;` + vals); + hmFormula(`p=${i}:\\; y^{(2)} = [\\;` + vals + `\\;]`); } } } @@ -552,7 +558,7 @@ const hmLabel = document.getElementById('hamming-label'); hmLabel.textContent = `Ближайший эталон: ${data.hamming_winner}`; hmLabel.className = 'status-label yes'; - if (showTrace) hmFormula(String.raw`\Rightarrow \text{победитель: } \mathbf{` + data.hamming_winner + `}`); + if (showTrace) hmFormula(String.raw`\Rightarrow \text{победитель (}\,y_j^{(2)}\text{ max):}\;\mathbf{` + data.hamming_winner + `}`); } function showResult(data) { @@ -618,5 +624,5 @@