From 01828000438f5f2ac2520eca6b9f581f6b4bcad8 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 17 May 2026 16:24:34 +0300 Subject: [PATCH 1/2] Implement trace functionality for Hopfield and Hamming networks; update Gemfile.lock and app.rb for new dependencies and features --- Gemfile.lock | 6 +- app.rb | 41 +++++++++- hamming.rb | 2 +- trace.rb | 18 +++++ views/index.erb | 202 +++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 242 insertions(+), 27 deletions(-) create mode 100644 trace.rb diff --git a/Gemfile.lock b/Gemfile.lock index 07c22c4..acc9dd9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,6 @@ GEM logger (1.7.0) multi_json (1.21.1) mustermann (3.1.1) - nio4r (2.7.5) nokogiri (1.19.3-aarch64-linux-gnu) racc (~> 1.4) nokogiri (1.19.3-aarch64-linux-musl) @@ -23,8 +22,6 @@ GEM racc (~> 1.4) nokogiri (1.19.3-x86_64-linux-musl) racc (~> 1.4) - puma (8.0.1) - nio4r (~> 2.0) racc (1.8.1) rack (3.2.6) rack-protection (4.2.1) @@ -60,6 +57,7 @@ GEM sinatra (= 4.2.1) tilt (~> 2.0) tilt (2.7.0) + webrick (1.9.2) PLATFORMS aarch64-linux-gnu @@ -72,12 +70,12 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - puma rackup roo rubyXL sinatra sinatra-contrib + webrick BUNDLED WITH 2.5.3 diff --git a/app.rb b/app.rb index c7bb231..db494cd 100644 --- a/app.rb +++ b/app.rb @@ -4,11 +4,12 @@ require_relative 'loader' require_relative 'functions' require_relative 'hopfield' require_relative 'hamming' +require_relative 'trace' EPS = 0.01 set :bind, '0.0.0.0' -set :port, 4567 +set :port, 4568 set :server, 'webrick' disable :protection set :host_authorization, { allow_if: ->(_env) { true } } @@ -64,6 +65,44 @@ post '/recall_steps' do }.to_json end +post '/recall_trace' do + content_type :json + noisy = JSON.parse(request.body.read)['vector'].map(&:to_f) + + hopfield_steps = [noisy.map(&:to_i)] + hopfield_nets = [] + current = noisy.dup + MAX_HOPFIELD_ITER.times do + net = trace_hopfield_step(WEIGHTS, current) + nxt = net.map { |v| v >= 0 ? 1 : -1 } + changed = current.each_with_index.count { |v, i| v.to_i != nxt[i] } + hopfield_nets << { net: net.map { |v| v.round(3) }, changed: changed } + hopfield_steps << nxt + break if vectors_equal?(current, nxt) + current = nxt + end + + eps_val = 0.9 / PATTERN_VECTORS.length + outputs = hamming_layer(PATTERN_VECTORS, noisy) + hamming_steps = [outputs.map { |v| v.round(2) }] + 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 + outputs = nxt + end + winner_idx = outputs.each_with_index.max_by { |v, _| v }[1] + + { + hopfield_steps: hopfield_steps, + hopfield_nets: hopfield_nets, + hamming_steps: hamming_steps, + pattern_names: PATTERN_NAMES, + hamming_winner: PATTERN_NAMES[winner_idx], + hamming_trace: hamming_trace(PATTERN_VECTORS, noisy) + }.to_json +end + post '/recall' do content_type :json noisy = JSON.parse(request.body.read)['vector'].map(&:to_f) diff --git a/hamming.rb b/hamming.rb index 18544ff..12a6976 100644 --- a/hamming.rb +++ b/hamming.rb @@ -13,7 +13,7 @@ def maxnet_step(outputs, eps) end end -MAX_MAXNET_ITER = 500 +MAX_MAXNET_ITER = 100 def recall_hamming(pattern_vectors, input_vec) eps = 0.9 / pattern_vectors.length diff --git a/trace.rb b/trace.rb new file mode 100644 index 0000000..43e356f --- /dev/null +++ b/trace.rb @@ -0,0 +1,18 @@ +def trace_hopfield_step(weights, vector) + n = vector.length + Array.new(n) { |i| n.times.sum { |j| weights[i][j] * vector[j] } } +end + +def hamming_trace(pattern_vectors, input_vec) + n = input_vec.length + k = pattern_vectors.length + dots = pattern_vectors.map { |pv| pv.zip(input_vec).sum { |a, b| a * b } } + initial = dots.map { |dot| (dot.to_f + n) / 2.0 } + { + eps: (0.9 / k).round(6), + k: k, + n: n, + dot_products: dots, + initial_outputs: initial.map { |v| v.round(2) } + } +end diff --git a/views/index.erb b/views/index.erb index 238a580..3fee0e1 100644 --- a/views/index.erb +++ b/views/index.erb @@ -3,6 +3,8 @@ Сети Хопфилда и Хэмминга + +