WIP: Implement trace functionality for Hopfield and Hamming networks; update Gemfile.lock and app.rb for new dependencies and features #1
@@ -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
|
||||
@@ -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]
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
require 'roo'
|
||||
require 'zip'
|
||||
Zip.warn_invalid_date = false
|
||||
|
||||
def load_patterns(file)
|
||||
xlsx = Roo::Spreadsheet.open(file)
|
||||
|
||||
+22
-16
@@ -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 @@
|
||||
|
||||
</body>
|
||||
<footer style="margin-top:3rem; font-size:0.75rem; color:#666; text-align:center;">
|
||||
© Develop by Antipenko D.A. for MIAD - 2026
|
||||
© Created by Antipenko D.A. for MIAD - 2026
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user